diff --git a/api-playground/json/data/maadhaar/GenerateMaadhaarIntentPayload.json b/api-playground/json/data/maadhaar/GenerateMaadhaarIntentPayload.json new file mode 100644 index 00000000..f3f62daf --- /dev/null +++ b/api-playground/json/data/maadhaar/GenerateMaadhaarIntentPayload.json @@ -0,0 +1,25 @@ +{ + "parameters": { + "header": [ + { + "x-client-id": "{{client_id}}" + }, + { + "x-client-secret": "{{client_secret}}" + }, + { + "x-product-instance-id": "{{product_instance_id}}" + } + ] + }, + "body": { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "desired_fields": [ + "residentName", + "dob", + "gender", + "pincode", + "address" + ] + } +} diff --git a/api-playground/json/data/maadhaar/GenerateMaadhaarQR.json b/api-playground/json/data/maadhaar/GenerateMaadhaarQR.json new file mode 100644 index 00000000..f3f62daf --- /dev/null +++ b/api-playground/json/data/maadhaar/GenerateMaadhaarQR.json @@ -0,0 +1,25 @@ +{ + "parameters": { + "header": [ + { + "x-client-id": "{{client_id}}" + }, + { + "x-client-secret": "{{client_secret}}" + }, + { + "x-product-instance-id": "{{product_instance_id}}" + } + ] + }, + "body": { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "desired_fields": [ + "residentName", + "dob", + "gender", + "pincode", + "address" + ] + } +} diff --git a/api-playground/json/data/maadhaar/GetMaadhaarWorkflowStatus.json b/api-playground/json/data/maadhaar/GetMaadhaarWorkflowStatus.json new file mode 100644 index 00000000..42b635e0 --- /dev/null +++ b/api-playground/json/data/maadhaar/GetMaadhaarWorkflowStatus.json @@ -0,0 +1,20 @@ +{ + "parameters": { + "query": [ + { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + ], + "header": [ + { + "x-client-id": "{{client_id}}" + }, + { + "x-client-secret": "{{client_secret}}" + }, + { + "x-product-instance-id": "{{product_instance_id}}" + } + ] + } +} diff --git a/api-playground/json/data/maadhaar/ProcessMaadhaarSDJWT.json b/api-playground/json/data/maadhaar/ProcessMaadhaarSDJWT.json new file mode 100644 index 00000000..db50f457 --- /dev/null +++ b/api-playground/json/data/maadhaar/ProcessMaadhaarSDJWT.json @@ -0,0 +1,19 @@ +{ + "parameters": { + "header": [ + { + "x-client-id": "{{client_id}}" + }, + { + "x-client-secret": "{{client_secret}}" + }, + { + "x-product-instance-id": "{{product_instance_id}}" + } + ] + }, + "body": { + "txn_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "sd_jwt": "eyJhbGciOiJSUzI1NiJ9..." + } +} diff --git a/api-playground/products.json b/api-playground/products.json index 2e5e5186..d85c78e5 100644 --- a/api-playground/products.json +++ b/api-playground/products.json @@ -63,6 +63,10 @@ { "name": "Aadhaar Lite", "path": "data/aadhaar-lite" + }, + { + "name": "mAadhaar verification", + "path": "data/maadhaar" } ] } diff --git a/api-references/data/maadhaar.json b/api-references/data/maadhaar.json new file mode 100644 index 00000000..42ea3e4a --- /dev/null +++ b/api-references/data/maadhaar.json @@ -0,0 +1,736 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Data Gateway - mAadhaar verification", + "description": "Initiate an mAadhaar QR or intent flow and retrieve the Aadhaar details shared by the user.\n\n[Read the integration guide](https://docs.setu.co/data/maadhaar/quickstart)", + "version": "1.0" + }, + "servers": [ + { + "url": "https://dg-sandbox.setu.co", + "description": "Sandbox" + }, + { + "url": "https://dg.setu.co", + "description": "Production" + } + ], + "paths": { + "/api/maadhaar/qr/generate": { + "post": { + "tags": ["mAadhaar verification"], + "summary": "Generate QR", + "description": "Generates a QR image that the user can scan with the mAadhaar app.", + "operationId": "GenerateMaadhaarQR", + "parameters": [ + { + "$ref": "#/components/parameters/ClientId" + }, + { + "$ref": "#/components/parameters/ClientSecret" + }, + { + "$ref": "#/components/parameters/ProductInstanceId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateRequest" + }, + "example": { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "desired_fields": [ + "residentName", + "dob", + "gender", + "pincode", + "address" + ] + } + } + } + }, + "responses": { + "200": { + "description": "QR generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QRGenerateResponse" + }, + "example": { + "qr_url": "https://example.com/maadhaar/qr_codes/maadhaar_qr_ca44473f-00ad-4744-a430-39b83c01cfb6.png", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "traceId": "1-6a672a69-39f7c6307129996459acb52b" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/api/maadhaar/signed-jwt/generate": { + "post": { + "tags": ["mAadhaar verification"], + "summary": "Generate intent payload", + "description": "Generates a signed JWT to pass to a platform-specific mAadhaar intent.", + "operationId": "GenerateMaadhaarIntentPayload", + "parameters": [ + { + "$ref": "#/components/parameters/ClientId" + }, + { + "$ref": "#/components/parameters/ClientSecret" + }, + { + "$ref": "#/components/parameters/ProductInstanceId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateRequest" + }, + "example": { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "desired_fields": [ + "residentName", + "dob", + "gender", + "pincode", + "address" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Intent payload generated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntentPayloadResponse" + }, + "example": { + "deeplink_signed_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "traceId": "1-6a672a69-39f7c6307129996459acb52b" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/api/maadhaar/process-sd-jwt": { + "post": { + "tags": ["mAadhaar verification"], + "summary": "Process SD-JWT", + "description": "Processes the SD-JWT returned by the mAadhaar app in an app-to-app intent flow.", + "operationId": "ProcessMaadhaarSDJWT", + "parameters": [ + { + "$ref": "#/components/parameters/ClientId" + }, + { + "$ref": "#/components/parameters/ClientSecret" + }, + { + "$ref": "#/components/parameters/ProductInstanceId" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProcessSDJWTRequest" + }, + "example": { + "txn_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "sd_jwt": "eyJhbGciOiJSUzI1NiJ9..." + } + } + } + }, + "responses": { + "200": { + "description": "SD-JWT processed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusResponse" + }, + "example": { + "aadhaar_output": { + "address": "JP Nagar, Bengaluru, Karnataka 560078", + "dob": "1995-10-18", + "gender": "MALE", + "pincode": "560078", + "residentName": "Sample User" + }, + "error": { + "code": "NO_ERROR", + "detail": "No error", + "traceId": "1-68d122f6-3732177863083023409ea933" + }, + "status": "success", + "traceId": "1-68d122f6-3732177863083023409ea933", + "txn": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + }, + "/api/maadhaar/workflow/status": { + "get": { + "tags": ["mAadhaar verification"], + "summary": "Get workflow status", + "description": "Returns the current status and Aadhaar details, when available, for an mAadhaar workflow.", + "operationId": "GetMaadhaarWorkflowStatus", + "parameters": [ + { + "$ref": "#/components/parameters/ClientId" + }, + { + "$ref": "#/components/parameters/ClientSecret" + }, + { + "$ref": "#/components/parameters/ProductInstanceId" + }, + { + "name": "workflow_id", + "in": "query", + "description": "The workflow UUID supplied when verification was initiated.", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "example": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + } + ], + "responses": { + "200": { + "description": "Workflow status retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatusResponse" + }, + "examples": { + "pending": { + "summary": "Authentication pending", + "value": { + "aadhaar_output": null, + "error": { + "code": "NO_ERROR", + "detail": "No error", + "traceId": "1-68f75962-033693ff7d131e1339f23c90" + }, + "status": "pending", + "traceId": "1-68f75962-033693ff7d131e1339f23c90", + "txn": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + }, + "success": { + "summary": "Authentication complete", + "value": { + "aadhaar_output": { + "address": "JP Nagar, Bengaluru, Karnataka 560078", + "dob": "1995-10-18", + "gender": "MALE", + "pincode": "560078", + "residentName": "Sample User" + }, + "error": { + "code": "NO_ERROR", + "detail": "No error", + "traceId": "1-68d122f6-3732177863083023409ea933" + }, + "status": "success", + "traceId": "1-68d122f6-3732177863083023409ea933", + "txn": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "404": { + "$ref": "#/components/responses/RequestNotFound" + }, + "500": { + "$ref": "#/components/responses/InternalError" + } + } + } + } + }, + "components": { + "parameters": { + "ClientId": { + "name": "x-client-id", + "in": "header", + "description": "Client ID provided by Setu.", + "required": true, + "schema": { + "type": "string", + "example": "{{client_id}}" + } + }, + "ClientSecret": { + "name": "x-client-secret", + "in": "header", + "description": "Client secret provided by Setu.", + "required": true, + "schema": { + "type": "string", + "example": "{{client_secret}}" + } + }, + "ProductInstanceId": { + "name": "x-product-instance-id", + "in": "header", + "description": "mAadhaar product instance ID provided by Setu.", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "example": "{{product_instance_id}}" + } + } + }, + "schemas": { + "GenerateRequest": { + "type": "object", + "required": ["workflow_id", "desired_fields"], + "properties": { + "workflow_id": { + "type": "string", + "format": "uuid", + "description": "A new UUID generated by you for this verification." + }, + "desired_fields": { + "type": "array", + "description": "Aadhaar claims that the user is asked to share.", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "residentName", + "dob", + "gender", + "address", + "pincode", + "residentImage", + "maskedMobile", + "maskedEmail", + "ageAbove18", + "ageAbove50", + "ageAbove60", + "ageAbove75" + ] + } + } + } + }, + "QRGenerateResponse": { + "type": "object", + "required": ["workflow_id", "qr_url", "traceId"], + "properties": { + "workflow_id": { + "type": "string", + "format": "uuid" + }, + "qr_url": { + "type": "string", + "format": "uri", + "description": "URL of the generated QR image." + }, + "traceId": { + "type": "string", + "description": "Root-level trace ID for the QR generation response. This response uses the camelCase field name traceId." + } + } + }, + "IntentPayloadResponse": { + "type": "object", + "required": ["workflow_id", "deeplink_signed_jwt", "traceId"], + "properties": { + "workflow_id": { + "type": "string", + "format": "uuid" + }, + "deeplink_signed_jwt": { + "type": "string", + "description": "Signed request to pass to the mAadhaar intent." + }, + "traceId": { + "type": "string", + "description": "Root-level trace ID for the intent payload response. This response uses the camelCase field name traceId." + } + } + }, + "ProcessSDJWTRequest": { + "type": "object", + "required": ["txn_id", "sd_jwt"], + "properties": { + "txn_id": { + "type": "string", + "format": "uuid", + "description": "The workflow ID used to generate the intent payload." + }, + "sd_jwt": { + "type": "string", + "description": "The SD-JWT returned by the mAadhaar app." + } + } + }, + "StatusResponse": { + "type": "object", + "required": [ + "status", + "workflow_id", + "txn", + "traceId", + "error" + ], + "properties": { + "status": { + "type": "string", + "enum": ["pending", "success", "error"] + }, + "workflow_id": { + "type": "string", + "format": "uuid" + }, + "txn": { + "type": "string", + "description": "UIDAI transaction identifier." + }, + "traceId": { + "type": "string", + "description": "Root-level trace ID for workflow status responses. Both the root response and nested error object use the camelCase field name traceId." + }, + "error": { + "$ref": "#/components/schemas/ErrorDetail" + }, + "aadhaar_output": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/AadhaarOutput" + } + ], + "description": "Claims shared by the user. This is null while authentication is pending." + } + } + }, + "AadhaarOutput": { + "type": "object", + "additionalProperties": true, + "description": "The Aadhaar claims selected in desired_fields and shared by the user.", + "properties": { + "residentName": { + "type": "string" + }, + "dob": { + "type": "string", + "format": "date" + }, + "gender": { + "type": "string" + }, + "address": { + "type": "string" + }, + "pincode": { + "type": "string" + }, + "residentImage": { + "type": "string", + "description": "Encoded resident image returned by UIDAI." + }, + "maskedMobile": { + "type": "string", + "description": "Masked mobile number returned by UIDAI." + }, + "maskedEmail": { + "type": "string", + "description": "Masked email address returned by UIDAI." + }, + "ageAbove18": { + "type": "boolean" + }, + "ageAbove50": { + "type": "boolean" + }, + "ageAbove60": { + "type": "boolean" + }, + "ageAbove75": { + "type": "boolean" + } + } + }, + "ErrorDetail": { + "type": "object", + "required": ["code", "detail", "traceId"], + "properties": { + "code": { + "type": "string", + "description": "Setu API error code, such as invalid_payload or NO_ERROR." + }, + "detail": { + "type": "string" + }, + "traceId": { + "type": "string", + "description": "Nested error trace ID. Error objects use the camelCase field name traceId across all mAadhaar responses." + } + } + }, + "ErrorResponse": { + "type": "object", + "required": ["workflow_id", "traceId", "error"], + "properties": { + "status": { + "type": "string", + "nullable": true + }, + "txn": { + "type": "string", + "nullable": true + }, + "workflow_id": { + "type": "string" + }, + "traceId": { + "type": "string", + "description": "Root-level trace ID for API error responses. These responses use the camelCase field name traceId." + }, + "error": { + "$ref": "#/components/schemas/ErrorDetail" + }, + "aadhaar_output": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/AadhaarOutput" + } + ] + } + } + }, + "WebhookResponse": { + "type": "object", + "required": [ + "status", + "workflow_id", + "txn", + "traceId", + "error", + "aadhaar_output" + ], + "properties": { + "status": { + "type": "string", + "enum": ["success", "pending", "error"] + }, + "workflow_id": { + "type": "string", + "format": "uuid" + }, + "txn": { + "type": "string" + }, + "traceId": { + "type": "string", + "description": "Root-level trace ID for webhook responses. Both the root response and nested error object use the camelCase field name traceId." + }, + "error": { + "$ref": "#/components/schemas/WebhookErrorDetail" + }, + "aadhaar_output": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/AadhaarOutput" + } + ] + } + }, + "example": { + "status": "success", + "workflow_id": "9f2d1b7a-4f5c-4a6d-8d8e-1a2b3c4d5e6f", + "txn": "9f2d1b7a-4f5c-4a6d-8d8e-1a2b3c4d5e6f", + "traceId": "7e3a9c2d-8b4f-4d6c-a123-4f56789abcde", + "error": { + "code": "0", + "detail": "" + }, + "aadhaar_output": { + "residentName": "John Doe", + "dob": "1990-01-01", + "gender": "MALE", + "pincode": "123456", + "address": "123 Main Street, Springfield, Example State 123456" + } + }, + "examples": { + "success": { + "$ref": "#/components/schemas/WebhookResponse/example" + }, + "userAborted": { + "summary": "User aborted authentication", + "value": { + "status": "error", + "workflow_id": "bc2bb5ac-4e26-4b89-9c80-0d7a95c2ee27", + "txn": "bc2bb5ac-4e26-4b89-9c80-0d7a95c2ee27", + "traceId": "c926a621-97a3-4e1b-a438-81bc3b61614d", + "error": { + "code": "303", + "detail": "Authentication process aborted by user" + }, + "aadhaar_output": null + } + }, + "authenticationFailed": { + "summary": "Authentication failed due to a network or server error", + "value": { + "status": "error", + "workflow_id": "08d96879-0626-4960-8378-97fb9042f51a", + "txn": "08d96879-0626-4960-8378-97fb9042f51a", + "traceId": "1-6a6882b8-3fc3c3ec7c9eaf1a693a4772", + "error": { + "code": "307", + "detail": "Failed to complete authentication due to network or server error" + }, + "aadhaar_output": null + } + } + } + }, + "WebhookErrorDetail": { + "type": "object", + "required": ["code", "detail"], + "properties": { + "code": { + "type": "string", + "description": "UIDAI result code represented as a string, such as 0 for success or 303 and 307 for authentication failures." + }, + "detail": { + "type": "string" + } + } + } + }, + "responses": { + "BadRequest": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "aadhaar_output": null, + "error": { + "code": "INVALID_REQUEST", + "detail": "Unique workflow identifier is required", + "traceId": "1-68f75962-033693ff7d131e1339f23c90" + }, + "status": null, + "traceId": "1-68f75962-033693ff7d131e1339f23c90", + "txn": null, + "workflow_id": "" + } + } + } + }, + "RequestNotFound": { + "description": "Workflow not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "aadhaar_output": null, + "error": { + "code": "REQUEST_NOT_FOUND", + "detail": "The requested workflow_id was not found.", + "traceId": "1-68f75962-033693ff7d131e1339f23c90" + }, + "status": null, + "traceId": "1-68f75962-033693ff7d131e1339f23c90", + "txn": null, + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + } + } + }, + "InternalError": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "aadhaar_output": null, + "error": { + "code": "INTERNAL_ERROR", + "detail": "Request processing failed", + "traceId": "1-68f75962-033693ff7d131e1339f23c90" + }, + "status": null, + "traceId": "1-68f75962-033693ff7d131e1339f23c90", + "txn": null, + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + } + } + } + } + } + }, + "tags": [ + { + "name": "mAadhaar verification" + } + ] +} diff --git a/content/data/maadhaar/api-reference.mdx b/content/data/maadhaar/api-reference.mdx new file mode 100644 index 00000000..97f1f113 --- /dev/null +++ b/content/data/maadhaar/api-reference.mdx @@ -0,0 +1,6 @@ +--- +sidebar_title: API reference +page_title: mAadhaar verification API reference +order: 2 +visible_in_sidebar: true +--- diff --git a/content/data/maadhaar/overview.mdx b/content/data/maadhaar/overview.mdx new file mode 100644 index 00000000..806d4b6c --- /dev/null +++ b/content/data/maadhaar/overview.mdx @@ -0,0 +1,67 @@ +--- +sidebar_title: Overview +page_title: mAadhaar verification overview +order: 0 +visible_in_sidebar: true +--- + +## mAadhaar verification + +mAadhaar verification lets a user share selected Aadhaar details with your +organisation through the UIDAI mAadhaar app. The user reviews the requested +details and completes authentication in the app before the data is shared. + +The flow does not require the user to type their Aadhaar number into your app +or website. + +### Integration modes + +You can initiate verification in either of the following ways: + +- **QR flow (cross-device):** Display a QR code on your website or application. + The user scans it with the mAadhaar app on another device. +- **Intent flow (same-device):** Open the mAadhaar app from your mobile app or + mobile website using a platform-specific intent. + +Both modes use a unique `workflow_id` generated by you. Use this value to +correlate the verification request, webhook notification, and status response. + +### Data sharing + +Specify the Aadhaar claims required for your use case in `desired_fields`. The +user can review the requested information before approving it in the mAadhaar +app. + +Supported requested fields include: + +- `residentName` +- `dob` +- `gender` +- `address` +- `pincode` +- `residentImage` +- `maskedMobile` +- `maskedEmail` +- `ageAbove18` +- `ageAbove50` +- `ageAbove60` +- `ageAbove75` + +Request only the fields required for your use case. + + + Configure a webhook endpoint during onboarding. Setu notifies this endpoint + when Aadhaar data is available. You can also poll the workflow status API. + + +
+ + + + diff --git a/content/data/maadhaar/quickstart.mdx b/content/data/maadhaar/quickstart.mdx new file mode 100644 index 00000000..399dfef1 --- /dev/null +++ b/content/data/maadhaar/quickstart.mdx @@ -0,0 +1,390 @@ +--- +sidebar_title: Quickstart +page_title: mAadhaar verification quickstart +order: 1 +visible_in_sidebar: true +--- + +## mAadhaar verification quickstart + +This guide describes how to initiate mAadhaar verification and retrieve the +details shared by the user. + +### Before you begin + +Contact Setu to configure the mAadhaar product and receive the following +credentials: + +- `x-client-id` +- `x-client-secret` +- `x-product-instance-id` + +Use these base URLs: + +- Sandbox — `https://dg-sandbox.setu.co` +- Production — `https://dg.setu.co` + +Send the three credentials as headers with every mAadhaar API request. + + + Generate a new UUID for workflow_id every time you start a + verification. Do not reuse a workflow ID. + + +
+ +## Choose an integration flow + +### QR flow + +Use the QR flow when the user views your experience on one device and has the +mAadhaar app on another device. + +1. Generate a UUID for `workflow_id`. +2. Call the generate QR API with the workflow ID and required Aadhaar fields. +3. Display the image returned in `qr_url`. +4. Start polling the workflow status API. +5. Ask the user to open the mAadhaar app, authenticate, and scan the QR code. +6. The user selects a profile, reviews the requested fields, approves sharing, + and completes biometric authentication. +7. After the user completes biometric authentication and approves Aadhaar + sharing, receive the webhook at your configured endpoint. You can also read + the Aadhaar details from the successful workflow status response. + +### Intent flow + +Use the intent flow when the user starts verification on the same mobile device +that has the mAadhaar app installed. + +1. Generate a UUID for `workflow_id`. +2. Call the generate intent payload API. +3. Pass `deeplink_signed_jwt` to the platform-specific mAadhaar intent. +4. The user reviews the requested fields, approves sharing, and completes + biometric authentication in the mAadhaar app. +5. For an app-to-app flow, receive the SD-JWT returned by the mAadhaar app and + send it to the process SD-JWT API. +6. For a web-to-app flow, wait for the Setu webhook or poll the workflow status + API. + + + On iOS, the mAadhaar app may not automatically return the user to your app. + Design your user experience so the user can return manually. + + +
+ +## Generate a QR code + +Send a `POST` request to `/api/maadhaar/qr/generate`. + + + {`POST /api/maadhaar/qr/generate + { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "desired_fields": [ + "residentName", + "dob", + "gender", + "pincode", + "address" + ] + }`} + + +A successful response contains the URL of the QR image: + + + {`{ + "qr_url": "https://example.com/maadhaar/qr_codes/maadhaar_qr_ca44473f-00ad-4744-a430-39b83c01cfb6.png", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "traceId": "1-6a672a69-39f7c6307129996459acb52b" + }`} + + +For an invalid payload, the API returns the standard error envelope: + + + {`{ + "aadhaar_output": null, + "error": { + "code": "INVALID_REQUEST", + "detail": "Unique workflow identifier is required", + "traceId": "2feb81d0-a84f-4885-9e3e-ba6f2946b288" + }, + "status": null, + "traceId": "2feb81d0-a84f-4885-9e3e-ba6f2946b288", + "txn": null, + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + }`} + + +Display this image without altering its contents. Begin polling the status API +while the QR code is visible. + +
+ +## Generate an intent payload + +Send a `POST` request to `/api/maadhaar/signed-jwt/generate`. + + + {`POST /api/maadhaar/signed-jwt/generate + { + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "desired_fields": [ + "residentName", + "dob", + "gender", + "pincode", + "address" + ] + }`} + + +The response contains a signed request to pass to the mAadhaar app: + + + {`{ + "deeplink_signed_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "traceId": "1-6a672a69-39f7c6307129996459acb52b" + }`} + + +For an invalid payload, the API returns the standard error envelope: + + + {`{ + "aadhaar_output": null, + "error": { + "code": "INVALID_REQUEST", + "detail": "Unique workflow identifier is required", + "traceId": "614b936c-342a-4d22-9009-7328d8859360" + }, + "status": null, + "traceId": "614b936c-342a-4d22-9009-7328d8859360", + "txn": null, + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + }`} + + +### Android app-to-app intent + +Use the UIDAI intent action and add the signed JWT as the `request` extra: + + + {`val intent = Intent("in.gov.uidai.pehchaan.INTENT_REQUEST").apply { + putExtra("request", deeplinkSignedJwt) + } + startActivityForResult(intent, MAADHAAR_REQUEST_CODE)`} + + +### iOS app-to-app intent + +Pass the signed JWT in the `request` query parameter and include your callback +scheme: + + + {`var components = URLComponents() + components.scheme = "pehchaan" + components.host = "in.gov.uidai.pehchan" + components.queryItems = [ + URLQueryItem(name: "request", value: deeplinkSignedJwt), + URLQueryItem(name: "callback", value: "yourAppCallback") + ] + if let url = components.url, UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + }`} + + +### Web-to-app intent + +For a mobile web flow, use the signed JWT as the `request` value. Detect the +user's platform before opening the URL: + + + {`const request = encodeURIComponent(deeplinkSignedJwt); + if (isIOS) { + window.location.href = + "pehchaan://in.gov.uidai.pehchan?request=" + request + "&source=web"; + } else if (isAndroid) { + window.location.href = + "intent:#Intent;action=in.gov.uidai.pehchaan.WEB_INTENT_REQUEST;S.request=" + + request + ";end"; + }`} + + +
+ +## Process an SD-JWT + +In the app-to-app intent flow, send the SD-JWT returned by mAadhaar to +`/api/maadhaar/process-sd-jwt`. + + + {`POST /api/maadhaar/process-sd-jwt + { + "txn_id": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "sd_jwt": "eyJhbGciOiJSUzI1NiJ9..." + }`} + + +Use the original `workflow_id` as `txn_id`. A successful response contains the +claims shared by the user: + + + {`{ + "aadhaar_output": { + "address": "JP Nagar, Bengaluru, Karnataka 560078", + "dob": "1995-10-18", + "gender": "MALE", + "pincode": "560078", + "residentName": "Sample User" + }, + "error": { + "code": "NO_ERROR", + "detail": "No error", + "traceId": "1-68d122f6-3732177863083023409ea933" + }, + "status": "success", + "traceId": "1-68d122f6-3732177863083023409ea933", + "txn": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + }`} + + +For an invalid payload or an SD-JWT processing failure, the API returns the +same error envelope: + + + {`{ + "aadhaar_output": null, + "error": { + "code": "INVALID_REQUEST", + "detail": "The SD-JWT string to process", + "traceId": "c926a621-97a3-4e1b-a438-81bc3b61614d" + }, + "status": null, + "traceId": "c926a621-97a3-4e1b-a438-81bc3b61614d", + "txn": null, + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + }`} + + +
+ +## Poll workflow status + +Send a `GET` request to `/api/maadhaar/workflow/status` with the workflow ID: + + + GET /api/maadhaar/workflow/status?workflow_id=ca44473f-00ad-4744-a430-39b83c01cfb6 + + +While the user has not completed authentication, the API returns `pending`: + + + {`{ + "aadhaar_output": null, + "error": { + "code": "NO_ERROR", + "detail": "No error", + "traceId": "1-68f75962-033693ff7d131e1339f23c90" + }, + "status": "pending", + "traceId": "1-68f75962-033693ff7d131e1339f23c90", + "txn": "ca44473f-00ad-4744-a430-39b83c01cfb6", + "workflow_id": "ca44473f-00ad-4744-a430-39b83c01cfb6" + }`} + + +Stop polling when `status` becomes `success` or `error`. Use exponential +backoff rather than sending continuous requests. + +If the `workflow_id` is unknown for the product instance, the status endpoint +returns `404` with `error.code` set to `REQUEST_NOT_FOUND`. All handled `400`, +`404`, and `500` errors from the mAadhaar APIs use this same envelope; only the +HTTP status, error code, and error detail change. + +### Webhook notification + +If a webhook URL is configured for your product instance, Setu sends the same +status object to that URL after processing the Aadhaar response. Return an HTTP +`200` or `201` response after accepting the notification. + +When the user successfully shares their Aadhaar details, Setu sends: + + + {`{ + "status": "success", + "workflow_id": "9f2d1b7a-4f5c-4a6d-8d8e-1a2b3c4d5e6f", + "txn": "9f2d1b7a-4f5c-4a6d-8d8e-1a2b3c4d5e6f", + "traceId": "7e3a9c2d-8b4f-4d6c-a123-4f56789abcde", + "error": { + "code": "0", + "detail": "" + }, + "aadhaar_output": { + "residentName": "John Doe", + "dob": "1990-01-01", + "gender": "MALE", + "pincode": "123456", + "address": "123 Main Street, Springfield, Example State 123456" + } + }`} + + +The webhook payload contains the same `workflow_id` and `txn` for this flow. + +If the user aborts authentication or UIDAI returns an authentication error, the +webhook is sent with `status: "error"`, the UIDAI error code and message, and +no Aadhaar output. Webhook error codes are UIDAI numeric codes represented as +strings; they are separate from the textual Setu API error codes such as +`invalid_payload` and `NO_ERROR`. UIDAI error code `303` means that the user +aborted the authentication process: + + + {`{ + "status": "error", + "workflow_id": "bc2bb5ac-4e26-4b89-9c80-0d7a95c2ee27", + "txn": "bc2bb5ac-4e26-4b89-9c80-0d7a95c2ee27", + "traceId": "c926a621-97a3-4e1b-a438-81bc3b61614d", + "error": { + "code": "303", + "detail": "Authentication process aborted by user" + }, + "aadhaar_output": null + }`} + + +If authentication cannot be completed because of a network issue or a server error on UIDAI's side, +the webhook contains UIDAI error code `307`: + + + {`{ + "status": "error", + "workflow_id": "08d96879-0626-4960-8378-97fb9042f51a", + "txn": "08d96879-0626-4960-8378-97fb9042f51a", + "traceId": "1-6a6882b8-3fc3c3ec7c9eaf1a693a4772", + "error": { + "code": "307", + "detail": "Failed to complete authentication due to network or server error" + }, + "aadhaar_output": null + }`} + + +Use `workflow_id` or `txn` to correlate the notification with the request, and +handle both `success` and `error` statuses in your webhook handler. + +
+ + + + diff --git a/content/endpoints.json b/content/endpoints.json index 08d01f1c..37a1c680 100644 --- a/content/endpoints.json +++ b/content/endpoints.json @@ -116,6 +116,12 @@ "path": "ekyc", "order": 8, "visible_in_sidebar": false + }, + { + "name": "mAadhaar verification", + "path": "maadhaar", + "order": 9, + "visible_in_sidebar": true } ] }, diff --git a/docs-ingestion/src/normalize-api-specs.test.ts b/docs-ingestion/src/normalize-api-specs.test.ts index d8962305..09bd722b 100644 --- a/docs-ingestion/src/normalize-api-specs.test.ts +++ b/docs-ingestion/src/normalize-api-specs.test.ts @@ -593,9 +593,9 @@ describe('buildOutputFiles', () => { // ============================================================================ describe('Integration: discoverSpecFiles', () => { - test('should discover all 25 spec files', async () => { + test('should discover all 27 spec files', async () => { const files = await discoverSpecFiles(API_REFERENCES_DIR); - expect(files.length).toBe(26); + expect(files.length).toBe(27); }); test('should have correct categories', async () => {