{
  "openapi": "3.0.0",
  "info": {
    "version": "3.0.0",
    "title": "Didit Verification API",
    "description": "Identity verification API. Authenticate with x-api-key header."
  },
  "servers": [
    {
      "url": "https://verification.didit.me"
    }
  ],
  "tags": [],
  "paths": {
    "/system/healthcheck": {
      "get": {
        "summary": "Service healthcheck (public, unauthenticated)",
        "description": "Public unauthenticated liveness probe. Returns `HTTP 200` with `{status: \"ok\", timestamp}` when service, DB, cache, and broker are healthy.",
        "operationId": "get_system_healthcheck",
        "tags": [
          "System"
        ],
        "security": [],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Service is healthy and accepting requests. Body is always `{\"status\": \"ok\", \"timestamp\": \"<iso8601>\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "timestamp"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok"
                      ],
                      "description": "Liveness marker. Always the literal string `\"ok\"` on a 200 response.",
                      "example": "ok"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Server time at which the healthcheck was evaluated, in ISO 8601 with millisecond precision and a `Z` (UTC) suffix.",
                      "example": "2026-04-21T16:42:50.445Z"
                    }
                  }
                },
                "examples": {
                  "Healthy": {
                    "summary": "Service is up",
                    "value": {
                      "status": "ok",
                      "timestamp": "2026-04-21T16:42:50.445Z"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service is unhealthy — one of the configured health-check plugins (database, cache, broker) is failing. The response body is intentionally minimal; the HTTP status is the load-bearing signal. Retry with exponential backoff."
          },
          "5XX": {
            "description": "Verification service is degraded or unreachable. Treat any non-2xx response as \"unhealthy\" and retry with exponential backoff."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -i https://verification.didit.me/system/healthcheck"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.get(\"https://verification.didit.me/system/healthcheck\", timeout=5)\nresp.raise_for_status()\nprint(resp.json())  # {'status': 'ok', 'timestamp': '2026-04-21T16:42:50.445Z'}"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(\"https://verification.didit.me/system/healthcheck\");\nif (!res.ok) throw new Error(`Didit unhealthy: ${res.status}`);\nconst body = await res.json();\nconsole.log(body); // { status: 'ok', timestamp: '2026-04-21T16:42:50.445Z' }"
          }
        ]
      }
    },
    "/v3/email/risk/": {
      "post": {
        "summary": "Risk-score an email address",
        "description": "Return deliverability, disposable-address, breach, cross-session match, and normalized risk-intelligence signals without sending an OTP. The endpoint creates an API session and returns its id as `request_id`.\n\n**Decision.** The top-level `status` mirrors `email.status`. It is normally `Approved`; the risk evaluation can produce `In Review` or `Declined`.\n\n**Compatibility aliases.** Live responses expose the normalized intelligence object as both `email.email_intelligence` and `email.enrichment`. The values are identical. New integrations can read `email.enrichment`. Both keys are absent when no usable intelligence data was returned.\n\n**Billing.** Live calls use Email Risk API pricing. The request is billable once the lookup starts, even when some best-effort fields are unavailable.\n\n**Sandbox.** Sandbox keys validate the request and return deterministic approved data without sending an email, consuming credits, creating a session, or contributing to Networks.\n\n**Authentication.** Send your application's API key in `x-api-key`. Missing or invalid credentials return `403` - this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests per minute per API key across all POST/PATCH/DELETE endpoints.\n\n**Social footprint.** Set `enable_social` to `true` to add a `email_social` block: the online platforms this address is registered on, with per-category counts and any profile details available. `profiles_registered: 0` means the platforms were checked and the address was found on none of them - a valid, billable answer. The block is absent when the add-on was not requested or the check could not be completed, and it is not billed in that case. Billing adds one `email_social` unit per request on top of this endpoint's own price.",
        "operationId": "post_v3email_risk",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/email/risk/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"email\": \"alice@example.com\",\n    \"country_code\": \"US\",\n    \"vendor_data\": \"lead-123\",\n    \"metadata\": {\"source\": \"signup_prescreen\"}\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/email/risk/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"], \"Content-Type\": \"application/json\"},\n    json={\n        \"email\": \"alice@example.com\",\n        \"country_code\": \"US\",\n        \"vendor_data\": \"lead-123\",\n        \"metadata\": {\"source\": \"signup_prescreen\"},\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result[\"status\"])  # Approved / In Review / Declined\nprint(result[\"email\"][\"is_breached\"], result[\"email\"][\"is_disposable\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/email/risk/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    email: 'alice@example.com',\n    country_code: 'US',\n    vendor_data: 'lead-123',\n    metadata: { source: 'signup_prescreen' },\n  }),\n});\nconst data = await res.json();\nconsole.log(data.status, data.email.is_breached, data.email.is_disposable);"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRiskRequest"
              },
              "examples": {
                "Minimal": {
                  "summary": "Score an address with defaults",
                  "value": {
                    "email": "alice@example.com"
                  }
                },
                "Full context": {
                  "summary": "Score with signals, country hint, and correlation ids",
                  "value": {
                    "email": "alice@example.com",
                    "country_code": "US",
                    "signals": {
                      "ip": "192.0.2.1",
                      "device_id": "8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2",
                      "device_platform": "web",
                      "os_version": "14.4",
                      "app_version": "1.2.34",
                      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15"
                    },
                    "vendor_data": "lead-123",
                    "metadata": {
                      "source": "signup_prescreen"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The risk evaluation completed. Inspect `status` for the decision; HTTP is always `200` for completed lookups.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailRiskResponse"
                },
                "examples": {
                  "Clean address": {
                    "summary": "Deliverable address with no breach exposure",
                    "value": {
                      "request_id": "82397be9-5921-4970-a979-2d5b43e08b33",
                      "status": "Approved",
                      "email": {
                        "status": "Approved",
                        "email": "alice@example.com",
                        "is_breached": false,
                        "breaches": [],
                        "is_disposable": false,
                        "is_undeliverable": false,
                        "verification_attempts": 0,
                        "verified_at": null,
                        "warnings": [],
                        "lifecycle": [],
                        "matches": [],
                        "email_intelligence": {
                          "score": 4.0,
                          "deliverable": "high",
                          "breach_risk_level": "Low",
                          "breach_risk_index": 4,
                          "is_recent_breach": false,
                          "is_frequent_breached": false,
                          "is_disposable": false,
                          "is_free_domain": false,
                          "is_breached": false,
                          "no_of_breaches": 0,
                          "reason_codes": []
                        },
                        "enrichment": {
                          "score": 4.0,
                          "deliverable": "high",
                          "breach_risk_level": "Low",
                          "breach_risk_index": 4,
                          "is_recent_breach": false,
                          "is_frequent_breached": false,
                          "is_disposable": false,
                          "is_free_domain": false,
                          "is_breached": false,
                          "no_of_breaches": 0,
                          "reason_codes": []
                        }
                      },
                      "vendor_data": "lead-123",
                      "metadata": {
                        "source": "signup_prescreen"
                      },
                      "created_at": "2026-09-01T10:30:00.123456+00:00"
                    }
                  },
                  "Breached address": {
                    "summary": "Address found in known breaches",
                    "value": {
                      "request_id": "d1e5c2a8-6f30-4c1a-8b2d-3e4f5a6b7c8d",
                      "status": "In Review",
                      "email": {
                        "status": "In Review",
                        "email": "bob@example.org",
                        "is_breached": true,
                        "breaches": [
                          {
                            "name": "ExampleBreach2023",
                            "domain": "example.org",
                            "breach_date": "2023-06-01",
                            "breach_emails_count": 1200000,
                            "description": "A data breach affecting example.org accounts.",
                            "logo_path": "https://logos.example.org/example.png",
                            "data_classes": [
                              "email_addresses",
                              "passwords"
                            ],
                            "is_verified": true
                          }
                        ],
                        "is_disposable": false,
                        "is_undeliverable": false,
                        "verification_attempts": 0,
                        "verified_at": null,
                        "warnings": [],
                        "lifecycle": [],
                        "matches": [],
                        "email_intelligence": {
                          "score": 58.0,
                          "deliverable": "high",
                          "breach_risk_level": "High",
                          "breach_risk_index": 72,
                          "is_recent_breach": true,
                          "is_frequent_breached": true,
                          "is_disposable": false,
                          "is_free_domain": true,
                          "is_breached": true,
                          "no_of_breaches": 4,
                          "reason_codes": [
                            "BREACH_EXPOSURE",
                            "FREQUENT_BREACH"
                          ]
                        },
                        "enrichment": {
                          "score": 58.0,
                          "deliverable": "high",
                          "breach_risk_level": "High",
                          "breach_risk_index": 72,
                          "is_recent_breach": true,
                          "is_frequent_breached": true,
                          "is_disposable": false,
                          "is_free_domain": true,
                          "is_breached": true,
                          "no_of_breaches": 4,
                          "reason_codes": [
                            "BREACH_EXPOSURE",
                            "FREQUENT_BREACH"
                          ]
                        }
                      },
                      "vendor_data": "lead-125",
                      "metadata": null,
                      "created_at": "2026-09-01T10:30:00.123456+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EmailRiskValidationError"
          },
          "403": {
            "$ref": "#/components/responses/RiskPermissionDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedWrite"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/ip/risk/": {
      "post": {
        "summary": "Risk-score an IP address",
        "description": "Return geolocation, network ownership, VPN/Tor and data-center flags, threat data, and `country_mismatch` for a supplied IP address. The endpoint creates an API session and returns its id as `request_id`.\n\n**Decision.** `status` is `In Review` when the resolved country conflicts with `claimed_country`, or when the address is associated with VPN, Tor, or data-center infrastructure. Otherwise it is `Approved`.\n\n**Best effort.** IP enrichment is best effort. If no enrichment source returns usable data, the endpoint returns an approved response with `ip.ip_address: null`, `ip.country_mismatch: null`, and an empty `ip.threat` object.\n\n**Billing.** Live calls use IP Risk API pricing. The request is billable once the lookup starts.\n\n**Sandbox.** Sandbox keys validate the request and return deterministic approved data without consuming credits, creating a session, or contributing to Networks.\n\n**Authentication.** Send your application's API key in `x-api-key`. Missing or invalid credentials return `403` - this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests per minute per API key across all POST/PATCH/DELETE endpoints.",
        "operationId": "post_v3ip_risk",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/ip/risk/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"ip_address\": \"8.8.8.8\",\n    \"claimed_country\": \"ESP\",\n    \"user_agent\": \"Mozilla/5.0\",\n    \"vendor_data\": \"lead-123\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/ip/risk/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"], \"Content-Type\": \"application/json\"},\n    json={\n        \"ip_address\": \"8.8.8.8\",\n        \"claimed_country\": \"ESP\",\n        \"user_agent\": \"Mozilla/5.0\",\n        \"vendor_data\": \"lead-123\",\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result[\"status\"])  # Approved / In Review\nprint(result[\"ip\"][\"ip_country_code\"], result[\"ip\"][\"country_mismatch\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/ip/risk/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    ip_address: '8.8.8.8',\n    claimed_country: 'ESP',\n    user_agent: 'Mozilla/5.0',\n    vendor_data: 'lead-123',\n  }),\n});\nconst data = await res.json();\nconsole.log(data.status, data.ip.country_mismatch);"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IPRiskRequest"
              },
              "examples": {
                "Minimal": {
                  "summary": "Score an address with defaults",
                  "value": {
                    "ip_address": "8.8.8.8"
                  }
                },
                "With claimed country": {
                  "summary": "Score with a claimed country for mismatch detection",
                  "value": {
                    "ip_address": "8.8.8.8",
                    "claimed_country": "ESP",
                    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15",
                    "vendor_data": "lead-123"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The risk evaluation completed. Inspect `status` for the decision; HTTP is always `200` for completed lookups.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IPRiskResponse"
                },
                "examples": {
                  "Clean residential IP": {
                    "summary": "Residential address, claimed country matches",
                    "value": {
                      "request_id": "9a96ed2a-721e-4b86-8cbf-d61eda529279",
                      "status": "Approved",
                      "ip": {
                        "status": "Approved",
                        "ip_address": "192.0.2.10",
                        "ip_country": "Spain",
                        "ip_country_code": "ES",
                        "ip_state": "Madrid",
                        "ip_city": "Madrid",
                        "latitude": 40.4168,
                        "longitude": -3.7038,
                        "isp": "Example Telecom",
                        "organization": "Example Telecom SA",
                        "is_vpn_or_tor": false,
                        "is_data_center": false,
                        "time_zone": "Europe/Madrid",
                        "time_zone_offset": "+0200",
                        "asn_number": 3352,
                        "asn_organization": "EXAMPLE-TELECOM",
                        "connection_type": "broadband",
                        "carrier": "Example Telecom",
                        "proxy_type": null,
                        "claimed_country": "ESP",
                        "country_mismatch": false,
                        "threat": {}
                      },
                      "vendor_data": "lead-123",
                      "metadata": null,
                      "created_at": "2026-09-01T10:30:00.123456+00:00"
                    }
                  },
                  "Datacenter mismatch": {
                    "summary": "Data-center address conflicting with the claimed country",
                    "value": {
                      "request_id": "5b1d4e9a-3c7b-4f8e-9a2d-1b0c9d8e7f6a",
                      "status": "In Review",
                      "ip": {
                        "status": "In Review",
                        "ip_address": "8.8.8.8",
                        "ip_country": "United States",
                        "ip_country_code": "US",
                        "ip_state": "California",
                        "ip_city": "Mountain View",
                        "latitude": 37.386,
                        "longitude": -122.0838,
                        "isp": "Google",
                        "organization": "Google LLC",
                        "is_vpn_or_tor": true,
                        "is_data_center": true,
                        "time_zone": "America/Los_Angeles",
                        "time_zone_offset": "-0700",
                        "asn_number": 15169,
                        "asn_organization": "GOOGLE, US",
                        "connection_type": "hosting",
                        "carrier": null,
                        "proxy_type": "VPN",
                        "claimed_country": "ESP",
                        "country_mismatch": true,
                        "threat": {
                          "is_proxy": true,
                          "is_data_center": true,
                          "is_tor": false
                        }
                      },
                      "vendor_data": "lead-126",
                      "metadata": null,
                      "created_at": "2026-09-01T10:30:00.123456+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/IPRiskValidationError"
          },
          "403": {
            "$ref": "#/components/responses/RiskPermissionDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedWrite"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/phone/risk/": {
      "post": {
        "summary": "Risk-score a phone number",
        "description": "Resolve a phone number and return carrier, line-type, porting, disposable-number, cross-session match, and normalized risk-intelligence signals without sending an OTP. The endpoint creates an API session and returns its id as `request_id`.\n\n**Decision.** The top-level `status` mirrors `phone.status`. It is normally `Approved`; the risk evaluation can produce `In Review` or `Declined`.\n\n**Compatibility aliases.** Live responses expose the normalized intelligence object as both `phone.phone_intelligence` and `phone.enrichment`. The values are identical. New integrations can read `phone.enrichment`. Both keys are absent when no usable intelligence data was returned.\n\n**Billing.** Live calls use Phone Risk API pricing. The request is billable once the lookup starts, even when some best-effort fields are unavailable.\n\n**Sandbox.** Sandbox keys validate the request and return deterministic approved data without sending an OTP, consuming credits, creating a session, or contributing to Networks.\n\n**Authentication.** Send your application's API key in `x-api-key`. Missing or invalid credentials return `403` - this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests per minute per API key across all POST/PATCH/DELETE endpoints.\n\n**Social footprint.** Set `enable_social` to `true` to add a `phone_social` block: the online platforms this number is registered on, with per-category counts and any profile details available. `profiles_registered: 0` means the platforms were checked and the number was found on none of them - a valid, billable answer. The block is absent when the add-on was not requested or the check could not be completed, and it is not billed in that case. Billing adds one `phone_social` unit per request on top of this endpoint's own price.",
        "operationId": "post_v3phone_risk",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/phone/risk/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"phone_number\": \"+14155552671\",\n    \"country_code\": \"US\",\n    \"vendor_data\": \"lead-123\",\n    \"metadata\": {\"source\": \"signup_prescreen\"}\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/phone/risk/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"], \"Content-Type\": \"application/json\"},\n    json={\n        \"phone_number\": \"+14155552671\",\n        \"country_code\": \"US\",\n        \"vendor_data\": \"lead-123\",\n        \"metadata\": {\"source\": \"signup_prescreen\"},\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result[\"status\"])  # Approved / In Review / Declined\nprint(result[\"phone\"][\"phone_intelligence\"][\"score\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/phone/risk/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    phone_number: '+14155552671',\n    country_code: 'US',\n    vendor_data: 'lead-123',\n    metadata: { source: 'signup_prescreen' },\n  }),\n});\nconst data = await res.json();\nconsole.log(data.status, data.phone.phone_intelligence?.score);"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhoneRiskRequest"
              },
              "examples": {
                "Minimal": {
                  "summary": "Score a number with defaults",
                  "value": {
                    "phone_number": "+14155552671"
                  }
                },
                "Full context": {
                  "summary": "Score with signals, country hint, and correlation ids",
                  "value": {
                    "phone_number": "+14155552671",
                    "country_code": "US",
                    "signals": {
                      "ip": "192.0.2.1",
                      "device_id": "8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2",
                      "device_platform": "ios",
                      "device_model": "iPhone17,2",
                      "os_version": "18.0.1",
                      "app_version": "1.2.34",
                      "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1"
                    },
                    "vendor_data": "lead-123",
                    "metadata": {
                      "source": "signup_prescreen"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The risk evaluation completed. Inspect `status` for the decision; HTTP is always `200` for completed lookups.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneRiskResponse"
                },
                "examples": {
                  "Clean mobile number": {
                    "summary": "Clean mobile number with intelligence coverage",
                    "value": {
                      "request_id": "4fd09d2e-9bc9-4c4e-9c46-7f625ac0ab62",
                      "status": "Approved",
                      "phone": {
                        "status": "Approved",
                        "phone_number_prefix": "+1",
                        "phone_number": "4155552671",
                        "full_number": "+14155552671",
                        "country_code": "US",
                        "country_name": "United States",
                        "carrier": {
                          "name": "Example Mobile",
                          "type": "mobile"
                        },
                        "is_disposable": false,
                        "is_virtual": false,
                        "verification_method": null,
                        "verification_attempts": 0,
                        "verified_at": null,
                        "warnings": [],
                        "lifecycle": [],
                        "matches": [],
                        "phone_intelligence": {
                          "score": 3.0,
                          "phone_type_risk": "Low",
                          "phone_trust_index": 97,
                          "network_stability_index": 95,
                          "is_disposable": false,
                          "is_ported": false,
                          "is_recently_ported": false,
                          "carrier_type": "mobile",
                          "reason_codes": []
                        },
                        "enrichment": {
                          "score": 3.0,
                          "phone_type_risk": "Low",
                          "phone_trust_index": 97,
                          "network_stability_index": 95,
                          "is_disposable": false,
                          "is_ported": false,
                          "is_recently_ported": false,
                          "carrier_type": "mobile",
                          "reason_codes": []
                        }
                      },
                      "vendor_data": "lead-123",
                      "metadata": {
                        "source": "signup_prescreen"
                      },
                      "created_at": "2026-09-01T10:30:00.123456+00:00"
                    }
                  },
                  "Number in review": {
                    "summary": "Disposable or virtual number flagged for review",
                    "value": {
                      "request_id": "8c22e1f0-4b3d-4a3a-9d1e-2f6b7c8d9e0f",
                      "status": "In Review",
                      "phone": {
                        "status": "In Review",
                        "phone_number_prefix": "+44",
                        "phone_number": "7700900123",
                        "full_number": "+447700900123",
                        "country_code": "GB",
                        "country_name": "United Kingdom",
                        "carrier": {
                          "name": "Example VoIP",
                          "type": "voip"
                        },
                        "is_disposable": true,
                        "is_virtual": true,
                        "verification_method": null,
                        "verification_attempts": 0,
                        "verified_at": null,
                        "warnings": [],
                        "lifecycle": [],
                        "matches": [],
                        "phone_intelligence": {
                          "score": 72.0,
                          "phone_type_risk": "High",
                          "phone_trust_index": 28,
                          "network_stability_index": 40,
                          "is_disposable": true,
                          "is_ported": true,
                          "is_recently_ported": true,
                          "carrier_type": "voip",
                          "reason_codes": [
                            "DISPOSABLE_NUMBER",
                            "RECENT_PORT"
                          ]
                        },
                        "enrichment": {
                          "score": 72.0,
                          "phone_type_risk": "High",
                          "phone_trust_index": 28,
                          "network_stability_index": 40,
                          "is_disposable": true,
                          "is_ported": true,
                          "is_recently_ported": true,
                          "carrier_type": "voip",
                          "reason_codes": [
                            "DISPOSABLE_NUMBER",
                            "RECENT_PORT"
                          ]
                        }
                      },
                      "vendor_data": "lead-124",
                      "metadata": null,
                      "created_at": "2026-09-01T10:30:00.123456+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/PhoneRiskValidationError"
          },
          "403": {
            "$ref": "#/components/responses/RiskPermissionDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitedWrite"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/": {
      "post": {
        "summary": "Create a verification session",
        "description": "Create a User Verification (KYC) or Business Verification (KYB) session and receive a hosted verification `url` plus a `session_token` to redirect or embed for your end user. The `workflow_id` selects which verification steps run and whether the session is KYC or KYB.\n\nCall this from your backend (never the browser — the API key is a secret) whenever a user or business needs to be verified: at signup, before a sensitive action, or when re-verification is required. Prerequisites: a published workflow (created in the Console [Workflows](https://docs.didit.me/console/workflows) page) and an application API key with available credits. Sandbox applications bypass the credit check.\n\n**Idempotency:** when `vendor_data` is provided and an unfinished session (`Not Started`, `In Progress`, `Resubmitted`, or `Awaiting User`) with the same `vendor_data` already exists on the workflow's **current latest published version** (and that session already has a hosted verification URL), the existing session is returned (still `201`) instead of creating a duplicate — with its `callback` and `metadata` updated to the newly provided values. An unfinished session created on an older version of the workflow (one that has since been republished) is **not** reused; a new session pinned to the latest published version is created instead. Sessions in `Approved`, `Declined`, `In Review`, `Expired`, `Abandoned`, or `Kyc Expired` are never reused.\n\n**Side effects:** the hosted verification URL is generated and stored; if `contact_details.send_notification_emails` is `true` and an email is provided, a verification invite email is sent. The session expires after the workflow's configured session expiration time. For KYB workflows, `contact_details.phone` and `expected_details` are ignored.",
        "operationId": "post_v3_session_create",
        "tags": [
          "Sessions"
        ],
        "responses": {
          "201": {
            "description": "Session created (or returned, if an unfinished session with the same `vendor_data` already exists on the workflow's latest published version). The response is the serialized session, including the hosted verification `url` to redirect the user to.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "session_id",
                    "session_number",
                    "session_token",
                    "url",
                    "vendor_data",
                    "metadata",
                    "status",
                    "workflow_id",
                    "workflow_version",
                    "callback"
                  ],
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Unique identifier of the verification session. Use this id when calling `GET /v3/session/{sessionId}/decision/`.",
                      "example": "11111111-2222-3333-4444-555555555555"
                    },
                    "session_number": {
                      "type": "integer",
                      "description": "Sequential, human-friendly number assigned to the session inside your application. Useful for support and dashboards.",
                      "example": 43762
                    },
                    "session_token": {
                      "type": "string",
                      "description": "12-character URL-safe token that authorizes the end user to access the hosted verification flow at `url`. Valid until the session expires. Treat it as a secret — anyone holding it can open the verification flow for this session.",
                      "example": "3FaJ9wLqX2Mz"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Hosted verification URL to redirect the end user to. The URL embeds the `session_token` and, if configured, uses your white-label domain. When the request includes `language`, the URL contains a language path segment — `https://verify.didit.me/{language}/session/{session_token}` (e.g. `/es/session/...`); without `language`, the segment is omitted.",
                      "example": "https://verify.didit.me/session/3FaJ9wLqX2Mz"
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Identifier you passed in the request to link the session to a user or business in your own system. Echoed back verbatim. Null when not provided.",
                      "example": "user-123"
                    },
                    "metadata": {
                      "description": "Arbitrary JSON payload you stored with the session at creation time. Echoed back verbatim — whatever JSON value you sent (object, string, number, array) is returned as-is, though a JSON object is recommended. Not shown to the end user. Always present in responses; `null` when not provided at creation time.",
                      "example": {
                        "user_type": "premium",
                        "account_id": "ABC123"
                      }
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "Not Started",
                        "In Progress",
                        "Approved",
                        "Declined",
                        "In Review",
                        "Expired",
                        "Abandoned",
                        "Kyc Expired",
                        "Resubmitted",
                        "Awaiting User"
                      ],
                      "description": "Current status of the session. Newly created sessions return `Not Started`. If a non-finished session already existed for the same `vendor_data` on the workflow's latest published version, the returned status reflects that existing session.",
                      "example": "Not Started"
                    },
                    "callback": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "Final redirect URL the user is sent to after completing the flow. Didit appends `?verificationSessionId={session_id}&status={status}` to this URL. Falls back to the workflow's configured callback URL when not provided in the request; `null` when neither is set.",
                      "example": "https://example.com/verification/callback"
                    },
                    "workflow_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Stable identifier of the workflow this session runs on. Always the workflow's stable group identifier — even if you referenced a specific workflow version UUID in the request (backward-compatible lookup), the response carries the stable `workflow_id`. Use it to correlate the session with the workflow you configured in the Console.",
                      "example": "11111111-2222-3333-4444-555555555555"
                    },
                    "workflow_version": {
                      "type": "integer",
                      "description": "Version number of the published workflow version the session was pinned to at creation. Didit resolves `workflow_id` to the workflow's latest published version when the session is created, and the session keeps running that version even if the workflow is republished later.",
                      "example": 3
                    }
                  }
                },
                "examples": {
                  "KYC session": {
                    "summary": "KYC session created",
                    "value": {
                      "session_id": "11111111-2222-3333-4444-555555555555",
                      "session_number": 43762,
                      "session_token": "3FaJ9wLqX2Mz",
                      "url": "https://verify.didit.me/en/session/3FaJ9wLqX2Mz",
                      "vendor_data": "user-123",
                      "metadata": {
                        "user_type": "premium",
                        "account_id": "ABC123"
                      },
                      "status": "Not Started",
                      "workflow_id": "11111111-2222-3333-4444-555555555555",
                      "workflow_version": 3,
                      "callback": "https://example.com/verification/callback"
                    }
                  },
                  "KYB session": {
                    "summary": "KYB session created",
                    "value": {
                      "session_id": "22222222-3333-4444-5555-666666666666",
                      "session_number": 43763,
                      "session_token": "Yk7pQ2vN8aBc",
                      "url": "https://verify.didit.me/en/session/Yk7pQ2vN8aBc",
                      "vendor_data": "company-acme-001",
                      "metadata": {
                        "tier": "enterprise"
                      },
                      "status": "Not Started",
                      "workflow_id": "33333333-4444-5555-6666-777777777777",
                      "workflow_version": 1,
                      "callback": "https://example.com/kyb/callback"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — the payload failed validation (missing or unknown `workflow_id`, invalid `language`, blocklisted `vendor_data`, malformed `portrait_image`, `address` without `country`/`poa_country`, invalid `sandbox_scenario`, etc.) or your organization does not have enough credits to start the session.\n\nThe body is an object keyed by the offending field name (or `detail` for non-field errors). Values are an **array of strings** for input-validation failures (e.g. missing required field, invalid language, oversized portrait image) and a **plain string** for failures detected while creating the session (unknown `workflow_id`, blocklisted `vendor_data`, no reference face available for a Face Match workflow). Handle both shapes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "detail": {
                      "type": "string",
                      "description": "Human-readable error message for non-field errors (e.g. insufficient credits). Field-level failures use the field name as the key instead, with a string or array-of-strings value.",
                      "example": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                },
                "examples": {
                  "Missing workflow_id": {
                    "summary": "Required field omitted (array-of-strings shape)",
                    "value": {
                      "workflow_id": [
                        "This field is required."
                      ]
                    }
                  },
                  "Invalid workflow_id": {
                    "summary": "Unknown workflow_id (plain-string shape)",
                    "value": {
                      "workflow_id": "Invalid workflow_id."
                    }
                  },
                  "Insufficient credits": {
                    "summary": "Organization is out of credits",
                    "value": {
                      "detail": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  },
                  "Blocklisted vendor_data": {
                    "summary": "vendor_data is blocklisted",
                    "value": {
                      "vendor_data": "This user or business has been blocked and cannot create new verification sessions."
                    }
                  },
                  "Portrait image too large": {
                    "summary": "portrait_image fails size validation",
                    "value": {
                      "portrait_image": [
                        "Image size exceeds 2MB."
                      ]
                    }
                  },
                  "No stored face for vendor_data": {
                    "summary": "Face Match workflow without portrait_image and no stored face for the vendor_data user",
                    "value": {
                      "portrait_image": "No stored face image was found for this user. Send a portrait_image, or complete an approved verification with face liveness or an ID document for this vendor_data first."
                    }
                  },
                  "Portrait image required without vendor_data": {
                    "summary": "Face Match workflow without portrait_image and without vendor_data",
                    "value": {
                      "portrait_image": "A portrait image is required to perform face match for this workflow. Send a portrait_image, or provide the vendor_data of a user with a previously stored face image to reuse it."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Authentication or authorization failed. The endpoint returns `403` whenever the `x-api-key` header is missing, malformed, the API key has expired, or the API key is valid but the client does not have permission to create sessions in this application (for example the API key belongs to a different organization). Re-fetch the application API key via the [Auth API](/auth-api/get-credentials) and retry.\n\n**Note:** All four failure modes return the same response body — `{\"detail\": \"You do not have permission to perform this action.\"}` — and there is no machine-readable discriminator (no error code field, no `WWW-Authenticate` challenge) that lets you tell them apart. If you need to differentiate (for example to surface a more specific error to the end user), check the `x-api-key` header is present and belongs to the intended application before calling this endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "You do not have permission to perform this action."
                    }
                  }
                },
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header or invalid API key",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "No permission": {
                    "summary": "Client cannot create sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — more than 600 session-create requests in a 60-second window from the same API key / IP. Inspect `Retry-After` and back off before retrying.\n\n**Note:** The source code also defines a `FREE_SESSION_RATE_LIMIT` of 10 calls/minute alongside `PAID_SESSION_RATE_LIMIT=600` (`sessions/serializers/session.py`), but that free-tier ceiling is **not applied to this V3 endpoint** — the rate-limit middleware enforces the 600/min `SESSION_CREATE_RATE_LIMIT` regardless of plan. 600/min is the only limit you can hit here.",
            "headers": {
              "Retry-After": {
                "description": "Seconds the caller must wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "minimum": 1,
                  "example": 42
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current 60-second window for the limit that was breached (600 for session-create). Absent on the sandbox-quota variant.",
                "schema": {
                  "type": "integer",
                  "example": 600
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Number of requests still allowed in the current window for the breached limit. Absent on the sandbox-quota variant.",
                "schema": {
                  "type": "integer",
                  "minimum": 0,
                  "example": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "UTC epoch seconds when the current rate-limit window resets. Absent on the sandbox-quota variant.",
                "schema": {
                  "type": "integer",
                  "minimum": 0,
                  "example": 1747497600
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation of the rate-limit breach. Use this message to distinguish which of the three limits was hit.",
                      "example": "Session creation rate limit exceeded. You can make up to 600 requests per minute."
                    }
                  }
                },
                "examples": {
                  "Session-create limit": {
                    "summary": "More than 600 session-create requests per minute",
                    "value": {
                      "detail": "Session creation rate limit exceeded. You can make up to 600 requests per minute."
                    }
                  },
                  "Sandbox session quota": {
                    "summary": "Sandbox application exceeded 500 sessions in 24 hours",
                    "value": {
                      "detail": "Sandbox session quota exceeded (500 sessions per 24h). Wait for the window to reset. Expected available in 3600 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/session/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"workflow_id\": \"11111111-2222-3333-4444-555555555555\",\n    \"vendor_data\": \"user-123\",\n    \"callback\": \"https://example.com/verification/callback\",\n    \"callback_method\": \"both\",\n    \"metadata\": {\"user_type\": \"premium\", \"account_id\": \"ABC123\"},\n    \"language\": \"en\",\n    \"contact_details\": {\n      \"email\": \"john.doe@example.com\",\n      \"send_notification_emails\": true,\n      \"email_lang\": \"en\",\n      \"phone\": \"+14155552671\"\n    },\n    \"expected_details\": {\n      \"first_name\": \"John\",\n      \"last_name\": \"Doe\",\n      \"date_of_birth\": \"1990-05-15\",\n      \"id_country\": \"USA\",\n      \"expected_document_types\": [\"P\", \"ID\"]\n    }\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://verification.didit.me/v3/session/\"\nheaders = {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Content-Type\": \"application/json\",\n}\npayload = {\n    \"workflow_id\": \"11111111-2222-3333-4444-555555555555\",\n    \"vendor_data\": \"user-123\",\n    \"callback\": \"https://example.com/verification/callback\",\n    \"callback_method\": \"both\",\n    \"metadata\": {\"user_type\": \"premium\", \"account_id\": \"ABC123\"},\n    \"language\": \"en\",\n    \"contact_details\": {\n        \"email\": \"john.doe@example.com\",\n        \"send_notification_emails\": True,\n        \"email_lang\": \"en\",\n        \"phone\": \"+14155552671\",\n    },\n    \"expected_details\": {\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"date_of_birth\": \"1990-05-15\",\n        \"id_country\": \"USA\",\n        \"expected_document_types\": [\"P\", \"ID\"],\n    },\n}\n\nresponse = requests.post(url, json=payload, headers=headers, timeout=15)\nresponse.raise_for_status()\nsession = response.json()\nprint(session[\"session_id\"], session[\"url\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch('https://verification.didit.me/v3/session/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    workflow_id: '11111111-2222-3333-4444-555555555555',\n    vendor_data: 'user-123',\n    callback: 'https://example.com/verification/callback',\n    callback_method: 'both',\n    metadata: { user_type: 'premium', account_id: 'ABC123' },\n    language: 'en',\n    contact_details: {\n      email: 'john.doe@example.com',\n      send_notification_emails: true,\n      email_lang: 'en',\n      phone: '+14155552671',\n    },\n    expected_details: {\n      first_name: 'John',\n      last_name: 'Doe',\n      date_of_birth: '1990-05-15',\n      id_country: 'USA',\n      expected_document_types: ['P', 'ID'],\n    },\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`Session create failed: ${response.status}`);\n}\nconst session = await response.json();\nconsole.log(session.session_id, session.url);"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "workflow_id"
                ],
                "properties": {
                  "workflow_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Stable identifier of the workflow that defines which verification steps the session will run. Workflows are created and managed in the [Workflows](/console/workflows) page of the Console. The `workflow_id` also implicitly selects whether the session is KYC or KYB.",
                    "example": "11111111-2222-3333-4444-555555555555",
                    "x-readme-id": "0.0"
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "A unique identifier for the user being verified, such as a UUID, email, or internal user ID. This field is used for: (1) **User grouping** — sessions with the same vendor_data are linked to the same user profile in the Users tab. (2) **Cross-session duplicate detection** — when checking for duplicated faces, documents, phone numbers, emails, IP addresses, or device fingerprints, sessions with the same vendor_data are treated as the same user and excluded from matches. Without vendor_data, every session is treated as a unique user and all potential duplicates are surfaced. We strongly recommend always providing a vendor_data to reduce noise in duplicate detection.",
                    "example": "user-123",
                    "x-readme-id": "0.1"
                  },
                  "callback": {
                    "type": "string",
                    "description": "URL to redirect the user to after verification completes. Didit automatically appends `verificationSessionId` and `status` (Approved, Declined, In Review) as query parameters. Custom URL schemes (e.g. `myapp://`) are supported for mobile callbacks. If omitted, the workflow's default `callback_url` is used.",
                    "example": "https://example.com/verification/callback",
                    "x-readme-id": "0.2"
                  },
                  "callback_method": {
                    "type": "string",
                    "description": "Determines which device should handle the redirect to the provided callback URL. Use `initiator` to redirect only the device that started the flow, `completer` for the device that finishes it, or `both` to allow either device to trigger the callback. If you ever notice the callback not triggering reliably, we recommend setting this value to `both`.",
                    "enum": [
                      "initiator",
                      "completer",
                      "both"
                    ],
                    "default": "initiator",
                    "example": "both",
                    "x-readme-id": "0.3"
                  },
                  "metadata": {
                    "description": "Arbitrary JSON stored with the session and echoed back in the response and webhooks. Any JSON value is accepted (object, string, number, array), but a JSON object of key/value pairs is recommended. Not shown to the end user. Use it to pass your own correlation ids, A/B variants, or business context.",
                    "example": {
                      "user_type": "premium",
                      "account_id": "ABC123"
                    },
                    "x-readme-id": "0.4"
                  },
                  "language": {
                    "type": "string",
                    "description": "Language code (ISO 639-1) for the verification process interface. Controls the language displayed to the end user during verification. If not provided, the browser's language will be automatically detected and used. Check all the supported languages [here](/integration/supported-languages).",
                    "enum": [
                      "en",
                      "ar",
                      "bg",
                      "bn",
                      "bs",
                      "ca",
                      "cnr",
                      "cs",
                      "da",
                      "de",
                      "el",
                      "es",
                      "et",
                      "fa",
                      "fi",
                      "fr",
                      "he",
                      "hi",
                      "hr",
                      "hu",
                      "hy",
                      "id",
                      "it",
                      "ja",
                      "ka",
                      "kk",
                      "ko",
                      "ky",
                      "lt",
                      "lv",
                      "mk",
                      "mn",
                      "ms",
                      "nl",
                      "no",
                      "pl",
                      "pt-BR",
                      "pt",
                      "ro",
                      "ru",
                      "sk",
                      "sl",
                      "so",
                      "sq",
                      "sr",
                      "sv",
                      "th",
                      "tr",
                      "uk",
                      "uz",
                      "vi",
                      "zh-CN",
                      "zh-TW",
                      "zh"
                    ],
                    "example": "en",
                    "x-readme-id": "0.5"
                  },
                  "contact_details": {
                    "type": "object",
                    "description": "User contact information that can be used for notifications, prefilling verification forms, and phone verification. This includes email address, preferred language for communications, and phone number.",
                    "example": {
                      "email": "john.doe@example.com",
                      "send_notification_emails": true,
                      "email_lang": "en",
                      "phone": "+14155552671"
                    },
                    "properties": {
                      "email": {
                        "type": "string",
                        "format": "email",
                        "description": "Email address of the user (e.g., \"john.doe@example.com\") that will be used during the [Email Verification](/core-technology/email-verification/overview) step. If not provided, the user must provide it during the verification flow.",
                        "example": "john.doe@example.com",
                        "x-readme-id": "1.0"
                      },
                      "send_notification_emails": {
                        "type": "boolean",
                        "default": false,
                        "description": "If true and an email is provided, Didit sends the initial \"Verify your identity\" email asynchronously when the User Verification (KYC) or Business Verification (KYB) session is created. Didit also sends verification status notifications for sessions requiring manual review to the provided email address (e.g., from 'In Review' to 'Approved' or 'Declined'). This helps users return to your application once their verification is complete. If you have white-label activated for the session, the email sent will be white-labeled.",
                        "example": true,
                        "x-readme-id": "1.1"
                      },
                      "email_lang": {
                        "type": "string",
                        "description": "Language code (ISO 639-1) for email notifications. Controls the language of all email communications (e.g., \"en\", \"es\", \"fr\"). There is no stored default — when omitted, the verification invite email simply falls back to English (`en`) at send time. The enum below is a snapshot; the live source of truth for accepted values is the [supported languages](/integration/supported-languages) doc — always consult it before relying on a specific code.",
                        "enum": [
                          "en",
                          "ar",
                          "bg",
                          "bn",
                          "bs",
                          "ca",
                          "cnr",
                          "cs",
                          "da",
                          "de",
                          "el",
                          "es",
                          "et",
                          "fa",
                          "fi",
                          "fr",
                          "he",
                          "hi",
                          "hr",
                          "hu",
                          "hy",
                          "id",
                          "it",
                          "ja",
                          "ka",
                          "kk",
                          "ko",
                          "ky",
                          "lt",
                          "lv",
                          "mk",
                          "mn",
                          "ms",
                          "nl",
                          "no",
                          "pl",
                          "pt-BR",
                          "pt",
                          "ro",
                          "ru",
                          "sk",
                          "sl",
                          "so",
                          "sq",
                          "sr",
                          "sv",
                          "th",
                          "tr",
                          "uk",
                          "uz",
                          "vi",
                          "zh-CN",
                          "zh-TW",
                          "zh"
                        ],
                        "example": "en",
                        "x-readme-id": "1.2"
                      },
                      "phone": {
                        "type": "string",
                        "description": "Phone number in E.164 format (e.g., \"+14155552671\") that will be used during the [Phone Verification](/core-technology/phone-verification/overview) step. If not provided, the user must provide it during the verification flow. Ignored for Business Verification (KYB) workflows. **Important:** This phone number is only enforced if it is a valid E.164 phone number. If the provided number is invalid or cannot be parsed, it will be ignored and the user will be able to input any valid phone number during the Phone Verification step.",
                        "example": "+14155552671",
                        "x-readme-id": "1.3"
                      }
                    },
                    "x-readme-id": "0.4"
                  },
                  "expected_details": {
                    "type": "object",
                    "description": "Expected user details used to cross-validate against the data extracted from the user's ID document, Proof of Address, and other verification steps. Mismatches are surfaced as warnings on the decision; some fields (e.g. `id_country`, `expected_document_types`) also alter the user-facing flow. For Business Verification (KYB) workflows only the business fields (`company_name`, `registry_country`, `registration_number`) are used — they pre-fill the company registry search for the user — and all person-level fields are ignored.",
                    "example": {
                      "first_name": "John",
                      "last_name": "Doe",
                      "date_of_birth": "1990-05-15",
                      "nationality": "USA",
                      "id_country": "USA",
                      "expected_document_types": [
                        "P",
                        "ID"
                      ]
                    },
                    "properties": {
                      "first_name": {
                        "type": "string",
                        "description": "User's first name. For example, `John`. The matching uses fuzzy comparison, and you can tune the strictness by configuring the name match score threshold in the Console for both ID Document and Proof of Address workflows.",
                        "example": "John",
                        "x-readme-id": "1.0"
                      },
                      "last_name": {
                        "type": "string",
                        "description": "User's last name. For example, `Doe`. The matching uses fuzzy comparison, and you can tune the strictness by configuring the name match score threshold in the Console for both ID Document and Proof of Address workflows.",
                        "example": "Doe",
                        "x-readme-id": "1.1"
                      },
                      "date_of_birth": {
                        "type": "string",
                        "format": "date",
                        "description": "User's date of birth with format: YYYY-MM-DD. For example, `1990-05-15`.",
                        "example": "1990-05-15",
                        "x-readme-id": "1.2"
                      },
                      "gender": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                          "M",
                          "F"
                        ],
                        "default": null,
                        "description": "User's gender. Must be either 'M', 'F', or null.",
                        "example": "M",
                        "x-readme-id": "1.3"
                      },
                      "nationality": {
                        "type": "string",
                        "description": "ISO 3166-1 alpha-3 country code representing the applicant's country of origin. For example, `USA`. See the [full list of supported country codes](https://docs.didit.me/core-technology/id-verification/supported-documents-id-verification#supported-documents-by-country).",
                        "example": "USA",
                        "x-readme-id": "1.4"
                      },
                      "country": {
                        "type": "string",
                        "description": "ISO 3166-1 alpha-3 country code used as a fallback for both ID Verification and Proof of Address country-mismatch checks. Required when `address` is provided and neither `id_country` nor `poa_country` is set.",
                        "example": "USA",
                        "x-readme-id": "1.4.1"
                      },
                      "id_country": {
                        "type": "string",
                        "description": "ISO 3166-1 alpha-3 country code representing the expected country of the applicant's ID document, which may differ from nationality. For example, `GBR`. Takes priority over `country` for ID verification country mismatch checks. See the [full list of supported country codes](https://docs.didit.me/core-technology/id-verification/supported-documents-id-verification#supported-documents-by-country).",
                        "example": "GBR",
                        "x-readme-id": "1.5"
                      },
                      "poa_country": {
                        "type": "string",
                        "description": "ISO 3166-1 alpha-3 country code representing the expected country of the Proof of Address document. For example, `USA`. Takes priority over `country` for POA country mismatch checks. See the [full list of supported country codes](https://docs.didit.me/core-technology/id-verification/supported-documents-id-verification#supported-documents-by-country).",
                        "example": "USA",
                        "x-readme-id": "1.5.1"
                      },
                      "address": {
                        "type": "string",
                        "description": "The address in a human readable format, including as much information as possible. For example, `123 Main St, San Francisco, CA 94105, USA`. When provided, you must also pass `country` or `poa_country`, otherwise the request fails with `400`.",
                        "example": "123 Main St, San Francisco, CA 94105, USA",
                        "x-readme-id": "1.6"
                      },
                      "identification_number": {
                        "type": "string",
                        "description": "The user's document number, personal number, or tax number. For example, `123456789`.",
                        "example": "123456789",
                        "x-readme-id": "1.7"
                      },
                      "ip_address": {
                        "type": "string",
                        "description": "Expected IP address for the session, in IPv4 or IPv6 format. If the actual IP address differs from this value, a warning will be logged. For example, `192.168.1.100` or `2001:db8::1`.",
                        "example": "192.168.1.100",
                        "x-readme-id": "1.8"
                      },
                      "expected_document_types": {
                        "type": "array",
                        "description": "Restricts the document types the user can present during the ID verification (OCR) step. When set, the document selection screen only shows the requested types and the returned `documents_allowed` is filtered accordingly. Values are case-insensitive and deduplicated; unknown values are rejected with `400`. Allowed codes: `P` (passport), `ID` (national ID), `DL` (driver's license), `RP` (residence permit), `HIC` (health insurance card), `TC` (tax card), `SSC` (social security card).",
                        "items": {
                          "type": "string",
                          "enum": [
                            "P",
                            "ID",
                            "DL",
                            "RP",
                            "HIC",
                            "TC",
                            "SSC"
                          ]
                        },
                        "example": [
                          "P",
                          "ID"
                        ],
                        "x-readme-id": "1.9"
                      },
                      "company_name": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Expected legal name of the business being verified. For example, `Tesco PLC`. Pre-fills the company-name field of the registry search in Business Verification (KYB) workflows; when `registration_number` is also provided, the registry lookup combines both identifiers. Ignored for KYC workflows.",
                        "example": "Tesco PLC",
                        "x-readme-id": "1.10"
                      },
                      "registry_country": {
                        "type": "string",
                        "maxLength": 10,
                        "description": "ISO 3166-1 alpha-2 code of the country whose company registry the business is registered in. For example, `GB`. Where company registries operate at state or province level, append the ISO 3166-2 subdivision code as `XX-YY`: `US-CA` targets the California registry. Same format as `country_code` on the [KYB Registry Search API](https://docs.didit.me/standalone-apis/kyb-registry-search). Pre-selects the registry country in Business Verification (KYB) workflows; ignored for KYC workflows.",
                        "example": "US-CA",
                        "x-readme-id": "1.11"
                      },
                      "registration_number": {
                        "type": "string",
                        "maxLength": 100,
                        "description": "Expected registration number of the business in the company registry. For example, `00445790`. Pre-fills the registration-number field of the registry search in Business Verification (KYB) workflows; when `company_name` is also provided, the registry lookup combines both identifiers. Ignored for KYC workflows.",
                        "example": "00445790",
                        "x-readme-id": "1.12"
                      }
                    },
                    "x-readme-id": "0.5"
                  },
                  "portrait_image": {
                    "type": "string",
                    "format": "byte",
                    "description": "Base64-encoded portrait image of the end user's face (max 2MB; JPEG, PNG, WebP, or TIFF). Used as the reference image to match against the liveness capture when the workflow is a `Biometric Authentication` workflow with Face Match enabled, or any graph workflow where Face Match runs before ID Verification (OCR). Optional when the `vendor_data` user already has a stored face image: Didit reuses it automatically, resolved in priority order: approved liveness face, ePassport chip photo, ID document portrait, manually enrolled profile face (only faces from approved sessions or faces you enrolled yourself are reused). When provided, `portrait_image` always takes precedence over the stored face. If omitted and no stored face exists (or `vendor_data` is not sent), session creation fails with `400`. Ignored for other workflow types.",
                    "example": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
                    "x-readme-id": "0.6"
                  },
                  "sandbox_scenario": {
                    "type": "string",
                    "description": "Sandbox-only scenario slug. Only accepted when the API key belongs to a sandbox-mode application; rejected on live applications. When set, the create flow expands the scenario's bundled magic values onto the session's input fields (contact_details, expected_details) so the mocked providers reproduce the scenario's outcome through the real workflow pipeline. See the scenario catalog at GET /v1/sandbox/scenarios/ or [Sandbox & Test Data](/integration/sandbox-testing). You can also arm (or re-arm) a scenario after create via POST /v3/session/{sessionId}/sandbox/arm/, as long as the session is still `Not Started`. For non-doc lookup, use `lookup_partial_match`, `lookup_no_match`, or `lookup_provider_error` to test the configured attempt budget and fallback. For identity wallets, use `wallet_cancelled`, `wallet_timeout`, or `wallet_provider_error`; `approve` simulates a verified wallet. All catalog wallets can be tested in sandbox, including schemes unavailable on live applications. Simulated attempts are not charged.",
                    "example": "decline_document_expired"
                  }
                },
                "example": {
                  "workflow_id": "11111111-2222-3333-4444-555555555555",
                  "vendor_data": "user-123",
                  "callback": "https://example.com/verification/callback",
                  "callback_method": "both",
                  "metadata": {
                    "user_type": "premium",
                    "account_id": "ABC123"
                  },
                  "language": "en",
                  "contact_details": {
                    "email": "john.doe@example.com",
                    "send_notification_emails": true,
                    "email_lang": "en",
                    "phone": "+14155552671"
                  },
                  "expected_details": {
                    "first_name": "John",
                    "last_name": "Doe",
                    "date_of_birth": "1990-05-15",
                    "id_country": "USA",
                    "expected_document_types": [
                      "P",
                      "ID"
                    ]
                  }
                }
              },
              "examples": {
                "Create KYC session": {
                  "summary": "Full happy-path payload for a User Verification (KYC) session",
                  "description": "Realistic create call that uses every commonly-set field: workflow selection, vendor linkage, callback routing, metadata, locale, contact prefill, and expected user details. Copy-paste this directly into the cURL sample above.",
                  "value": {
                    "workflow_id": "11111111-2222-3333-4444-555555555555",
                    "vendor_data": "user-123",
                    "callback": "https://example.com/verification/callback",
                    "callback_method": "both",
                    "metadata": {
                      "user_type": "premium",
                      "account_id": "ABC123"
                    },
                    "language": "en",
                    "contact_details": {
                      "email": "john.doe@example.com",
                      "send_notification_emails": true,
                      "email_lang": "en",
                      "phone": "+14155552671"
                    },
                    "expected_details": {
                      "first_name": "John",
                      "last_name": "Doe",
                      "date_of_birth": "1990-05-15",
                      "nationality": "USA",
                      "id_country": "USA",
                      "expected_document_types": [
                        "P",
                        "ID"
                      ]
                    }
                  }
                },
                "Create KYB session": {
                  "summary": "Happy-path payload for a Business Verification (KYB) session",
                  "description": "Same shape as the KYC call — the `workflow_id` is what makes the session KYB. `vendor_data` typically references the company in your system and `contact_details.email` targets the legal representative who will complete the flow. `expected_details` accepts the business fields (`company_name`, `registry_country`, `registration_number`), which pre-fill the company registry search; person-level fields and `contact_details.phone` are ignored for KYB workflows.",
                  "value": {
                    "workflow_id": "33333333-4444-5555-6666-777777777777",
                    "vendor_data": "company-acme-001",
                    "callback": "https://example.com/kyb/callback",
                    "callback_method": "both",
                    "metadata": {
                      "tier": "enterprise",
                      "company_id": "ACME-001"
                    },
                    "expected_details": {
                      "company_name": "Tesco PLC",
                      "registry_country": "GB",
                      "registration_number": "00445790"
                    },
                    "language": "en",
                    "contact_details": {
                      "email": "legal-rep@acme.example.com",
                      "send_notification_emails": true,
                      "email_lang": "en"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/session/imports/": {
      "post": {
        "summary": "Create a verification import job",
        "description": "Create an asynchronous import job for historical User Verification sessions, Business Verification sessions, transaction monitoring records, or workflow custom status rules. Use this to migrate from providers such as Sumsub, MetaMap, Veriff, Onfido, Persona, Trulioo, Jumio, Incode, iDenfy, or any other provider after transforming the export into Didit's canonical CSV/NDJSON format. Imports are disabled by default and must be enabled per organization by Didit.",
        "operationId": "post_v3_session_imports_create",
        "tags": [
          "Sessions"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "import_type": {
                    "type": "string",
                    "enum": [
                      "user_verification",
                      "business_verification",
                      "status_rules",
                      "transactions"
                    ],
                    "default": "user_verification",
                    "description": "What to import: historical User Verification sessions, historical Business Verification sessions, workflow custom status rules, or historical transaction monitoring records."
                  },
                  "workflow_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Workflow UUID that imported sessions or status rules should be attached to. Required for user_verification, business_verification, and status_rules. Omit for transactions."
                  },
                  "source_format": {
                    "type": "string",
                    "enum": [
                      "csv",
                      "ndjson"
                    ],
                    "description": "Optional. Inferred from the uploaded file extension when omitted."
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Canonical CSV or NDJSON file. Use NDJSON for large imports. Maximum upload size 25 MB (use `source_file_url` for bigger files). Mutually exclusive with `source_file_url`."
                  },
                  "source_file_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Alternative to file upload. Must be an HTTPS URL resolving to a public address (private/loopback networks are rejected). Mutually exclusive with `file`."
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source_file_url"
                ],
                "properties": {
                  "import_type": {
                    "type": "string",
                    "enum": [
                      "user_verification",
                      "business_verification",
                      "status_rules",
                      "transactions"
                    ],
                    "default": "user_verification",
                    "description": "What to import: historical User Verification sessions, historical Business Verification sessions, workflow custom status rules, or historical transaction monitoring records."
                  },
                  "workflow_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Workflow UUID that imported sessions or status rules should be attached to. Required for user_verification, business_verification, and status_rules. Omit for transactions."
                  },
                  "source_format": {
                    "type": "string",
                    "enum": [
                      "csv",
                      "ndjson"
                    ],
                    "description": "Optional. Inferred from the URL's file extension when omitted."
                  },
                  "source_file_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Alternative to file upload. Must be an HTTPS URL resolving to a public address (private/loopback networks are rejected). Mutually exclusive with `file`."
                  }
                }
              },
              "examples": {
                "URL-based import": {
                  "value": {
                    "import_type": "user_verification",
                    "workflow_id": "9f9b1234-aaaa-bbbb-cccc-1234567890ab",
                    "source_file_url": "https://files.example.com/exports/sessions.ndjson"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Import job accepted. Poll the returned `uuid` until `status` is `COMPLETED` or `FAILED`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionImportJob"
                },
                "examples": {
                  "Job accepted": {
                    "value": {
                      "uuid": "3f9c1a2b-4d5e-4f60-8a7b-9c0d1e2f3a4b",
                      "status": "PENDING",
                      "import_type": "user_verification",
                      "source_format": "ndjson",
                      "source_filename": "sessions.ndjson",
                      "total_rows": 0,
                      "processed_rows": 0,
                      "checkpoint_row": 0,
                      "created_count": 0,
                      "updated_count": 0,
                      "skipped_count": 0,
                      "failed_count": 0,
                      "total_media_bytes": 0,
                      "last_error": null,
                      "created_at": "2026-05-17T08:42:11Z",
                      "updated_at": "2026-05-17T08:42:11Z",
                      "started_at": null,
                      "completed_at": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid workflow, file type, file size, source URL, or selector combination.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid workflow": {
                    "value": {
                      "workflow_id": [
                        "Invalid workflow_id."
                      ]
                    }
                  },
                  "Workflow required": {
                    "value": {
                      "workflow_id": [
                        "This field is required for this import type."
                      ]
                    }
                  },
                  "Wrong file type": {
                    "value": {
                      "file": [
                        "Only CSV and NDJSON files are supported."
                      ]
                    }
                  },
                  "File too large": {
                    "value": {
                      "file": [
                        "Import file exceeds the maximum allowed size."
                      ]
                    }
                  },
                  "No source": {
                    "value": {
                      "file": [
                        "Upload a file or provide source_file_url."
                      ]
                    }
                  },
                  "Both sources": {
                    "value": {
                      "file": [
                        "Use either file or source_file_url, not both."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Imports not enabled, sandbox application, or missing/invalid API key (this endpoint returns `403`, never `401`, for authentication failures). Verification imports are disabled by default and must be enabled per organization by Didit.",
            "content": {
              "application/json": {
                "examples": {
                  "Imports not enabled": {
                    "value": {
                      "detail": "Verification imports are not enabled for this organization."
                    }
                  },
                  "Sandbox": {
                    "value": {
                      "detail": "Verification imports are not enabled for sandbox applications."
                    }
                  },
                  "Bad API key": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "The application already has an active import job (PENDING/PROCESSING/PAUSED). Wait for it to finish before starting another.",
            "content": {
              "application/json": {
                "examples": {
                  "Active job": {
                    "value": {
                      "detail": "This application already has an active import job. Wait for it to finish before starting another."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/imports/template/": {
      "get": {
        "summary": "Download verification import template",
        "description": "Download the canonical CSV header for verification imports. The column set is determined by `import_type`. The first column of session templates is the idempotency key `external_id`.",
        "operationId": "get_v3_session_imports_template",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "import_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "user_verification",
                "business_verification",
                "status_rules",
                "transactions"
              ],
              "default": "user_verification"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV template file.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot download import templates. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "summary": "Missing, invalid, or revoked API key",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/imports/{importId}/": {
      "get": {
        "summary": "Retrieve a verification import job",
        "description": "Retrieve import progress counters and terminal status for one job. Poll until `status` is `COMPLETED` or `FAILED`; `failed_count` > 0 means some rows were rejected — list them via the errors endpoint.",
        "operationId": "get_v3_session_imports_retrieve",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "importId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Import job status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionImportJob"
                }
              }
            }
          },
          "404": {
            "description": "Import job not found for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot read import jobs for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "summary": "Missing, invalid, or revoked API key",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/imports/{importId}/errors/": {
      "get": {
        "summary": "List verification import row errors",
        "description": "List row-level errors for a verification import job, ordered by `row_number`. Use this endpoint to produce a corrected retry file containing only failed rows.",
        "operationId": "get_v3_session_imports_errors",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "importId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size. Defaults to 50 when omitted."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Zero-based offset of the first record to return."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated row errors.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of error rows — exact up to 100, capped at 100 beyond that. Rely on `next` being `null` to detect the last page."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or `null` on the last page."
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or `null` on the first page."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SessionImportError"
                      }
                    }
                  }
                },
                "examples": {
                  "Row errors": {
                    "value": {
                      "count": 1,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "uuid": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
                          "row_number": 17,
                          "external_id": "ext-000017",
                          "error": "status: invalid value 'unknown_status'",
                          "raw_row": {
                            "external_id": "ext-000017",
                            "status": "unknown_status",
                            "first_name": "Jane"
                          },
                          "created_at": "2026-05-17T08:44:02Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Import job not found for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot read import jobs for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "summary": "Missing, invalid, or revoked API key",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/{sessionId}/decision/": {
      "get": {
        "summary": "Retrieve the full decision for a verification session",
        "description": "Retrieve the complete decision report for a verification session — the rolled-up session `status` plus one report per verification feature the workflow executed. This is the canonical read endpoint for both User Verification (KYC) and Business Verification (KYB) sessions: the same path serves both, and the top-level `session_kind` discriminator tells you which shape you received (`\"user\"` or `\"business\"`).\n\n**Every feature report is a plural array.** V3 workflows are graphs that can run the same feature more than once, so each block (`id_verifications`, `nfc_verifications`, `liveness_checks`, `face_matches`, `poa_verifications`, `document_ai_documents`, `phone_verifications`, `email_verifications`, `aml_screenings`, `ip_analyses`, `database_validations`, `questionnaire_responses`) is a JSON array whose items each carry a `node_id` identifying the workflow graph node that produced them. Read NFC as `response.nfc_verifications[0]` — never as a singular `nfc` field. A block is `null` until the workflow has run that feature at least once; features the workflow does not include never appear with data.\n\n**When to call.** The recommended pattern is event-driven: wait for the `status.updated` webhook that fires when the session reaches a decision (`Approved`, `Declined`, `In Review`), then call this endpoint once to fetch the full report. Polling also works — the endpoint can be called at any point in the session lifecycle and returns the data produced so far — but webhook-then-fetch is cheaper and faster. Media URLs in the response (document images, videos, PDFs) are short-lived presigned links: fetch them promptly or re-request the decision to get fresh ones, and do not persist them as long-term references.\n\n**Statuses.** The top-level `status` is the session lifecycle status (`Not Started`, `In Progress`, `Awaiting User`, `In Review`, `Approved`, `Declined`, `Resubmitted`, `Expired`, `Kyc Expired`, `Abandoned`). Each feature item additionally carries its own feature-level `status` (`Not Finished`, `Approved`, `Declined`, `In Review`, ...). A session can be `Approved` overall while an individual feature is `In Review`, depending on the workflow's decision rules.\n\n**Authentication and visibility.** Authenticate with the application API key in the `x-api-key` header (a console user Bearer token with the `read:sessions` permission also works). Only sessions owned by the authenticated application are visible. If your workflow restricts response attributes, non-allowed fields inside feature items are returned as `null` while `status`, `warnings`, and `node_id` are always preserved.\n\n**Rate limits.** GET requests are limited to 600 per minute per API key. Exceeding the limit returns `429` with `Retry-After` and `X-RateLimit-*` headers.",
        "operationId": "get_v3_session_decision",
        "responses": {
          "200": {
            "description": "Full decision report. `session_kind` discriminates the two shapes: `user` sessions carry the KYC feature arrays shown below; `business` sessions instead carry `registry_checks`, `document_verifications` and `key_people_checks` alongside the shared arrays. Feature arrays are `null` until the workflow has run that feature; media URLs are short-lived presigned links.",
            "content": {
              "application/json": {
                "examples": {
                  "Example": {
                    "summary": "Full Example",
                    "value": {
                      "session_id": "11111111-2222-3333-4444-555555555555",
                      "session_kind": "user",
                      "session_number": 43762,
                      "session_url": "https://verify.didit.me/session/11111111-2222-3333-4444-555555555555",
                      "status": "In Review",
                      "environment": "live",
                      "workflow_id": "11111111-2222-3333-4444-555555555555",
                      "features": [
                        "ID_VERIFICATION",
                        "NFC",
                        "LIVENESS",
                        "FACE_MATCH",
                        "POA",
                        "PHONE",
                        "DATABASE_VALIDATION",
                        "AML",
                        "IP_ANALYSIS"
                      ],
                      "vendor_data": "11111111-1111-1111-1111-111111111111",
                      "metadata": {
                        "user_type": "premium",
                        "account_id": "ABC123"
                      },
                      "expected_details": {
                        "first_name": "Carmen",
                        "last_name": "Española Española"
                      },
                      "contact_details": {
                        "email": "carmen@example.com",
                        "email_lang": "es",
                        "send_notification_emails": false,
                        "phone": null
                      },
                      "callback": "https://verify.didit.me/",
                      "id_verifications": [
                        {
                          "node_id": "feature_ocr_1",
                          "status": "Approved",
                          "document_type": "Identity Card",
                          "document_subtype": "ID_CARD_GENERIC",
                          "document_number": "CAA000000",
                          "personal_number": "99999999R",
                          "portrait_image": "https://<media-host>/portrait.jpg",
                          "front_image": "https://<media-host>/front.jpg",
                          "front_video": "https://<media-host>/front.mp4",
                          "back_image": "https://<media-host>/back.jpg",
                          "back_video": "https://<media-host>/back.mp4",
                          "full_front_image": "https://<media-host>/full_front.jpg",
                          "full_back_image": "https://<media-host>/full_back.jpg",
                          "front_image_camera_front": "https://<media-host>/front_camera_front.jpg",
                          "back_image_camera_front": "https://<media-host>/back_camera_front.jpg",
                          "date_of_birth": "1980-01-01",
                          "age": 45,
                          "expiration_date": "2031-06-02",
                          "date_of_issue": "2021-06-02",
                          "issuing_state": "ESP",
                          "issuing_state_name": "Spain",
                          "first_name": "Carmen",
                          "last_name": "Española Española",
                          "full_name": "Carmen Española Española",
                          "gender": "F",
                          "address": "Avda de Madrid 34, Madrid, Madrid",
                          "formatted_address": "Avda de Madrid 34, Madrid, Madrid 28822, Spain",
                          "place_of_birth": "Madrid",
                          "marital_status": "Single",
                          "nationality": "ESP",
                          "extra_fields": {
                            "dl_categories": [],
                            "blood_group": null
                          },
                          "mrz": {
                            "surname": "ESPANOLA ESPANOLA",
                            "name": "CARMEN",
                            "country": "ESP",
                            "nationality": "ESP",
                            "birth_date": "800101",
                            "expiry_date": "310602",
                            "sex": "F",
                            "document_type": "ID",
                            "document_number": "CAA000000",
                            "optional_data": "99999999R",
                            "optional_data_2": "",
                            "birth_date_hash": "4",
                            "expiry_date_hash": "8",
                            "document_number_hash": "4",
                            "final_hash": "1",
                            "personal_number": "99999999R",
                            "warnings": [],
                            "errors": [],
                            "mrz_type": "TD1",
                            "mrz_string": "IDESPCAA000000499999999R<<<<<<\n8001014F3106028ESP<<<<<<<<<<<1\nESPANOLA<ESPANOLA<<CARMEN<<<<<",
                            "mrz_key": "CAA000000480010143106028"
                          },
                          "parsed_address": {
                            "city": "Madrid",
                            "label": "Spain ID Card Address",
                            "region": "Madrid",
                            "country": "ES",
                            "category": "Residential",
                            "street_1": "Avda de Madrid 34",
                            "street_2": null,
                            "is_verified": true,
                            "postal_code": "28822",
                            "raw_results": {
                              "types": [
                                "street_address"
                              ],
                              "geometry": {
                                "location": {
                                  "lat": 37.4222804,
                                  "lng": -122.0843428
                                },
                                "viewport": {
                                  "northeast": {
                                    "lat": 37.4237349802915,
                                    "lng": -122.083183169709
                                  },
                                  "southwest": {
                                    "lat": 37.4210370197085,
                                    "lng": -122.085881130292
                                  }
                                },
                                "location_type": "ROOFTOP"
                              },
                              "place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4",
                              "formatted_address": "Avda de Madrid 34, 28822 Madrid, Spain",
                              "navigation_points": [
                                {
                                  "location": {
                                    "latitude": 37.4222804,
                                    "longitude": -122.0843428
                                  }
                                }
                              ],
                              "address_components": [
                                {
                                  "types": [
                                    "street_number"
                                  ],
                                  "long_name": "34",
                                  "short_name": "34"
                                },
                                {
                                  "types": [
                                    "route"
                                  ],
                                  "long_name": "Avda de Madrid",
                                  "short_name": "Avda de Madrid"
                                },
                                {
                                  "types": [
                                    "locality",
                                    "political"
                                  ],
                                  "long_name": "Madrid",
                                  "short_name": "Madrid"
                                },
                                {
                                  "types": [
                                    "country",
                                    "political"
                                  ],
                                  "long_name": "Spain",
                                  "short_name": "ES"
                                },
                                {
                                  "types": [
                                    "postal_code"
                                  ],
                                  "long_name": "28822",
                                  "short_name": "28822"
                                }
                              ]
                            },
                            "address_type": "Avda",
                            "document_location": {
                              "latitude": 37.4222804,
                              "longitude": -122.0843428
                            },
                            "formatted_address": "Avda de Madrid 34, 28822 Madrid, Spain"
                          },
                          "front_image_camera_front_face_match_score": 95.5,
                          "back_image_camera_front_face_match_score": 93.2,
                          "document_selfie_face_matches": [
                            {
                              "session_id": "3f0c9a52-7b1e-4d68-a2c4-5e9d8b7f1a20",
                              "session_number": 1180,
                              "similarity_percentage": 97.4,
                              "vendor_data": "user_ref_001",
                              "vendor_user_id": null,
                              "biometric_template_id": null,
                              "verification_date": "2026-09-02T09:15:00Z",
                              "user_details": {
                                "full_name": "Jane Doe"
                              },
                              "match_image_url": "https://<media-host>/match_face.jpg",
                              "status": "Approved",
                              "is_blocklisted": false,
                              "is_allowlisted": false,
                              "api_service": null,
                              "source": "session"
                            }
                          ],
                          "front_image_quality_score": {
                            "focus_score": 85.3,
                            "brightness_score": 92.1,
                            "brightness_issue": "ok",
                            "is_document_fully_visible": true,
                            "resolution_score": 72.4,
                            "overall_score": 88.7
                          },
                          "back_image_quality_score": {
                            "focus_score": 79.1,
                            "brightness_score": 90.5,
                            "brightness_issue": "ok",
                            "is_document_fully_visible": true,
                            "resolution_score": 72.4,
                            "overall_score": 85.2
                          },
                          "extra_files": [
                            "https://<media-host>/extra_id_verification.jpg"
                          ],
                          "matches": [
                            {
                              "session_id": "7d4f1f60-9c2e-4b8a-8f3d-2a1b5c6d7e8f",
                              "session_number": 1234,
                              "vendor_data": "user_ref_001",
                              "verification_date": "2024-06-15T10:30:00Z",
                              "user_details": {
                                "name": "John Smith",
                                "document_type": "ID",
                                "document_number": "CLM148418"
                              },
                              "status": "Approved",
                              "is_blocklisted": false,
                              "api_service": null,
                              "front_image_url": "https://<media-host>/document_front.jpg"
                            },
                            {
                              "session_id": "b2c8e4d1-6a3f-4e7b-95c0-1d8f2a6b4c9e",
                              "session_number": 1235,
                              "vendor_data": null,
                              "verification_date": "2024-05-20T14:45:00Z",
                              "user_details": {
                                "name": "John Smith",
                                "document_type": "ID",
                                "document_number": "CLM148418"
                              },
                              "status": "Declined",
                              "is_blocklisted": true,
                              "api_service": "ID_VERIFICATION",
                              "front_image_url": "https://<media-host>/document_front_2.jpg"
                            }
                          ],
                          "warnings": [
                            {
                              "feature": "ID_VERIFICATION",
                              "risk": "QR_NOT_DETECTED",
                              "additional_data": null,
                              "log_type": "information",
                              "short_description": "QR not detected",
                              "long_description": "The system couldn't find or read the QR code on the document, which is necessary for document verification. This could be due to poor image quality or an unsupported document type.",
                              "node_id": "feature_ocr_1"
                            }
                          ],
                          "verification_method": "document",
                          "assurance": "documentary",
                          "wallet_provider": null,
                          "fallback_from": null,
                          "id_lookup": null,
                          "wallet_verification": null,
                          "document_liveness": {
                            "portrait_replace": {
                              "score": 96.46,
                              "front": 96.46,
                              "back": 98.2,
                              "decline_threshold": 35,
                              "review_threshold": 70,
                              "bucket": "approve"
                            },
                            "printed_copy": {
                              "score": 91.2,
                              "front": 91.2,
                              "back": 93.7,
                              "decline_threshold": 35,
                              "review_threshold": 77,
                              "bucket": "approve"
                            },
                            "screen_replay": {
                              "score": 99.9,
                              "front": 99.9,
                              "back": 99.5,
                              "decline_threshold": 30,
                              "review_threshold": 70,
                              "bucket": "approve"
                            }
                          }
                        },
                        {
                          "node_id": "feature_ocr_2",
                          "status": "Approved",
                          "issuing_state": "ZAF",
                          "issuing_state_name": "South Africa",
                          "first_name": "Thabo",
                          "last_name": "Mokoena",
                          "full_name": "Thabo Mokoena",
                          "date_of_birth": "1991-06-15",
                          "personal_number": "9106155043088",
                          "verification_method": "id_lookup",
                          "assurance": "data_match",
                          "wallet_provider": null,
                          "fallback_from": null,
                          "id_lookup": {
                            "source": "Department of Home Affairs",
                            "checked_at": "2026-09-04T09:12:44Z",
                            "attempts": 1,
                            "max_attempts": 2,
                            "outcome": "match",
                            "comparison": [
                              {
                                "field": "identification_number",
                                "label": "ID number",
                                "provided": "9106155043088",
                                "record": "9106155043088",
                                "result": "match"
                              },
                              {
                                "field": "full_name",
                                "label": "Full name",
                                "provided": "Thabo Mokoena",
                                "record": "Thabo Mokoena",
                                "result": "match"
                              },
                              {
                                "field": "date_of_birth",
                                "label": "Date of birth",
                                "provided": "1991-06-15",
                                "record": "1991-06-15",
                                "result": "match"
                              }
                            ],
                            "registry_portrait": "https://<media-host>/registry_portrait.jpg",
                            "face_match_score": 96.4,
                            "source_errors": []
                          },
                          "wallet_verification": null,
                          "warnings": []
                        },
                        {
                          "node_id": "feature_ocr_3",
                          "status": "Approved",
                          "issuing_state": "DNK",
                          "issuing_state_name": "Denmark",
                          "first_name": "Freja",
                          "last_name": "Nielsen",
                          "full_name": "Freja Nielsen",
                          "date_of_birth": "1988-03-02",
                          "verification_method": "wallet",
                          "assurance": "cryptographic",
                          "wallet_provider": "mitid",
                          "fallback_from": null,
                          "id_lookup": null,
                          "wallet_verification": {
                            "provider": "mitid",
                            "provider_name": "MitID",
                            "issuing_authority": "Danish Agency for Digital Government",
                            "issuing_country": "DNK",
                            "credential_type": "person_identification",
                            "level_of_assurance": "substantial",
                            "verified_at": "2026-09-04T09:12:44Z",
                            "signature_valid": true,
                            "attributes": {
                              "full_name": "Freja Nielsen",
                              "date_of_birth": "1988-03-02",
                              "cpr_alias": "b0f1c2d3-e4f5-4678-9abc-def012345678"
                            },
                            "portrait": null,
                            "face_match_score": null
                          },
                          "warnings": []
                        }
                      ],
                      "nfc_verifications": [
                        {
                          "node_id": "feature_nfc_1",
                          "status": "In Review",
                          "is_nfc_skipped": false,
                          "skip_reason": null,
                          "portrait_image": "https://<media-host>/portrait.jpg",
                          "signature_image": "https://<media-host>/signature.jpg",
                          "chip_data": {
                            "document_type": "ID",
                            "issuing_country": "ESP",
                            "document_number": "123456789",
                            "expiration_date": "2030-01-01",
                            "first_name": "John",
                            "last_name": "Smith",
                            "birth_date": "1990-05-15",
                            "gender": "M",
                            "nationality": "ESP",
                            "address": "CALLE MAYOR 123 4B, MADRID, MADRID",
                            "place_of_birth": "MADRID, MADRID"
                          },
                          "authenticity": {
                            "sod_integrity": true,
                            "dg_integrity": true
                          },
                          "certificate_summary": {
                            "issuer": "Common Name: CSCA SPAIN, Serial Number: 3, Organization: DIRECCION GENERAL DE LA POLICIA, Country: ES",
                            "subject": "Common Name: DS n-eID SPAIN 2, Organizational Unit: PASSPORT, Organization: DIRECCION GENERAL DE LA POLICIA, Country: ES",
                            "serial_number": "118120836164494130086420187336801405660",
                            "not_valid_after": "2031-02-18 10:21:11",
                            "not_valid_before": "2020-11-18 10:21:11"
                          },
                          "warnings": [
                            {
                              "feature": "NFC",
                              "risk": "DATA_INCONSISTENT",
                              "additional_data": null,
                              "log_type": "warning",
                              "short_description": "OCR and NFC mrz code extracted are not the same",
                              "long_description": "The Optical Character Recognition (OCR) data and the NFC chip data don't match, indicating potential document tampering or data inconsistency.",
                              "node_id": "feature_nfc_1"
                            }
                          ]
                        }
                      ],
                      "liveness_checks": [
                        {
                          "node_id": "feature_liveness_1",
                          "status": "Approved",
                          "method": "ACTIVE_3D",
                          "score": 89.92,
                          "reference_image": "https://<media-host>/reference.jpg",
                          "video_url": "https://<media-host>/video.mp4",
                          "age_estimation": 24.3,
                          "matches": [
                            {
                              "session_id": "7d4f1f60-9c2e-4b8a-8f3d-2a1b5c6d7e8f",
                              "session_number": 1234,
                              "vendor_data": "user_ref_001",
                              "verification_date": "2024-06-15T10:30:00Z",
                              "user_details": {
                                "full_name": "John Smith",
                                "document_type": "ID",
                                "document_number": "CLM148418"
                              },
                              "status": "Approved",
                              "is_blocklisted": false,
                              "is_allowlisted": false,
                              "api_service": null,
                              "source": "session",
                              "match_image_url": "https://<media-host>/face_match.jpg",
                              "similarity_percentage": 98.5
                            },
                            {
                              "session_id": "3e9a7c21-5b48-4f0e-9c6a-8d2f4b1e0a35",
                              "session_number": 1100,
                              "vendor_data": "customer_xyz",
                              "verification_date": "2024-04-10T09:15:00Z",
                              "user_details": {
                                "full_name": "John Smith",
                                "document_type": "P",
                                "document_number": "DZ8375806"
                              },
                              "status": "Approved",
                              "is_blocklisted": false,
                              "is_allowlisted": false,
                              "api_service": "PASSIVE_LIVENESS",
                              "source": "session",
                              "match_image_url": "https://<media-host>/face_match_2.jpg",
                              "similarity_percentage": 95.2
                            }
                          ],
                          "warnings": [
                            {
                              "feature": "LIVENESS",
                              "risk": "LOW_LIVENESS_SCORE",
                              "additional_data": null,
                              "log_type": "information",
                              "short_description": "Low liveness score",
                              "long_description": "The liveness check resulted in a low score, indicating potential use of non-live facial representations or poor-quality biometric data.",
                              "node_id": "feature_liveness_1"
                            }
                          ],
                          "face_quality": null,
                          "face_luminance": null
                        }
                      ],
                      "face_matches": [
                        {
                          "node_id": "feature_face_match_1",
                          "status": "In Review",
                          "score": 65.43,
                          "source_image_session_id": null,
                          "source_image": "https://<media-host>/source-image.jpg",
                          "target_image": "https://<media-host>/target-image.jpg",
                          "warnings": [
                            {
                              "feature": "FACEMATCH",
                              "risk": "LOW_FACE_MATCH_SIMILARITY",
                              "additional_data": null,
                              "log_type": "warning",
                              "short_description": "Low face match similarity",
                              "long_description": "The facial features of the provided image don't closely match the reference image, suggesting a potential identity mismatch.",
                              "node_id": "feature_face_match_1"
                            }
                          ]
                        }
                      ],
                      "phone_verifications": [
                        {
                          "node_id": "feature_phone_1",
                          "status": "Approved",
                          "phone_number_prefix": "+34",
                          "phone_number": "600600600",
                          "full_number": "+34600600600",
                          "country_code": "ES",
                          "country_name": "Spain",
                          "carrier": {
                            "name": "Orange",
                            "type": "mobile"
                          },
                          "is_disposable": false,
                          "is_virtual": false,
                          "verification_method": "sms",
                          "verification_attempts": 1,
                          "verified_at": "2024-07-28T06:47:35.654321Z",
                          "lifecycle": [
                            {
                              "type": "PHONE_VERIFICATION_MESSAGE_SENT",
                              "timestamp": "2025-08-24T09:12:39.580554+00:00",
                              "details": {
                                "status": "Success",
                                "reason": null,
                                "channel": "sms",
                                "actual_channel": "sms"
                              },
                              "fee": 0.1
                            },
                            {
                              "type": "VALID_CODE_ENTERED",
                              "timestamp": "2025-08-24T09:12:39.662157+00:00",
                              "details": {
                                "code_tried": "123456",
                                "status": "Approved"
                              },
                              "fee": 0
                            },
                            {
                              "type": "PHONE_VERIFICATION_APPROVED",
                              "timestamp": "2025-08-24T09:12:39.684292+00:00",
                              "details": null,
                              "fee": 0
                            }
                          ],
                          "warnings": [],
                          "matches": [
                            {
                              "session_id": null,
                              "session_number": null,
                              "vendor_data": null,
                              "verification_date": null,
                              "phone_number": "+34600000000",
                              "status": null,
                              "is_blocklisted": true,
                              "api_service": null,
                              "source": "list_entry"
                            }
                          ]
                        }
                      ],
                      "email_verifications": [
                        {
                          "node_id": "feature_email_1",
                          "status": "Approved",
                          "email": "test@example.com",
                          "is_breached": true,
                          "breaches": [
                            {
                              "name": "TAPAirPortugal",
                              "domain": "flytap.com",
                              "logo_path": "https://logos.example.com/TAPAirPortugal.png",
                              "breach_date": "2022-08-25",
                              "description": "In August 2022, the Portuguese airline <a href=\"https://www.bleepingcomputer.com/news/security/ragnar-locker-ransomware-claims-attack-on-portugals-flag-airline/\" target=\"_blank\" rel=\"noopener\">TAP Air Portugal was the target of a ransomware attack perpetrated by the Ragnar Locker gang</a> who later leaked the compromised data via a public dark web site. Over 5M unique email addresses were exposed alongside other personal data including names, genders, DoBs, phone numbers and physical addresses.",
                              "is_verified": true,
                              "data_classes": [
                                "dates_of_birth",
                                "email_addresses",
                                "genders",
                                "names",
                                "nationalities",
                                "phone_numbers",
                                "physical_addresses",
                                "salutations",
                                "spoken_languages"
                              ],
                              "breach_emails_count": 6083479
                            }
                          ],
                          "is_disposable": false,
                          "is_undeliverable": false,
                          "verification_attempts": 1,
                          "verified_at": "2025-09-15T17:36:19.963451Z",
                          "warnings": [
                            {
                              "feature": "EMAIL",
                              "risk": "BREACHED_EMAIL_DETECTED",
                              "additional_data": null,
                              "log_type": "information",
                              "short_description": "Breached email detected",
                              "long_description": "This email address was found in one or more known data breaches.",
                              "node_id": "feature_email_1"
                            }
                          ],
                          "lifecycle": [
                            {
                              "type": "EMAIL_VERIFICATION_MESSAGE_SENT",
                              "timestamp": "2025-09-15T17:36:19.792684+00:00",
                              "details": {
                                "status": "Success",
                                "reason": null
                              },
                              "fee": 0.03
                            },
                            {
                              "type": "VALID_CODE_ENTERED",
                              "timestamp": "2025-09-15T17:36:19.963427+00:00",
                              "details": {
                                "code_tried": "123456",
                                "status": "Approved"
                              },
                              "fee": 0
                            },
                            {
                              "type": "EMAIL_VERIFICATION_DECLINED",
                              "timestamp": "2025-09-15T17:36:20.081471+00:00",
                              "details": {
                                "reason": "BREACHED_EMAIL_DETECTED"
                              },
                              "fee": 0
                            }
                          ],
                          "matches": [
                            {
                              "session_id": null,
                              "session_number": null,
                              "vendor_data": null,
                              "verification_date": null,
                              "email": "test@example.com",
                              "status": null,
                              "is_blocklisted": true,
                              "api_service": null,
                              "source": "list_entry"
                            }
                          ]
                        }
                      ],
                      "poa_verifications": [
                        {
                          "node_id": "feature_poa_1",
                          "status": "Declined",
                          "document_file": "https://<media-host>/poa_document.pdf",
                          "issuing_state": "AR",
                          "document_type": "UTILITY_BILL",
                          "document_subtype": null,
                          "document_language": "es",
                          "document_metadata": {
                            "file_size": 1000,
                            "content_type": "application/pdf",
                            "creation_date": "2021-01-01",
                            "modified_date": "2021-01-01",
                            "overlay_manipulation": null,
                            "creator": null,
                            "producer": "PDF Generator",
                            "software": null,
                            "encryption": null,
                            "is_signed": false,
                            "is_tampered": false,
                            "signature_info": null,
                            "exif_original_date": null,
                            "exif_digitized_date": null,
                            "processed_by_known_editor": false,
                            "has_different_creation_mod_date": true
                          },
                          "issuer": "Aguas del Norte",
                          "issue_date": "2021-02-01",
                          "expiration_date": null,
                          "poa_address": "AVDA. MONSEÑOR TAVELLA N° 3396, SALTA",
                          "poa_formatted_address": "Av. Monseñor Tavella 3396, A4400 Salta, Argentina",
                          "poa_parsed_address": {
                            "address_type": "Avenida",
                            "street_1": "Avenida Monseñor Tavella 3396",
                            "street_2": null,
                            "city": "Salta",
                            "region": "Salta",
                            "country": "AR",
                            "postal_code": "A4400",
                            "document_location": {
                              "latitude": -24.8208664,
                              "longitude": -65.4131
                            }
                          },
                          "name_on_document": "Fernando De Lima",
                          "name_match_score_expected_details": null,
                          "name_match_score_id_verification": 38.5,
                          "expected_details_address": null,
                          "expected_details_formatted_address": null,
                          "expected_details_parsed_address": {},
                          "extra_fields": {
                            "bank_account_number": "1234567890",
                            "bank_iban": null,
                            "bank_sort_code": null,
                            "bank_routing_number": null,
                            "bank_swift_bic": null,
                            "bank_branch_name": null,
                            "bank_branch_address": null,
                            "document_phone_number": "+5491112345678",
                            "additional_names": []
                          },
                          "extra_files": [
                            "https://<media-host>/extra_poa.pdf"
                          ],
                          "detected_codes": [
                            {
                              "type": "QR_CODE",
                              "page_number": 1,
                              "position": [
                                [
                                  820,
                                  1120
                                ],
                                [
                                  1002,
                                  1120
                                ],
                                [
                                  1002,
                                  1302
                                ],
                                [
                                  820,
                                  1302
                                ]
                              ],
                              "x": 820,
                              "y": 1120,
                              "width": 182,
                              "height": 182,
                              "page_width": 1190,
                              "page_height": 1684,
                              "raw_payload": "aHR0cHM6Ly9hZ3Vhc2RlbG5vcnRlLmNvbS9mYWN0dXJhLzk5ODgxMQ==",
                              "parsed_payload": "https://aguasdelnorte.com/factura/998811"
                            },
                            {
                              "type": "CODE_128",
                              "page_number": 1,
                              "position": [
                                [
                                  112,
                                  1480
                                ],
                                [
                                  560,
                                  1480
                                ],
                                [
                                  560,
                                  1540
                                ],
                                [
                                  112,
                                  1540
                                ]
                              ],
                              "x": 112,
                              "y": 1480,
                              "width": 448,
                              "height": 60,
                              "page_width": 1190,
                              "page_height": 1684,
                              "raw_payload": "MDA5OTg4MTEwMDA0Mg==",
                              "parsed_payload": "0099881100042"
                            }
                          ],
                          "warnings": []
                        }
                      ],
                      "document_ai_documents": [
                        {
                          "status": "Approved",
                          "node_id": "feature_document_ai_1",
                          "items": [
                            {
                              "uuid": "c1a2b3c4-d5e6-7f80-9a1b-2c3d4e5f6071",
                              "node_id": "feature_document_ai_1",
                              "document_key": "proof_of_funds",
                              "original_filename": "bank_statement.pdf",
                              "file_size": 184320,
                              "file_url": "https://<media-host>/document_ai/proof_of_funds.pdf",
                              "status": "Approved",
                              "extracted_data": {
                                "account_holder": "John Doe",
                                "balance": 15230.55,
                                "currency": "EUR",
                                "statement_date": "2026-05-31"
                              },
                              "detected_codes": [
                                {
                                  "type": "QR_CODE",
                                  "page_number": 2,
                                  "position": [
                                    [
                                      124,
                                      86
                                    ],
                                    [
                                      306,
                                      86
                                    ],
                                    [
                                      306,
                                      268
                                    ],
                                    [
                                      124,
                                      268
                                    ]
                                  ],
                                  "x": 124,
                                  "y": 86,
                                  "width": 182,
                                  "height": 182,
                                  "page_width": 1190,
                                  "page_height": 1684,
                                  "raw_payload": "SU5WLTIwMjYtMDA0Mg==",
                                  "parsed_payload": "INV-2026-0042"
                                }
                              ],
                              "fields": [
                                {
                                  "key": "account_holder",
                                  "name": "Account holder",
                                  "instruction": "Extract the full name of the account holder.",
                                  "type": "text",
                                  "required": true
                                },
                                {
                                  "key": "balance",
                                  "name": "Closing balance",
                                  "instruction": "Extract the closing balance amount.",
                                  "type": "number",
                                  "required": true
                                }
                              ],
                              "document_metadata": {
                                "is_tampered": false
                              },
                              "cross_check_result": null,
                              "created_at": "2026-06-01T12:34:56Z"
                            }
                          ],
                          "warnings": []
                        }
                      ],
                      "questionnaire_responses": [
                        {
                          "node_id": "feature_questionnaire_1",
                          "questionnaire_id": "9f7485e0-b00b-4d56-9d3e-7859b68d1213",
                          "title": "Source of Funds",
                          "description": "Reply to this questionnaire to help us understand the source of funds.",
                          "languages": [
                            "en"
                          ],
                          "default_language": "en",
                          "is_active": true,
                          "is_simple_questionnaire": true,
                          "questionnaire_group_id": "2b6a9d40-13a8-4b1e-9a6c-3f1d2e4b5a60",
                          "version": 1,
                          "published_at": "2025-11-02T09:14:55.000000Z",
                          "sections": [
                            {
                              "title": null,
                              "description": null,
                              "items": [
                                {
                                  "uuid": "618636d9-7d5c-41ce-b8d0-1ab2a4be20db",
                                  "value": "question_1",
                                  "element_type": "DROPDOWN",
                                  "is_required": true,
                                  "title": "What is your primary source of funds?",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": [
                                    {
                                      "label": "Salary",
                                      "value": "salary"
                                    },
                                    {
                                      "label": "Business Income",
                                      "value": "business_income"
                                    },
                                    {
                                      "label": "Savings",
                                      "value": "savings"
                                    },
                                    {
                                      "label": "Investments",
                                      "value": "investments"
                                    },
                                    {
                                      "label": "Sale of Asset",
                                      "value": "sale_of_asset"
                                    },
                                    {
                                      "label": "Inheritance/Gift",
                                      "value": "inheritance_gift"
                                    },
                                    {
                                      "label": "Pension",
                                      "value": "pension"
                                    },
                                    {
                                      "label": "Crypto Proceeds",
                                      "value": "crypto_proceeds"
                                    },
                                    {
                                      "label": "Other",
                                      "value": "other",
                                      "requires_text_input": true
                                    }
                                  ],
                                  "max_files": 1,
                                  "answer": {
                                    "value": "salary"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "2d16b527-72be-42e0-8e96-b164b818386c",
                                  "value": "question_2",
                                  "element_type": "LONG_TEXT",
                                  "is_required": true,
                                  "title": "Provide details of the primary source.",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": null,
                                  "max_files": 1,
                                  "answer": {
                                    "value": "Test answer"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "a9239b7c-fbfb-4ea7-b7e4-c835cd4016e0",
                                  "value": "question_3",
                                  "element_type": "DROPDOWN",
                                  "is_required": true,
                                  "title": "What is your annual income range (pre-tax)?",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": [
                                    {
                                      "label": "Less than $25,000",
                                      "value": "<25k"
                                    },
                                    {
                                      "label": "$25,000 - $50,000",
                                      "value": "25k-50k"
                                    },
                                    {
                                      "label": "$50,001 - $100,000",
                                      "value": "50k-100k"
                                    },
                                    {
                                      "label": "$100,001 - $250,000",
                                      "value": "100k-250k"
                                    },
                                    {
                                      "label": "More than $250,000",
                                      "value": ">250k"
                                    }
                                  ],
                                  "max_files": 1,
                                  "answer": {
                                    "value": "<25k"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "93dede62-6d0c-4a7f-934d-42175eb94011",
                                  "value": "question_4",
                                  "element_type": "DROPDOWN",
                                  "is_required": true,
                                  "title": "What is your approximate net worth (range)?",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": [
                                    {
                                      "label": "Less than $50,000",
                                      "value": "<50k"
                                    },
                                    {
                                      "label": "$50,000 - $250,000",
                                      "value": "50k-250k"
                                    },
                                    {
                                      "label": "$250,001 - $1,000,000",
                                      "value": "250k-1m"
                                    },
                                    {
                                      "label": "$1,000,001 - $5,000,000",
                                      "value": "1m-5m"
                                    },
                                    {
                                      "label": "More than $5,000,000",
                                      "value": ">5m"
                                    }
                                  ],
                                  "max_files": 1,
                                  "answer": {
                                    "value": "<50k"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "2af60d6f-6961-4692-9ee7-24b3033610a6",
                                  "value": "question_5",
                                  "element_type": "LONG_TEXT",
                                  "is_required": true,
                                  "title": "For your initial deposit/funding, indicate the exact source and amount.",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": null,
                                  "max_files": 1,
                                  "answer": {
                                    "value": "Test answer"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "0ad9d1aa-736f-46cf-947b-9e1241b53e40",
                                  "value": "question_6",
                                  "element_type": "LONG_TEXT",
                                  "is_required": true,
                                  "title": "Breakdown of sources by percentage.",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": null,
                                  "max_files": 1,
                                  "answer": {
                                    "value": "Test answer"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "1bf8a2a3-14ee-48a8-bb3d-175481aae4aa",
                                  "value": "question_7",
                                  "element_type": "SINGLE_CHOICE",
                                  "is_required": true,
                                  "title": "Will any funds originate from third parties? If yes, please provide details.",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": [
                                    {
                                      "label": "Yes",
                                      "value": "yes",
                                      "requires_text_input": true
                                    },
                                    {
                                      "label": "No",
                                      "value": "no"
                                    }
                                  ],
                                  "max_files": 1,
                                  "answer": {
                                    "text": "Additional details",
                                    "value": "yes"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "e18d4dd3-b7bf-4883-ba18-d6046adbe313",
                                  "value": "question_8",
                                  "element_type": "SINGLE_CHOICE",
                                  "is_required": true,
                                  "title": "Do you hold or plan to use virtual assets (e.g., crypto) to fund this account? If yes, please provide details.",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": [
                                    {
                                      "label": "Yes",
                                      "value": "yes",
                                      "requires_text_input": true
                                    },
                                    {
                                      "label": "No",
                                      "value": "no"
                                    }
                                  ],
                                  "max_files": 1,
                                  "answer": {
                                    "text": "Additional details",
                                    "value": "yes"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "a90a073d-e098-404c-bbce-5130d8b12a13",
                                  "value": "question_9",
                                  "element_type": "FILE_UPLOAD",
                                  "is_required": true,
                                  "title": "Upload a proof of funds document",
                                  "description": "You can upload your three (3) most recent bank statements, three (3) most recent payslips, your most recent tax return, proof of company ownership, trading exchange statement, sale of property, or proof of inheritance.",
                                  "placeholder": null,
                                  "choices": null,
                                  "max_files": 3,
                                  "answer": {
                                    "files": [
                                      "/media/ocr/",
                                      "/media/ocr/"
                                    ]
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                },
                                {
                                  "uuid": "9503b486-7cb8-4c3b-a97d-4b64926a5a47",
                                  "value": "question_10",
                                  "element_type": "LONG_TEXT",
                                  "is_required": false,
                                  "title": "Would you like to add any details to help us expedite our review of the documents you submitted?",
                                  "description": null,
                                  "placeholder": null,
                                  "choices": null,
                                  "max_files": 1,
                                  "answer": {
                                    "value": "Test answer"
                                  },
                                  "required_if": null,
                                  "repeatable_config": null
                                }
                              ]
                            }
                          ],
                          "status": "Approved"
                        }
                      ],
                      "aml_screenings": [
                        {
                          "node_id": "feature_aml_1",
                          "status": "In Review",
                          "total_hits": 1,
                          "entity_type": "person",
                          "hits": [
                            {
                              "id": "cPtTGRKkyddAcAC4xgsLCm",
                              "url": "https://news.example.org/articles/sample",
                              "match": false,
                              "score": 0.73,
                              "target": null,
                              "caption": "Javier Ejemplo Modelo",
                              "datasets": [
                                "PEP"
                              ],
                              "features": null,
                              "rca_name": "",
                              "last_seen": "2025-06-13T00:00:00",
                              "risk_view": {
                                "crimes": {
                                  "score": 0,
                                  "weightage": 20,
                                  "risk_level": "Low",
                                  "risk_scores": {}
                                },
                                "countries": {
                                  "score": 0,
                                  "weightage": 30,
                                  "risk_level": "Low",
                                  "risk_scores": {}
                                },
                                "categories": {
                                  "score": 100,
                                  "weightage": 50,
                                  "risk_level": "High",
                                  "risk_scores": {
                                    "PEP": 100
                                  }
                                },
                                "custom_list": {}
                              },
                              "first_seen": "2025-01-18T00:00:00",
                              "properties": {
                                "name": [
                                  "Javier Ejemplo Modelo"
                                ],
                                "alias": [
                                  "Javier Ejemplo Modelo",
                                  "David Azagra"
                                ],
                                "notes": [
                                  "Spanish orchestra conductor"
                                ],
                                "title": null,
                                "gender": [
                                  "male"
                                ],
                                "height": null,
                                "topics": null,
                                "weight": null,
                                "address": null,
                                "country": null,
                                "website": null,
                                "eyeColor": null,
                                "keywords": null,
                                "lastName": [
                                  "Ejemplo",
                                  "Modelo"
                                ],
                                "position": null,
                                "religion": null,
                                "birthDate": [
                                  "1974"
                                ],
                                "education": [
                                  "Tokyo Arts and Space (2012-2012)",
                                  "Saint Petersburg Conservatory (-2010)",
                                  "Comillas Pontifical University"
                                ],
                                "ethnicity": null,
                                "firstName": [
                                  "David"
                                ],
                                "hairColor": null,
                                "weakAlias": null,
                                "birthPlace": [
                                  "Madrid"
                                ],
                                "modifiedAt": null,
                                "wikidataId": null,
                                "citizenship": null,
                                "nationality": null
                              },
                              "match_score": 98,
                              "risk_score": 73,
                              "review_status": "Unreviewed",
                              "score_breakdown": {
                                "name_score": 95,
                                "name_weight": 60,
                                "name_weight_normalized": 70.59,
                                "name_contribution": 67.06,
                                "dob_score": 100,
                                "dob_weight": 25,
                                "dob_weight_normalized": 29.41,
                                "dob_contribution": 29.41,
                                "country_score": 0,
                                "country_weight": 15,
                                "country_weight_normalized": 0,
                                "country_contribution": 0,
                                "document_number_match_type": "NEUTRAL",
                                "document_number_effect": "No document number provided for screening",
                                "total_score": 98
                              },
                              "pep_matches": [
                                {
                                  "aliases": [
                                    "Javier Ejemplo Modelo",
                                    "David Azagra"
                                  ],
                                  "education": [
                                    "Tokyo Arts and Space (2012-2012)",
                                    "Saint Petersburg Conservatory (-2010)",
                                    "Comillas Pontifical University"
                                  ],
                                  "list_name": "Wikidata",
                                  "publisher": "Wikidata",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "description": "Wikidata is the structured data project of the Wikipedia community, providing fact-based information edited by humans and machines",
                                  "matched_name": "Javier Ejemplo Modelo",
                                  "pep_position": "",
                                  "date_of_birth": "1974",
                                  "other_sources": [],
                                  "place_of_birth": "Madrid"
                                }
                              ],
                              "linked_entities": [
                                {
                                  "name": [
                                    "Antonio Ejemplo"
                                  ],
                                  "active": [],
                                  "status": [],
                                  "details": [],
                                  "relation": []
                                }
                              ],
                              "warning_matches": [],
                              "sanction_matches": [],
                              "adverse_media_details": {
                                "sentiment": "Moderately Negative",
                                "entity_type": "person",
                                "sentiment_score": -2,
                                "adverse_keywords": {
                                  "fraud": 3,
                                  "juicio": 1,
                                  "delitos": 2,
                                  "imputado": 1,
                                  "impunidad": 1,
                                  "corruption": 2,
                                  "favoritism": 2,
                                  "privilegio": 1,
                                  "corrupción": 1,
                                  "persecution": 2,
                                  "desconfianza": 1,
                                  "desprestigio": 1,
                                  "fraude de ley": 2,
                                  "manipulación": 1,
                                  "investigación": 3,
                                  "prevaricación": 8,
                                  "trato de favor": 1,
                                  "irregularidades": 2,
                                  "crisis de confianza": 1,
                                  "tráfico de influencias": 8
                                }
                              },
                              "adverse_media_matches": [
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo is implicated in legal violations related to favoritism and influence trafficking, leading to a negative portrayal in the article.",
                                  "headline": "La Diputación de Villaejemplo consolida la plaza a medida para el ex asesor de Moncloa amigo del \"hermanito\" de Ejemplo",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "fraud",
                                    "prevaricación",
                                    "tráfico de influencias",
                                    "irregularidades",
                                    "imputado"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-10T20:46:38"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo is implicated in legal issues regarding favoritism and corruption, leading to a negative portrayal in the article.",
                                  "headline": "La Diputación de Villaejemplo consolida la plaza a medida para el ex asesor de Moncloa amigo del \"hermanito\" de Ejemplo",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "fraud",
                                    "prevaricación",
                                    "tráfico de influencias",
                                    "irregularidades",
                                    "trato de favor"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-10T20:46:38"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo Modelo is mentioned in connection with Carlos Ficticio's corruption case, indicating his involvement in alleged influence peddling.",
                                  "headline": "España, paraíso del aforado",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "prevaricación",
                                    "tráfico de influencias",
                                    "corrupción",
                                    "impunidad",
                                    "privilegio",
                                    "desconfianza",
                                    "manipulación",
                                    "fraude de ley"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-10T05:05:34"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo Modelo is implicated in the same investigation as Ficticio, which raises questions about his conduct and political ethics.",
                                  "headline": "Aforamientos: esa figura incómoda",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "prevaricación",
                                    "tráfico de influencias",
                                    "investigación",
                                    "juicio",
                                    "fraude de ley",
                                    "desprestigio",
                                    "crisis de confianza",
                                    "delitos"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-08T06:01:00"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo is implicated in a legal investigation regarding irregularities in his hiring, which raises serious concerns about his conduct.",
                                  "headline": "La jueza del 'caso Javier Ejemplo' denuncia un «fraude de ley» en el aforamiento de Ficticio (Partido Ejemplo)",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "fraud",
                                    "irregularities",
                                    "prevaricación",
                                    "tráfico de influencias"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-09T10:19:10"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo Modelo is mentioned in connection with legal allegations of corruption, contributing to a negative perception.",
                                  "headline": "'Caso aforamiento': la letrada mayor de la Asamblea certifica a la juez que Ficticio es diputado desde antes de prometer su cargo en el Pleno",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "prevaricación",
                                    "tráfico de influencias"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-09T08:08:30"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo Modelo is implicated in the same investigation as Ficticio, raising concerns about political corruption and influence.",
                                  "headline": "Aforamientos: esa figura incómoda",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "prevaricación",
                                    "tráfico de influencias",
                                    "investigación"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-08T06:01:00"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo Modelo is implicated in the same investigation as Ficticio, which raises concerns about political misconduct.",
                                  "headline": "Aforamientos: esa figura incómoda",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "prevaricación",
                                    "tráfico de influencias",
                                    "investigación",
                                    "delitos"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-08T06:00:59"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo is implicated in a case of favoritism and corruption, which casts a negative light on his character and actions.",
                                  "headline": "'Caso Javier Ejemplo': las asociaciones judiciales salen en defensa de la juez Luisa Inventada ante las \"presiones externas\" que sufre",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "favoritism",
                                    "corruption",
                                    "persecution"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-06T10:08:15"
                                },
                                {
                                  "country": "spain",
                                  "summary": "Javier Ejemplo is implicated in a case of alleged favoritism and corruption, which casts a negative light on his character and actions.",
                                  "headline": "'Caso Javier Ejemplo': las asociaciones judiciales salen en defensa de la juez Luisa Inventada ante las \"presiones externas\" que sufre",
                                  "sentiment": "moderately negative",
                                  "thumbnail": "https://news.example.org/articles/sample",
                                  "source_url": "https://news.example.org/articles/sample",
                                  "author_name": null,
                                  "other_sources": [],
                                  "adverse_keywords": [
                                    "favoritism",
                                    "corruption",
                                    "persecution"
                                  ],
                                  "sentiment_score": -2,
                                  "publication_date": "2025-06-06T08:08:15"
                                }
                              ],
                              "additional_information": {}
                            }
                          ],
                          "score": 80,
                          "screened_data": {
                            "full_name": "Javier Ejemplo Modelo",
                            "nationality": "ES",
                            "date_of_birth": "1974-01-01",
                            "document_number": null
                          },
                          "is_ongoing_monitoring_enabled": true,
                          "next_ongoing_monitoring_bill_date": "2026-07-24",
                          "last_ongoing_screening_at": "2026-09-12T04:03:11Z",
                          "last_ongoing_screening_datasets_updated_at": "2026-09-11T06:00:00Z",
                          "warnings": [
                            {
                              "feature": "AML",
                              "risk": "POSSIBLE_MATCH_FOUND",
                              "additional_data": null,
                              "log_type": "warning",
                              "short_description": "Possible match found in AML screening",
                              "long_description": "The Anti-Money Laundering (AML) screening process identified potential matches with watchlists or high-risk databases, requiring further review.",
                              "node_id": "feature_aml_1"
                            }
                          ]
                        }
                      ],
                      "ip_analyses": [
                        {
                          "node_id": "feature_ip_1",
                          "status": "Approved",
                          "device_brand": "Apple",
                          "device_model": "iPhone",
                          "browser_family": "Mobile Safari",
                          "os_family": "iOS",
                          "platform": "mobile",
                          "device_fingerprint": "didit-fp-a1b2c3d4e5f6g7h8",
                          "ip_country": "Spain",
                          "ip_country_code": "ES",
                          "ip_state": "Barcelona",
                          "ip_city": "Barcelona",
                          "latitude": 41.4022,
                          "longitude": 2.1407,
                          "ip_address": "83.50.226.71",
                          "isp": null,
                          "organization": null,
                          "is_vpn_or_tor": false,
                          "is_data_center": false,
                          "time_zone": "Europe/Madrid",
                          "time_zone_offset": "+0100",
                          "ip": {
                            "location": {
                              "latitude": 40.2206327,
                              "longitude": 1.5770097
                            },
                            "distance_from_id_document": 23.4,
                            "distance_from_poa_document": 12.3
                          },
                          "id_document": {
                            "location": {
                              "latitude": 41.2706327,
                              "longitude": 1.9770097
                            },
                            "distance_from_ip": 23.4,
                            "distance_from_poa_document": 18.7
                          },
                          "poa_document": {
                            "location": {
                              "latitude": 41.2706327,
                              "longitude": 1.9770097
                            },
                            "distance_from_ip": 12.3,
                            "distance_from_id_document": 18.7
                          },
                          "warnings": [],
                          "matches": [
                            {
                              "session_id": "99999999-8888-7777-6666-555555555555",
                              "session_number": 41205,
                              "vendor_data": "22222222-2222-2222-2222-222222222222",
                              "verification_date": "2024-07-20T10:15:30Z",
                              "match_type": "ip_address",
                              "match_source": "ip_address",
                              "matched_value": "83.50.226.71",
                              "status": "Approved",
                              "is_blocklisted": false,
                              "api_service": null,
                              "source": "session",
                              "device_info": {
                                "device_brand": "Apple",
                                "device_model": "iPhone",
                                "browser_family": "Mobile Safari",
                                "os_family": "iOS",
                                "platform": "mobile",
                                "device_fingerprint": "didit-fp-f9e8d7c6b5a40312"
                              },
                              "location_info": {
                                "ip_address": "83.50.226.71",
                                "ip_country": "Spain",
                                "ip_country_code": "ES",
                                "ip_state": "Barcelona",
                                "ip_city": "Barcelona",
                                "is_vpn_or_tor": false,
                                "is_data_center": false
                              },
                              "confidence": 0.0,
                              "match_mode": "co_occurrence"
                            },
                            {
                              "session_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
                              "session_number": 42830,
                              "vendor_data": "33333333-3333-3333-3333-333333333333",
                              "verification_date": "2024-06-30T18:22:05Z",
                              "match_type": "device_fingerprint",
                              "match_source": "recovered_high",
                              "matched_value": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
                              "status": "Declined",
                              "is_blocklisted": false,
                              "api_service": null,
                              "source": "session",
                              "device_info": {
                                "device_brand": "Samsung",
                                "device_model": "SM-G991B",
                                "browser_family": "Chrome Mobile",
                                "os_family": "Android",
                                "platform": "mobile",
                                "device_fingerprint": null
                              },
                              "location_info": {
                                "ip_address": "83.50.231.18",
                                "ip_country": "Spain",
                                "ip_country_code": "ES",
                                "ip_state": "Madrid",
                                "ip_city": "Madrid",
                                "is_vpn_or_tor": false,
                                "is_data_center": false
                              },
                              "confidence": 1.0,
                              "match_mode": "deterministic",
                              "recovery_similarity": 0.9874,
                              "tls_ja4_corroborated": true,
                              "recovery_gate_reason": "hardware_root_match"
                            }
                          ]
                        }
                      ],
                      "database_validations": [
                        {
                          "node_id": "feature_db_validation_1",
                          "issuing_state": "BRA",
                          "validation_type": "one_by_one",
                          "screened_data": {
                            "last_name": "De Lima",
                            "first_name": "Fernando",
                            "tax_number": "01234567890",
                            "date_of_birth": "1980-01-01",
                            "document_type": "ID",
                            "expiration_date": "2030-01-01"
                          },
                          "validations": [
                            {
                              "service_id": "bra_cpf",
                              "service_name": "Brazil - CPF status check",
                              "outcome_code": "MATCH",
                              "validation": {
                                "full_name": "full_match",
                                "date_of_birth": "full_match",
                                "identification_number": "full_match"
                              },
                              "source_data": {
                                "identification_number": "01234567890",
                                "first_name": "FERNANDO",
                                "last_name": "DE LIMA",
                                "date_of_birth": "1980-01-01",
                                "gender": "M",
                                "nationality": "BRA"
                              }
                            }
                          ],
                          "match_type": "full_match",
                          "status": "Approved",
                          "warnings": []
                        }
                      ],
                      "reviews": [
                        {
                          "user": "compliance@example.com",
                          "new_status": "Declined",
                          "comment": "Possible match found in AML screening",
                          "created_at": "2024-07-18T13:29:00.366811Z"
                        }
                      ],
                      "created_at": "2024-07-24T08:54:25.443172Z",
                      "expires_at": "2025-07-24T08:54:25.443172Z"
                    }
                  },
                  "BusinessExample": {
                    "summary": "Business (KYB) session example",
                    "description": "A `session_kind = \"business\"` decision: KYB sessions replace the KYC feature arrays with `registry_checks`, `document_verifications` and `key_people_checks`, while sharing `aml_screenings`, `phone_verifications`, `email_verifications`, `questionnaire_responses`, `ip_analyses`, `reviews` and the session envelope.",
                    "value": {
                      "session_id": "66666666-7777-8888-9999-000000000000",
                      "session_kind": "business",
                      "session_number": 31415,
                      "session_url": "https://verify.didit.me/session/business123",
                      "status": "In Review",
                      "environment": "live",
                      "workflow_id": "abababab-cdcd-efef-0101-232323232323",
                      "features": [
                        "KYB_REGISTRY",
                        "KYB_DOCUMENTS",
                        "KYB_KEY_PEOPLE"
                      ],
                      "vendor_data": "merchant-001234",
                      "metadata": null,
                      "callback": "https://example.com/verification/callback",
                      "registry_checks": [
                        {
                          "status": "Approved",
                          "node_id": "feature_kyb_registry_1",
                          "data_resolved": true,
                          "company": {
                            "uuid": "dddd4444-eeee-5555-ffff-666677778888",
                            "node_id": "feature_kyb_registry_1",
                            "status": "Approved",
                            "registry_status": "active",
                            "data_resolved": true,
                            "company_name": "ACME HOLDINGS LTD",
                            "registration_number": "12345678",
                            "country_code": "GB",
                            "region": null,
                            "company_type": "Private Limited Company",
                            "incorporation_date": "2015-03-12",
                            "registered_address": "1 Example Street, London, EC1A 1AA",
                            "tax_number": null,
                            "risk_level": null,
                            "verification_status": null,
                            "is_from_registry": true,
                            "fetch_status": "resolved",
                            "alternative_names": null,
                            "nature_of_business": "62012 - Business and domestic software development",
                            "registered_capital": "100 GBP",
                            "registered_capital_amount": "100.00",
                            "registered_capital_currency": "GBP",
                            "website": null,
                            "email": null,
                            "phone": null,
                            "legal_entity_identifier": null,
                            "location_of_registration": "England and Wales",
                            "financial_summary": null,
                            "officers": [
                              {
                                "uuid": "aaaa1111-bbbb-2222-cccc-333344445555",
                                "name": "Jane Smith",
                                "designation": "Director",
                                "role": "director",
                                "nationality": "British",
                                "is_active": true,
                                "kyc_status": "Approved",
                                "kyc_session_url": "https://verify.didit.me/session/abc123def456"
                              }
                            ],
                            "beneficial_owners": [
                              {
                                "uuid": "bbbb2222-cccc-3333-dddd-444455556666",
                                "name": "John Doe",
                                "first_name": "John",
                                "last_name": "Doe",
                                "entity_type": "person",
                                "roles": [
                                  "ubo",
                                  "shareholder"
                                ],
                                "ownership_min_shares": "50",
                                "ownership_max_shares": "75",
                                "is_active": true,
                                "kyc_status": "Pending",
                                "kyc_session_url": "https://verify.didit.me/session/def456ghi789",
                                "effective_ownership_percent": 75.0
                              }
                            ],
                            "addresses": [
                              {
                                "type": "registered",
                                "address": "1 Example Street, London, EC1A 1AA",
                                "country": "GB"
                              }
                            ],
                            "industries": [
                              {
                                "code": "62012",
                                "description": "Business and domestic software development"
                              }
                            ],
                            "accounts": null,
                            "registry_data": {
                              "addresses_detail": [
                                {
                                  "type": "registered",
                                  "address": "1 Example Street, London, EC1A 1AA",
                                  "country": "GB"
                                }
                              ],
                              "industries": [
                                {
                                  "code": "62012",
                                  "description": "Business and domestic software development"
                                }
                              ]
                            },
                            "user_provided_data": {
                              "company_name": "ACME HOLDINGS",
                              "registration_number": "12345678"
                            },
                            "confirmed_by_user_at": "2026-06-10T12:01:30.000000Z",
                            "last_console_edit_at": null,
                            "is_editable": false
                          },
                          "ownership_structure": {
                            "nodes": [
                              {
                                "id": "company",
                                "name": "ACME HOLDINGS LTD",
                                "type": "company"
                              },
                              {
                                "id": "ubo-1",
                                "name": "John Doe",
                                "type": "person",
                                "ownership_percent": 75.0
                              }
                            ]
                          },
                          "warnings": []
                        }
                      ],
                      "aml_screenings": null,
                      "document_verifications": [
                        {
                          "status": "In Review",
                          "node_id": "feature_kyb_documents_1",
                          "items": [
                            {
                              "uuid": "eeee5555-ffff-6666-0000-777788889999",
                              "document_type": "LEGAL_PRESENCE",
                              "document_subtype": "CERTIFICATE_OF_INCORPORATION",
                              "document_group": "LEGAL_PRESENCE",
                              "file_url": "https://<media-host>/kyb/certificate-of-incorporation.pdf",
                              "original_filename": "certificate_of_incorporation.pdf",
                              "file_size": 482133,
                              "status": "Approved",
                              "created_at": "2026-06-10T12:03:11.000000Z",
                              "cross_check_result": {
                                "critical": {
                                  "company_name": {
                                    "document": "ACME HOLDINGS LTD",
                                    "registry": "ACME HOLDINGS LTD",
                                    "score": 1.0,
                                    "match": true
                                  },
                                  "registration_number": {
                                    "document": "12345678",
                                    "registry": "12345678",
                                    "match": true
                                  }
                                },
                                "non_critical": {},
                                "people": {}
                              },
                              "document_metadata": {
                                "file_size": 482133,
                                "content_type": "application/pdf",
                                "creation_date": "2015-03-12T09:00:00",
                                "modified_date": "2015-03-12T09:00:00",
                                "creator": null,
                                "producer": null,
                                "software": null,
                                "encryption": null,
                                "is_signed": true,
                                "is_tampered": false,
                                "signature_info": null,
                                "exif_original_date": null,
                                "exif_digitized_date": null,
                                "processed_by_known_editor": false,
                                "has_different_creation_mod_date": false,
                                "overlay_manipulation": null
                              },
                              "description": null,
                              "is_requested": false,
                              "ocr_data": {
                                "company_name": "ACME HOLDINGS LTD",
                                "registration_number": "12345678",
                                "incorporation_date": "2015-03-12"
                              },
                              "is_console_upload": false,
                              "is_confirmed": true
                            },
                            {
                              "uuid": "ffff6666-0000-7777-1111-888899990000",
                              "document_type": "OWNERSHIP_STRUCTURE",
                              "document_subtype": null,
                              "document_group": "OWNERSHIP_STRUCTURE",
                              "file_url": null,
                              "original_filename": null,
                              "file_size": null,
                              "status": "Not Finished",
                              "created_at": "2026-06-10T15:40:02.000000Z",
                              "cross_check_result": null,
                              "document_metadata": null,
                              "description": "Please upload an up-to-date shareholder registry",
                              "is_requested": true,
                              "ocr_data": null,
                              "is_console_upload": false,
                              "is_confirmed": true
                            }
                          ],
                          "groups": {
                            "LEGAL_PRESENCE": {
                              "total": 1,
                              "approved": 1,
                              "pending": 0,
                              "declined": 0,
                              "in_review": 0,
                              "other": 0,
                              "missing": 0
                            },
                            "OWNERSHIP_STRUCTURE": {
                              "total": 1,
                              "approved": 0,
                              "pending": 0,
                              "declined": 0,
                              "in_review": 0,
                              "other": 0,
                              "missing": 1
                            }
                          },
                          "required_groups": [
                            "LEGAL_PRESENCE",
                            "OWNERSHIP_STRUCTURE"
                          ],
                          "warnings": []
                        }
                      ],
                      "key_people_checks": [
                        {
                          "status": "In Review",
                          "node_id": "feature_kyb_key_people_1",
                          "registry": {
                            "officers": [
                              {
                                "uuid": "aaaa1111-bbbb-2222-cccc-333344445555",
                                "name": "Jane Smith",
                                "designation": "Director",
                                "role": "director",
                                "nationality": "British",
                                "appointment_date": "2015-03-12",
                                "termination_date": null,
                                "is_active": true,
                                "address": "1 Example Street, London, EC1A 1AA",
                                "aml_status": "Approved",
                                "kyc_status": "Approved",
                                "kyc_session_url": "https://verify.didit.me/session/abc123def456",
                                "kyc_session_id": "77777777-8888-9999-aaaa-bbbbbbbbbbbb",
                                "verification_workflow_type": "kyc",
                                "verification_workflow_id": "12121212-3434-5656-7878-909090909090",
                                "verification_workflow_label": "Key People KYC",
                                "verification_workflow_features": [
                                  {
                                    "feature": "ID_VERIFICATION",
                                    "status": "Approved"
                                  },
                                  {
                                    "feature": "LIVENESS",
                                    "status": "Approved"
                                  },
                                  {
                                    "feature": "AML",
                                    "status": "Approved"
                                  }
                                ],
                                "didit_internal_id": "99999999-0000-1111-2222-333333333333",
                                "kyc_document_type": "P",
                                "kyc_nationality": "GBR",
                                "kyc_liveness_passed": true,
                                "kyc_verified_at": "2026-06-10T14:22:31.123456Z",
                                "kyc_aml_categories": {
                                  "sanctions": "clear",
                                  "pep": "clear",
                                  "adverse_media": "clear",
                                  "warnings": "clear"
                                },
                                "kyc_notification_sent_at": "2026-06-09T09:00:00.000000Z"
                              }
                            ],
                            "beneficial_owners": [
                              {
                                "uuid": "bbbb2222-cccc-3333-dddd-444455556666",
                                "name": "John Doe",
                                "first_name": "John",
                                "last_name": "Doe",
                                "date_of_birth": "1980-05-04",
                                "country_of_birth": null,
                                "email": null,
                                "company_name": null,
                                "registration_number": null,
                                "entity_type": "person",
                                "nationality": "British",
                                "designation": null,
                                "roles": [
                                  "ubo",
                                  "shareholder"
                                ],
                                "ownership_min_shares": "50",
                                "ownership_max_shares": "75",
                                "is_active": true,
                                "aml_status": null,
                                "kyc_status": "In Progress",
                                "kyc_session_url": "https://verify.didit.me/session/def456ghi789",
                                "kyc_session_id": "88888888-9999-aaaa-bbbb-cccccccccccc",
                                "verification_workflow_type": "kyc",
                                "verification_workflow_id": "12121212-3434-5656-7878-909090909090",
                                "verification_workflow_label": "Key People KYC",
                                "verification_workflow_features": [
                                  {
                                    "feature": "ID_VERIFICATION",
                                    "status": "Not Finished"
                                  },
                                  {
                                    "feature": "LIVENESS",
                                    "status": "Not Finished"
                                  },
                                  {
                                    "feature": "AML",
                                    "status": "Not Finished"
                                  }
                                ],
                                "didit_internal_id": null,
                                "kyc_document_type": null,
                                "kyc_nationality": null,
                                "kyc_liveness_passed": null,
                                "kyc_verified_at": null,
                                "kyc_aml_categories": null,
                                "kyc_notification_sent_at": null,
                                "child_beneficial_owners": [],
                                "effective_ownership_percent": 75.0
                              }
                            ]
                          },
                          "submitted": {
                            "parties": [
                              {
                                "uuid": "cccc3333-dddd-4444-eeee-555566667777",
                                "entity_type": "person",
                                "source": "USER",
                                "name": "John Doe",
                                "first_name": "John",
                                "last_name": "Doe",
                                "company_name": null,
                                "registration_number": null,
                                "email": "john.doe@example.com",
                                "nationality": "GBR",
                                "phone_number": "+447700900123",
                                "date_of_birth": "1980-05-04",
                                "position": "Chief Executive Officer",
                                "custom_fields": {},
                                "is_active": true,
                                "is_skipped": false,
                                "requires_verification": true,
                                "roles": [
                                  {
                                    "role": "ubo",
                                    "ownership_percent": 75.0,
                                    "voting_percent": 75.0
                                  },
                                  {
                                    "role": "director",
                                    "ownership_percent": null,
                                    "voting_percent": null
                                  }
                                ],
                                "kyc_session_id": "88888888-9999-aaaa-bbbb-cccccccccccc",
                                "kyc_session_status": "In Progress",
                                "kyc_session_url": "https://verify.didit.me/session/def456ghi789",
                                "kyb_sub_session_id": null,
                                "kyb_sub_session_status": null,
                                "kyb_sub_session_url": null,
                                "verification_workflow_type": "kyc",
                                "verification_workflow_id": "12121212-3434-5656-7878-909090909090",
                                "verification_workflow_label": "Key People KYC",
                                "verification_workflow_features": [
                                  {
                                    "feature": "ID_VERIFICATION",
                                    "status": "Not Finished"
                                  },
                                  {
                                    "feature": "LIVENESS",
                                    "status": "Not Finished"
                                  },
                                  {
                                    "feature": "AML",
                                    "status": "Not Finished"
                                  }
                                ],
                                "didit_internal_id": null
                              }
                            ]
                          },
                          "ubo_kyc_summary": {
                            "total": 1,
                            "approved": 0,
                            "flagged": 0,
                            "pending": 1
                          },
                          "warnings": []
                        }
                      ],
                      "phone_verifications": null,
                      "email_verifications": null,
                      "questionnaire_responses": null,
                      "ip_analyses": null,
                      "reviews": [],
                      "contact_details": null,
                      "expected_details": {
                        "company_name": "Tesco PLC",
                        "registry_country": "GB",
                        "registration_number": "00445790"
                      },
                      "created_at": "2026-06-10T11:58:04.000000Z",
                      "expires_at": "2026-06-24T11:58:04.000000Z"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "The unique identifier of the session for which to retrieve verification results."
                    },
                    "session_kind": {
                      "type": "string",
                      "enum": [
                        "user",
                        "business"
                      ],
                      "description": "Discriminator indicating whether this is a User Verification (KYC) or Business Verification (KYB) session. When `user`, the KYC feature arrays (`id_verifications`, `nfc_verifications`, `liveness_checks`, `face_matches`, `poa_verifications`, `document_ai_documents`, `database_validations`, ...) apply and the business arrays are absent. When `business`, the payload instead carries `registry_checks`, `document_verifications`, `key_people_checks` plus the shared arrays (`aml_screenings`, `phone_verifications`, `email_verifications`, `ip_analyses`, `questionnaire_responses`). **Omitted when `include=events` is passed** — the events shape only exists for user sessions, so the discriminator is dropped from that variant."
                    },
                    "session_number": {
                      "type": "integer",
                      "description": "The number of the session.",
                      "nullable": true
                    },
                    "session_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "The URL of the session.",
                      "nullable": true
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "Not Started",
                        "In Progress",
                        "Awaiting User",
                        "In Review",
                        "Approved",
                        "Declined",
                        "Resubmitted",
                        "Expired",
                        "Kyc Expired",
                        "Abandoned"
                      ],
                      "description": "Overall lifecycle status of the session — the rolled-up workflow result. Terminal values are `Approved`, `Declined`, `In Review`, `Expired`, `Kyc Expired`, and `Abandoned`; `Not Started`, `In Progress`, `Awaiting User`, and `Resubmitted` indicate the session is still moving through the workflow."
                    },
                    "workflow_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Stable identifier of the workflow group that produced this session. Workflows are versioned — this value identifies the workflow itself, not the specific version.",
                      "nullable": true
                    },
                    "features": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "The feature of the session."
                      },
                      "description": "List of verification features configured for this session, as display names: `ID_VERIFICATION`, `NFC`, `LIVENESS`, `FACE_MATCH`, `POA`, `PHONE`, `EMAIL_VERIFICATION`, `AML`, `IP_ANALYSIS`, `DATABASE_VALIDATION`, `QUESTIONNAIRE`, `AGE_ESTIMATION`, `FACE_SEARCH` (Business Verification sessions use the KYB feature set: `KYB_REGISTRY`, `KYB_DOCUMENTS`, `KYB_KEY_PEOPLE`, `AML`, `PHONE`, `EMAIL_VERIFICATION`, `IP_ANALYSIS`, `QUESTIONNAIRE`). With `include=events` each entry becomes an object `{feature, node_id}` instead of a plain string, and the email feature is renamed: it appears as `EMAIL` in events mode instead of the `EMAIL_VERIFICATION` used here."
                    },
                    "vendor_data": {
                      "type": "string",
                      "description": "The vendor data of the session.",
                      "nullable": true
                    },
                    "metadata": {
                      "type": "object",
                      "description": "The metadata of the session.",
                      "nullable": true
                    },
                    "expected_details": {
                      "type": "object",
                      "description": "Expected details supplied at session creation — used for cross-validation against extracted data (KYC) or to pre-fill the company registry search (KYB). Echoes back exactly the keys that were provided; `null` when none were supplied. KYC sessions carry the person fields; Business (KYB) sessions carry `company_name`, `registry_country` and `registration_number`.",
                      "properties": {
                        "first_name": {
                          "type": "string",
                          "description": "User's first name. For example, `John`."
                        },
                        "last_name": {
                          "type": "string",
                          "description": "User's last name. For example, `Doe`."
                        },
                        "date_of_birth": {
                          "type": "string",
                          "format": "date",
                          "description": "User's date of birth with format: YYYY-MM-DD. For example, `1990-05-15`."
                        },
                        "gender": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "M",
                            "F"
                          ],
                          "default": null,
                          "description": "User's gender. Must be either 'M', 'F', or null."
                        },
                        "nationality": {
                          "type": "string",
                          "description": "ISO 3166-1 alpha-3 country code representing the applicant's country of origin. For example, `USA`."
                        },
                        "country": {
                          "type": "string",
                          "description": "ISO 3166-1 alpha-3 country code representing the country of the Proof of Address document, or the country of the applicant's ID document, which may differ from nationality. For example, `GBR`."
                        },
                        "address": {
                          "type": "string",
                          "description": "The address in a human readable format, including as much information as possible. For example, `123 Main St, San Francisco, CA 94105, USA`."
                        },
                        "identification_number": {
                          "type": "string",
                          "description": "The user's document number, personal number, or tax number. For example, `123456789`."
                        },
                        "ip_address": {
                          "type": "string",
                          "format": "ipv4",
                          "description": "Expected IP address for the session. If the actual IP address differs from this value, a warning will be logged. For example, `192.168.1.100`."
                        },
                        "expected_document_types": {
                          "type": "array",
                          "description": "Document types the ID verification step was restricted to at session creation. Empty/unset means no restriction. Codes: `P` (passport), `ID` (national ID), `DL` (driver's license), `RP` (residence permit), `HIC` (health insurance card), `TC` (tax card), `SSC` (social security card).",
                          "items": {
                            "type": "string",
                            "enum": [
                              "P",
                              "ID",
                              "DL",
                              "RP",
                              "HIC",
                              "TC",
                              "SSC"
                            ]
                          }
                        },
                        "id_country": {
                          "type": "string",
                          "nullable": true,
                          "description": "Expected ID-document issuing country (ISO 3166-1 alpha-3), when restricted at creation time.",
                          "example": "ESP"
                        },
                        "poa_country": {
                          "type": "string",
                          "nullable": true,
                          "description": "Expected Proof of Address document country (ISO 3166-1 alpha-3), when restricted at creation time.",
                          "example": "ESP"
                        },
                        "company_name": {
                          "type": "string",
                          "description": "Expected legal name of the business. Business (KYB) sessions only."
                        },
                        "registry_country": {
                          "type": "string",
                          "description": "Expected registry country as `XX` or `XX-YY` (ISO 3166-1 alpha-2, optionally with an ISO 3166-2 subdivision for state-level registries, e.g. `US-CA`). Business (KYB) sessions only."
                        },
                        "registration_number": {
                          "type": "string",
                          "description": "Expected company registration number. Business (KYB) sessions only."
                        }
                      },
                      "nullable": true
                    },
                    "contact_details": {
                      "type": "object",
                      "description": "Contact details supplied when the session was created (used for notification emails, prefilled phone/email verification, and communication language). `null` when neither an email nor a phone number was provided.",
                      "properties": {
                        "email": {
                          "type": "string",
                          "description": "Email address of the user (e.g., \"john.doe@example.com\") that will be used during the Email Verification step. If not provided, the user must provide it during the verification flow."
                        },
                        "email_lang": {
                          "type": "string",
                          "description": "Language code (ISO 639-1) for email notifications. Controls the language of all email communications (e.g., \"en\", \"es\", \"fr\")."
                        },
                        "send_notification_emails": {
                          "type": "boolean",
                          "default": false,
                          "description": "If true and an email is provided, Didit sends the initial \"Verify your identity\" email asynchronously when the User Verification (KYC) or Business Verification (KYB) session is created. Didit also sends verification status notifications for sessions requiring manual review to the provided email address."
                        },
                        "phone": {
                          "type": "string",
                          "nullable": true,
                          "description": "Phone number of the user in E.164 format if available (e.g., +14155552671). `null` when only an email was supplied at session creation. Note: This field returns the original phone number provided during session creation. If the number was invalid, it may not be in E.164 format."
                        }
                      },
                      "nullable": true
                    },
                    "callback": {
                      "type": "string",
                      "format": "uri",
                      "description": "The callback URL of the session.",
                      "nullable": true
                    },
                    "id_verifications": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of ID verification (OCR) reports** produced by ID-document steps in the workflow graph. Always a JSON array — read `id_verifications[0]` and iterate if your workflow can run more than one ID check (for example a primary check plus a step-up). `null` until at least one ID step has produced data. Each item is the full report, including `node_id`, feature-level `status`, extracted document fields, image URLs, quality scores, MRZ, address parsing, cross-session matches, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "description": "One ID verification report - the full report for a single ID Verification step. `verification_method` says which of the three methods produced it (document capture, non-doc lookup or wallet sign-in) and the method-specific evidence block is populated accordingly.",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Workflow graph node id of the OCR step that produced this report."
                          },
                          "verification_method": {
                            "type": "string",
                            "enum": [
                              "document",
                              "id_lookup",
                              "wallet"
                            ],
                            "description": "Which ID Verification method produced this report. `document` - the user photographed a physical ID (the default, and the value on every session created before the other methods existed). `id_lookup` - the user typed their national ID number and it was checked against a government register or another authoritative source for that country (`id_lookup.source` names which). `wallet` - the user signed in with a government or bank digital identity."
                          },
                          "assurance": {
                            "type": "string",
                            "enum": [
                              "documentary",
                              "data_match",
                              "cryptographic"
                            ],
                            "description": "Assurance tier derived from `verification_method`: `documentary` for a document that was captured and checked, `data_match` for details that matched a record held by the source queried, `cryptographic` for attributes an identity provider authenticated and signed."
                          },
                          "wallet_provider": {
                            "type": "string",
                            "nullable": true,
                            "description": "Catalog wallet id when `verification_method` is `wallet` (`mitid`, `bankid_se`, `itsme`, ...). `null` otherwise."
                          },
                          "fallback_from": {
                            "type": "object",
                            "nullable": true,
                            "description": "Why a non-document method ended the ID step. Set on the declined report when a lookup or a wallet sign-in failed and the country's fallback switch was `decline`. `null` otherwise.",
                            "properties": {
                              "method": {
                                "type": "string",
                                "enum": [
                                  "id_lookup",
                                  "wallet"
                                ],
                                "description": "The method that failed."
                              },
                              "reason": {
                                "type": "string",
                                "description": "The outcome that ended it, e.g. `no_match`, `provider_error`, `cancelled`, `timeout`."
                              },
                              "action": {
                                "type": "string",
                                "description": "The configured action that was taken, e.g. `decline`."
                              }
                            }
                          },
                          "id_lookup": {
                            "type": "object",
                            "nullable": true,
                            "description": "Registry evidence. Present only when `verification_method` is `id_lookup`; `null` otherwise.",
                            "properties": {
                              "source": {
                                "type": "string",
                                "description": "Customer-facing name of the source queried, e.g. `Department of Home Affairs` (a government register) or `UK credit bureau and financial services records` (not a government register). This is the only statement of provenance for the lookup; do not assume a government source."
                              },
                              "checked_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "When the register answered."
                              },
                              "attempts": {
                                "type": "integer",
                                "description": "1-based attempt number this report came from."
                              },
                              "max_attempts": {
                                "type": "integer",
                                "description": "Attempt budget configured for the country (1 to 5, default 1)."
                              },
                              "outcome": {
                                "type": "string",
                                "enum": [
                                  "match",
                                  "partial_match",
                                  "no_match",
                                  "provider_error",
                                  "format_rejected"
                                ],
                                "nullable": true,
                                "description": "What the register answered. Only `match`, `partial_match` and `no_match` count against the attempt budget and bill."
                              },
                              "comparison": {
                                "type": "array",
                                "description": "One row per comparable field the source answered on, plus one row per source error. Comparison rows use the normalised field names below rather than the country's request field keys, because several request fields (first and last name, or any of the identifier aliases) collapse into a single comparison. A source that failed appends a row with `field: \"provider\"` and `result: \"error\"`, so read `result` before treating a row as a field verdict.",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "field",
                                    "label",
                                    "provided",
                                    "record",
                                    "result"
                                  ],
                                  "properties": {
                                    "field": {
                                      "type": "string",
                                      "enum": [
                                        "identification_number",
                                        "full_name",
                                        "date_of_birth",
                                        "address",
                                        "provider"
                                      ],
                                      "description": "Normalised comparison field. `provider` is not a user field: it marks a source error row."
                                    },
                                    "label": {
                                      "type": "string",
                                      "description": "Display label for the row, e.g. `ID number`, `Full name`, `Provider`."
                                    },
                                    "provided": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "What the user typed. `null` on a `provider` error row."
                                    },
                                    "record": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "What the source held. On a `provider` error row this carries the error message instead."
                                    },
                                    "result": {
                                      "type": "string",
                                      "enum": [
                                        "match",
                                        "partial",
                                        "no_match",
                                        "error"
                                      ],
                                      "description": "Per-field comparison result. `error` appears only on a `provider` row and means that source did not answer; treat it as evidence about the query, never as a field mismatch."
                                    }
                                  }
                                }
                              },
                              "registry_portrait": {
                                "type": "string",
                                "format": "uri",
                                "nullable": true,
                                "description": "Short-lived presigned URL to the portrait the source returned. Only the four government registers that return one (South Africa, Nigeria, Argentina, Panama)."
                              },
                              "face_match_score": {
                                "type": "number",
                                "nullable": true,
                                "description": "Selfie against the registry portrait, 0-100. Only where the register returns a portrait."
                              }
                            }
                          },
                          "wallet_verification": {
                            "type": "object",
                            "nullable": true,
                            "description": "Credential evidence. Present only when `verification_method` is `wallet`; `null` otherwise.",
                            "properties": {
                              "provider": {
                                "type": "string",
                                "description": "Catalog wallet id, e.g. `mitid`."
                              },
                              "provider_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Wallet name as the end user knows it, e.g. `MitID`."
                              },
                              "issuing_authority": {
                                "type": "string",
                                "nullable": true,
                                "description": "The authority behind the wallet, e.g. `Danish Agency for Digital Government`."
                              },
                              "issuing_country": {
                                "type": "string",
                                "description": "ISO 3166-1 alpha-3 country the wallet was offered in."
                              },
                              "credential_type": {
                                "type": "string",
                                "nullable": true,
                                "description": "Credential the wallet presented, e.g. `person_identification`."
                              },
                              "level_of_assurance": {
                                "type": "string",
                                "enum": [
                                  "low",
                                  "substantial",
                                  "high"
                                ],
                                "nullable": true,
                                "description": "The level of assurance the wallet asserted. A sign-in that asserts less than the level requested fails instead of downgrading."
                              },
                              "verified_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "The wallet's authentication instant."
                              },
                              "signature_valid": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "Whether the signed assertion the wallet returned validated."
                              },
                              "attributes": {
                                "type": "object",
                                "additionalProperties": true,
                                "description": "The attributes the wallet shared, keyed as the wallet's catalog entry lists them."
                              },
                              "portrait": {
                                "type": "string",
                                "format": "uri",
                                "nullable": true,
                                "description": "Short-lived presigned URL to the portrait the wallet shared, where it shares one."
                              },
                              "face_match_score": {
                                "type": "number",
                                "nullable": true,
                                "description": "Selfie against the wallet portrait, 0-100, where the wallet shares one."
                              }
                            }
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Expired"
                            ],
                            "description": "Feature-level status of this ID verification step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`."
                          },
                          "document_type": {
                            "type": "string",
                            "description": "Type of identity document"
                          },
                          "document_subtype": {
                            "type": "string",
                            "nullable": true,
                            "description": "Accepted document subtype code from the workflow document settings, including the document region when applicable. Examples: `ID_CARD_GENERIC`, `QUEENSLAND_DRIVER_LICENSE_GENERIC`."
                          },
                          "document_number": {
                            "type": "string",
                            "description": "Document identification number"
                          },
                          "personal_number": {
                            "type": "string",
                            "description": "Personal identification number"
                          },
                          "portrait_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the portrait image"
                          },
                          "front_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the front document image"
                          },
                          "front_video": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the front document video"
                          },
                          "back_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the back document image"
                          },
                          "back_video": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the back document video"
                          },
                          "full_front_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the full front document image"
                          },
                          "full_back_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the full back document image"
                          },
                          "front_image_camera_front": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the front document image captured from the front-facing camera"
                          },
                          "back_image_camera_front": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the back document image captured from the front-facing camera"
                          },
                          "date_of_birth": {
                            "type": "string",
                            "format": "date",
                            "description": "Date of birth from document"
                          },
                          "age": {
                            "type": "integer",
                            "description": "Calculated age from date of birth"
                          },
                          "expiration_date": {
                            "type": "string",
                            "format": "date",
                            "description": "Document expiration date"
                          },
                          "date_of_issue": {
                            "type": "string",
                            "format": "date",
                            "description": "Document issue date"
                          },
                          "issuing_state": {
                            "type": "string",
                            "description": "ISO code of issuing state"
                          },
                          "issuing_state_name": {
                            "type": "string",
                            "description": "Full name of issuing state"
                          },
                          "first_name": {
                            "type": "string",
                            "description": "First name from document"
                          },
                          "last_name": {
                            "type": "string",
                            "description": "Last name from document"
                          },
                          "full_name": {
                            "type": "string",
                            "description": "Full name from document"
                          },
                          "gender": {
                            "type": "string",
                            "description": "Gender from document"
                          },
                          "address": {
                            "type": "string",
                            "description": "Raw address from document"
                          },
                          "formatted_address": {
                            "type": "string",
                            "description": "Formatted full address"
                          },
                          "place_of_birth": {
                            "type": "string",
                            "description": "Place of birth from document"
                          },
                          "marital_status": {
                            "type": "string",
                            "description": "Marital status from document"
                          },
                          "nationality": {
                            "type": "string",
                            "description": "ISO nationality code"
                          },
                          "extra_fields": {
                            "type": "object",
                            "description": "Additional document fields. Includes document-specific attributes (e.g. `dl_categories`, `blood_group`, `sponsor`, `employer`, `dl_class_code_b_from`, `dl_class_code_b_to`). Driver license class validity dates are returned as `dl_class_code_<class>_from` and `dl_class_code_<class>_to`, and per-class restriction/information codes (e.g. column 12 of UK licences) as `dl_class_code_<class>_notes`. When the document carries names, address, or place of birth in multiple scripts, this object also includes alternate-script versions of those fields. The workflow setting `preferred_characters` (`latin` or `non_latin`) controls which script populates the top-level fields (`first_name`, `last_name`, `full_name`, `address`, `place_of_birth`); the opposite script lands here as `first_name_non_latin` / `last_name_non_latin` / `full_name_non_latin` / `middle_name_non_latin` / `address_non_latin` / `place_of_birth_non_latin` (when `preferred_characters` is `latin`) or with a `_latin` suffix (when `preferred_characters` is `non_latin`). Keys appear only when the OCR actually extracts a real alternate-script value — a field whose alternate value is in the same script as the preferred set (for example, a Cyrillic-labelled field whose OCR value came back in Latin homoglyphs) is skipped. When `preferred_characters` is `latin` but the document only carries non-Latin text, Didit transliterates the extracted values and exposes `first_name_latin` / `last_name_latin` / etc. as a fallback.",
                            "additionalProperties": true,
                            "properties": {
                              "dl_categories": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "blood_group": {
                                "type": "string",
                                "nullable": true
                              },
                              "first_name_non_latin": {
                                "type": "string",
                                "description": "First name in the non-Latin script when `preferred_characters=latin` and a non-Latin version is present on the document (e.g. `Айна` for a Kyrgyz ID)."
                              },
                              "last_name_non_latin": {
                                "type": "string",
                                "description": "Surname in the non-Latin script when `preferred_characters=latin` and a non-Latin version is present on the document."
                              },
                              "middle_name_non_latin": {
                                "type": "string",
                                "description": "Middle name / patronymic in the non-Latin script when `preferred_characters=latin` and a non-Latin version is present on the document."
                              },
                              "full_name_non_latin": {
                                "type": "string",
                                "description": "Composed full name in the non-Latin script. Reconstructed from the individual components when both first and last names are available."
                              },
                              "address_non_latin": {
                                "type": "string",
                                "description": "Address in the non-Latin script when `preferred_characters=latin` and a non-Latin version is present on the document."
                              },
                              "place_of_birth_non_latin": {
                                "type": "string",
                                "description": "Place of birth in the non-Latin script when `preferred_characters=latin` and a non-Latin version is present on the document."
                              },
                              "first_name_latin": {
                                "type": "string",
                                "description": "First name in Latin script. Populated when `preferred_characters=non_latin` and a Latin version is present on the document, or — as a transliteration fallback — when `preferred_characters=latin` but the document only carries non-Latin text."
                              },
                              "last_name_latin": {
                                "type": "string",
                                "description": "Surname in Latin script. Same rules as `first_name_latin`."
                              },
                              "middle_name_latin": {
                                "type": "string",
                                "description": "Middle name / patronymic in Latin script. Same rules as `first_name_latin`."
                              },
                              "full_name_latin": {
                                "type": "string",
                                "description": "Composed full name in Latin script. Always reconstructed from the individual components when both first and last names are available."
                              },
                              "address_latin": {
                                "type": "string",
                                "description": "Address in Latin script. Same rules as `first_name_latin`."
                              },
                              "place_of_birth_latin": {
                                "type": "string",
                                "description": "Place of birth in Latin script. Same rules as `first_name_latin`."
                              }
                            }
                          },
                          "mrz": {
                            "type": "object",
                            "nullable": true,
                            "description": "Parsed Machine-Readable Zone (MRZ) fields extracted from the document. `null` if no MRZ was detected.",
                            "properties": {
                              "surname": {
                                "type": "string",
                                "example": "MARTINEZ<SANCHEZ"
                              },
                              "name": {
                                "type": "string",
                                "example": "ELENA"
                              },
                              "country": {
                                "type": "string",
                                "example": "ESP"
                              },
                              "nationality": {
                                "type": "string",
                                "example": "ESP"
                              },
                              "birth_date": {
                                "type": "string",
                                "example": "850315"
                              },
                              "expiry_date": {
                                "type": "string",
                                "example": "220821"
                              },
                              "sex": {
                                "type": "string",
                                "example": "F"
                              },
                              "document_type": {
                                "type": "string",
                                "example": "ID"
                              },
                              "document_number": {
                                "type": "string",
                                "example": "YZA123456"
                              },
                              "optional_data": {
                                "type": "string",
                                "example": "X9876543L"
                              },
                              "optional_data_2": {
                                "type": "string",
                                "example": ""
                              },
                              "birth_date_hash": {
                                "type": "string",
                                "example": "7"
                              },
                              "expiry_date_hash": {
                                "type": "string",
                                "example": "4"
                              },
                              "document_number_hash": {
                                "type": "string",
                                "example": "9"
                              },
                              "final_hash": {
                                "type": "string",
                                "example": "2"
                              },
                              "personal_number": {
                                "type": "string",
                                "example": "X9876543L"
                              },
                              "warnings": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "errors": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "mrz_type": {
                                "type": "string",
                                "example": "TD1"
                              },
                              "mrz_string": {
                                "type": "string",
                                "example": "IDESPMARTINEZ<SANCHEZ<<<<<<<<<<\nYZA123456<9ESP8503157F3208214<X9876543L<<<<<<<2\nMARTINEZ<SANCHEZ<<ELENA<<<<<<<<<<"
                              },
                              "mrz_key": {
                                "type": "string",
                                "example": "YZA123456985031573208214"
                              }
                            }
                          },
                          "parsed_address": {
                            "type": "object",
                            "description": "Structured address details",
                            "properties": {
                              "city": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "region": {
                                "type": "string"
                              },
                              "country": {
                                "type": "string",
                                "description": "Two-letter country code"
                              },
                              "category": {
                                "type": "string",
                                "description": "Address category (e.g., Residential, Commercial)"
                              },
                              "street_1": {
                                "type": "string"
                              },
                              "street_2": {
                                "type": "string",
                                "nullable": true
                              },
                              "is_verified": {
                                "type": "boolean",
                                "description": "Whether the address has been verified"
                              },
                              "postal_code": {
                                "type": "string"
                              },
                              "raw_results": {
                                "type": "object",
                                "properties": {
                                  "types": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  },
                                  "geometry": {
                                    "type": "object",
                                    "properties": {
                                      "location": {
                                        "type": "object",
                                        "properties": {
                                          "lat": {
                                            "type": "number"
                                          },
                                          "lng": {
                                            "type": "number"
                                          }
                                        }
                                      },
                                      "viewport": {
                                        "type": "object",
                                        "properties": {
                                          "northeast": {
                                            "type": "object",
                                            "properties": {
                                              "lat": {
                                                "type": "number"
                                              },
                                              "lng": {
                                                "type": "number"
                                              }
                                            }
                                          },
                                          "southwest": {
                                            "type": "object",
                                            "properties": {
                                              "lat": {
                                                "type": "number"
                                              },
                                              "lng": {
                                                "type": "number"
                                              }
                                            }
                                          }
                                        }
                                      },
                                      "location_type": {
                                        "type": "string"
                                      }
                                    }
                                  },
                                  "place_id": {
                                    "type": "string"
                                  },
                                  "formatted_address": {
                                    "type": "string"
                                  },
                                  "navigation_points": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "location": {
                                          "type": "object",
                                          "properties": {
                                            "latitude": {
                                              "type": "number"
                                            },
                                            "longitude": {
                                              "type": "number"
                                            }
                                          }
                                        }
                                      }
                                    }
                                  },
                                  "address_components": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "types": {
                                          "type": "array",
                                          "items": {
                                            "type": "string"
                                          }
                                        },
                                        "long_name": {
                                          "type": "string"
                                        },
                                        "short_name": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  }
                                }
                              },
                              "address_type": {
                                "type": "string"
                              },
                              "document_location": {
                                "type": "object",
                                "properties": {
                                  "latitude": {
                                    "type": "number"
                                  },
                                  "longitude": {
                                    "type": "number"
                                  }
                                }
                              },
                              "formatted_address": {
                                "type": "string"
                              }
                            }
                          },
                          "extra_files": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "format": "uri"
                            },
                            "description": "Additional document verification files"
                          },
                          "front_image_camera_front_face_match_score": {
                            "type": "number",
                            "nullable": true,
                            "description": "Face match score between the portrait extracted from the front document image and the front camera image"
                          },
                          "back_image_camera_front_face_match_score": {
                            "type": "number",
                            "nullable": true,
                            "description": "Face match score between the portrait extracted from the back document image and the front camera image"
                          },
                          "document_selfie_face_matches": {
                            "type": "array",
                            "description": "Previous sessions or face blocklist entries whose face matched the selfie the front camera took during document capture (Silent Capture Face Search). Same entry format as `liveness_checks[].matches`. `null` for sessions created before this field existed or when the search did not run; an empty array when it ran and found nothing. `match_image_url` is a presigned URL that expires.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "session_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true,
                                  "description": "Session ID of the matching face. `null` when `source` is `imported`, `list_entry`, or `retained_template`."
                                },
                                "session_number": {
                                  "type": "integer",
                                  "nullable": true
                                },
                                "similarity_percentage": {
                                  "type": "number",
                                  "description": "Face similarity between the two images, clamped to 0–100."
                                },
                                "vendor_data": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "`vendor_data` of the matching session or linked User for imported and retained-template faces."
                                },
                                "vendor_user_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true,
                                  "description": "Linked User id for `imported` and `retained_template` matches and for session matches linked to a User. `null` for list entries and sessions without a User."
                                },
                                "biometric_template_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true,
                                  "description": "Id of the retained biometric template. Set only when `source` is `retained_template`; `null` otherwise."
                                },
                                "verification_date": {
                                  "type": "string",
                                  "format": "date-time",
                                  "nullable": true,
                                  "description": "When the matching face was captured, or when a retained template was created. `null` for list entries."
                                },
                                "user_details": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Identity data from the matching session or imported User profile. Always `null` for `retained_template` and `list_entry` matches.",
                                  "properties": {
                                    "full_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "document_type": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "document_number": {
                                      "type": "string",
                                      "nullable": true
                                    }
                                  }
                                },
                                "match_image_url": {
                                  "type": "string",
                                  "format": "uri",
                                  "nullable": true,
                                  "description": "Reference image for image-backed matches. Always `null` for `retained_template` matches because retained templates contain no image."
                                },
                                "status": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Lifecycle status of the matching session. `null` for non-session sources."
                                },
                                "is_blocklisted": {
                                  "type": "boolean",
                                  "description": "Whether the matching face is on a blocklist."
                                },
                                "is_allowlisted": {
                                  "type": "boolean",
                                  "description": "Whether the matching face is on an allowlist."
                                },
                                "api_service": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Standalone API service of the matching session (e.g. `PASSIVE_LIVENESS`, `FACE_MATCH`); `null` for workflow sessions and non-session sources."
                                },
                                "source": {
                                  "type": "string",
                                  "enum": [
                                    "session",
                                    "imported",
                                    "list_entry",
                                    "retained_template"
                                  ],
                                  "description": "Origin of the matching face: `session`, `imported` (User face upload), `list_entry` (allow/block list), or `retained_template` (an image-free biometric template stored on a User, listed under `/v3/biometric-templates/`)."
                                }
                              }
                            },
                            "nullable": true
                          },
                          "front_image_quality_score": {
                            "type": "object",
                            "nullable": true,
                            "description": "Quality metrics for the front document image. Each sub-score ranges from 0 to 100.",
                            "properties": {
                              "focus_score": {
                                "type": "number",
                                "description": "Sharpness of the image measured via top-10% local Laplacian variance. Robust to documents with large uniform backgrounds. Higher values indicate a sharper, less blurry image."
                              },
                              "brightness_score": {
                                "type": "number",
                                "description": "How well-lit the image is. Penalizes images that are too dark or overexposed, with ideal brightness around mid-range."
                              },
                              "brightness_issue": {
                                "type": "string",
                                "enum": [
                                  "ok",
                                  "too_dark",
                                  "too_bright"
                                ],
                                "description": "Indicates the direction of the brightness problem when the brightness_score is low. 'ok' means brightness is acceptable, 'too_dark' means the image is underexposed, 'too_bright' means the image is overexposed."
                              },
                              "is_document_fully_visible": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "true if all four corners of the document are fully visible inside the image frame, false if any corner is cut off. Null when corner coordinates are unavailable."
                              },
                              "resolution_score": {
                                "type": "number",
                                "description": "Effective resolution of the image based on total pixel count."
                              },
                              "overall_score": {
                                "type": "number",
                                "description": "Weighted composite of sub-scores (focus 45%, brightness 30%, resolution 25%)."
                              }
                            }
                          },
                          "back_image_quality_score": {
                            "type": "object",
                            "nullable": true,
                            "description": "Quality metrics for the back document image. Same structure as front_image_quality_score.",
                            "properties": {
                              "focus_score": {
                                "type": "number",
                                "description": "Sharpness of the image measured via top-10% local Laplacian variance. Robust to documents with large uniform backgrounds. Higher values indicate a sharper, less blurry image."
                              },
                              "brightness_score": {
                                "type": "number",
                                "description": "How well-lit the image is. Penalizes images that are too dark or overexposed, with ideal brightness around mid-range."
                              },
                              "brightness_issue": {
                                "type": "string",
                                "enum": [
                                  "ok",
                                  "too_dark",
                                  "too_bright"
                                ],
                                "description": "Indicates the direction of the brightness problem when the brightness_score is low. 'ok' means brightness is acceptable, 'too_dark' means the image is underexposed, 'too_bright' means the image is overexposed."
                              },
                              "is_document_fully_visible": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "true if all four corners of the document are fully visible inside the image frame, false if any corner is cut off. Null when corner coordinates are unavailable."
                              },
                              "resolution_score": {
                                "type": "number",
                                "description": "Effective resolution of the image based on total pixel count."
                              },
                              "overall_score": {
                                "type": "number",
                                "description": "Weighted composite of sub-scores (focus 45%, brightness 30%, resolution 25%)."
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning (e.g., `ID_VERIFICATION`, `NFC`, `LIVENESS`). The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module, but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Additional contextual data about the warning"
                                },
                                "log_type": {
                                  "type": "string",
                                  "description": "Type of log: information, warning, or error"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning (for graph-based workflows)"
                                }
                              }
                            },
                            "description": "Document verification warnings"
                          },
                          "matches": {
                            "type": "array",
                            "description": "Matching documents found during duplicate/blocklist detection (up to 5 matches)",
                            "items": {
                              "type": "object",
                              "properties": {
                                "session_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "description": "Session ID of the matching document"
                                },
                                "session_number": {
                                  "type": "integer",
                                  "description": "Session number of the matching document"
                                },
                                "vendor_data": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Vendor data associated with the matching session"
                                },
                                "verification_date": {
                                  "type": "string",
                                  "format": "date-time",
                                  "description": "Date when the matching session was verified"
                                },
                                "user_details": {
                                  "type": "object",
                                  "properties": {
                                    "name": {
                                      "type": "string",
                                      "description": "Full name from the matching document"
                                    },
                                    "document_type": {
                                      "type": "string",
                                      "description": "Type of the matching document"
                                    },
                                    "document_number": {
                                      "type": "string",
                                      "description": "Document number of the matching document"
                                    }
                                  }
                                },
                                "status": {
                                  "type": "string",
                                  "description": "Status of the matching session"
                                },
                                "is_blocklisted": {
                                  "type": "boolean",
                                  "description": "Whether the matching document is blocklisted"
                                },
                                "api_service": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "API service type of the matching session"
                                },
                                "front_image_url": {
                                  "type": "string",
                                  "format": "uri",
                                  "nullable": true,
                                  "description": "URL of the front document image from the matching document"
                                }
                              }
                            }
                          },
                          "document_liveness": {
                            "type": "object",
                            "nullable": true,
                            "description": "Document-liveness scores per fraud type, reported whether or not a warning fired, so an approved document can still be audited. `null` when the check did not run.",
                            "properties": {
                              "portrait_replace": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "score": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Likelihood that the document is genuine for this fraud type, 0-100 (higher = more likely genuine). The lowest of the two sides - the value the decision used. `null` when neither side produced a usable score."
                                  },
                                  "front": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Score for the front side; `null` when not captured or when the score was dropped."
                                  },
                                  "back": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Score for the back side; `null` when not captured or when the score was dropped."
                                  },
                                  "decline_threshold": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "The decline threshold saved when this document was evaluated. Later workflow edits do not change it. Null when historical evaluation evidence is unavailable."
                                  },
                                  "review_threshold": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "The review threshold saved when this document was evaluated. Later workflow edits do not change it. Null when historical evaluation evidence is unavailable."
                                  },
                                  "bucket": {
                                    "type": "string",
                                    "nullable": true,
                                    "enum": [
                                      "approve",
                                      "review",
                                      "decline",
                                      null
                                    ],
                                    "description": "The fraud-type bucket saved at evaluation time. Null when there is no usable score, the check was not applied, or historical evaluation evidence is unavailable. Later workflow edits do not change it."
                                  }
                                }
                              },
                              "printed_copy": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "score": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Likelihood that the document is genuine for this fraud type, 0-100 (higher = more likely genuine). The lowest of the two sides - the value the decision used. `null` when neither side produced a usable score."
                                  },
                                  "front": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Score for the front side; `null` when not captured or when the score was dropped."
                                  },
                                  "back": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Score for the back side; `null` when not captured or when the score was dropped."
                                  },
                                  "decline_threshold": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "The decline threshold saved when this document was evaluated. Later workflow edits do not change it. Null when historical evaluation evidence is unavailable."
                                  },
                                  "review_threshold": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "The review threshold saved when this document was evaluated. Later workflow edits do not change it. Null when historical evaluation evidence is unavailable."
                                  },
                                  "bucket": {
                                    "type": "string",
                                    "nullable": true,
                                    "enum": [
                                      "approve",
                                      "review",
                                      "decline",
                                      null
                                    ],
                                    "description": "The fraud-type bucket saved at evaluation time. Null when there is no usable score, the check was not applied, or historical evaluation evidence is unavailable. Later workflow edits do not change it."
                                  }
                                }
                              },
                              "screen_replay": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "score": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Likelihood that the document is genuine for this fraud type, 0-100 (higher = more likely genuine). The lowest of the two sides - the value the decision used. `null` when neither side produced a usable score."
                                  },
                                  "front": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Score for the front side; `null` when not captured or when the score was dropped."
                                  },
                                  "back": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Score for the back side; `null` when not captured or when the score was dropped."
                                  },
                                  "decline_threshold": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "The decline threshold saved when this document was evaluated. Later workflow edits do not change it. Null when historical evaluation evidence is unavailable."
                                  },
                                  "review_threshold": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "The review threshold saved when this document was evaluated. Later workflow edits do not change it. Null when historical evaluation evidence is unavailable."
                                  },
                                  "bucket": {
                                    "type": "string",
                                    "nullable": true,
                                    "enum": [
                                      "approve",
                                      "review",
                                      "decline",
                                      null
                                    ],
                                    "description": "The fraud-type bucket saved at evaluation time. Null when there is no usable score, the check was not applied, or historical evaluation evidence is unavailable. Later workflow edits do not change it."
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "nfc_skip_reason": {
                      "type": "string",
                      "nullable": true,
                      "enum": [
                        "USER_SKIPPED",
                        "DOCUMENT_WITHOUT_CHIP",
                        "CHIP_CERTIFICATE_UNAVAILABLE",
                        "DEVICE_WITHOUT_NFC",
                        "INTEGRATION_WITHOUT_NFC_ACCESS",
                        "MRZ_KEY_UNAVAILABLE"
                      ],
                      "description": "Why NFC chip verification did not run, populated whenever the workflow includes an NFC step. `null` while NFC is pending or when the chip was actually read. Values: `USER_SKIPPED` - the user chose to skip on an NFC-capable device (allowed by `allow_nfc_skip`); `DOCUMENT_WITHOUT_CHIP` - the document has no readable NFC chip (not an ICAO 9303 electronic document); `CHIP_CERTIFICATE_UNAVAILABLE` - the issuing country's signing certificate (CSCA) covering the document's issue period is unavailable, so the chip signature cannot be verified; `DEVICE_WITHOUT_NFC` - the device reported no NFC reader; `INTEGRATION_WITHOUT_NFC_ACCESS` - the verification ran without a native SDK (e.g. in a web browser), which has no access to the phone's NFC reader; `MRZ_KEY_UNAVAILABLE` - the chip access key could not be derived from the document's MRZ."
                    },
                    "nfc_verifications": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of NFC / ePassport reports** produced by NFC steps in the workflow graph. **This is always a JSON array, never a singular `nfc` object** — read `nfc_verifications[0]` and iterate if your workflow can run NFC more than once. `null` until at least one NFC step has produced data. Each item is the full report, including `node_id`, feature-level `status`, `chip_data`, `authenticity` (SOD + DG integrity), `certificate_summary`, and `warnings[]`. When the NFC step was bypassed before it could ever be offered (chipless document, missing certificate, no NFC capability reported, unreadable MRZ key), this stays `null` and `nfc_skip_reason` explains why; a skip at the step itself (user tapped skip, or the reader turned out unavailable at scan time) still produces a report with `is_nfc_skipped: true`.",
                      "items": {
                        "type": "object",
                        "description": "One NFC report — the full report for a single ePassport chip read.",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Workflow graph node id of the NFC step that produced this report. Use it to correlate the report with the workflow definition."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ],
                            "description": "Feature-level status of this NFC step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`."
                          },
                          "is_nfc_skipped": {
                            "type": "boolean",
                            "description": "`true` when this NFC step was explicitly skipped instead of read; `skip_reason` says why."
                          },
                          "skip_reason": {
                            "type": "string",
                            "nullable": true,
                            "enum": [
                              "USER_SKIPPED",
                              "DOCUMENT_WITHOUT_CHIP",
                              "CHIP_CERTIFICATE_UNAVAILABLE",
                              "DEVICE_WITHOUT_NFC",
                              "INTEGRATION_WITHOUT_NFC_ACCESS",
                              "MRZ_KEY_UNAVAILABLE"
                            ],
                            "description": "Why this NFC step was skipped. Only set when `is_nfc_skipped` is `true`. Same taxonomy as the session-level `nfc_skip_reason`, which additionally covers the cases where NFC never produced a report at all."
                          },
                          "portrait_image": {
                            "type": "string",
                            "format": "uri"
                          },
                          "signature_image": {
                            "type": "string",
                            "format": "uri"
                          },
                          "chip_data": {
                            "type": "object",
                            "properties": {
                              "document_type": {
                                "type": "string"
                              },
                              "issuing_country": {
                                "type": "string"
                              },
                              "document_number": {
                                "type": "string"
                              },
                              "expiration_date": {
                                "type": "string",
                                "format": "date"
                              },
                              "first_name": {
                                "type": "string"
                              },
                              "last_name": {
                                "type": "string"
                              },
                              "birth_date": {
                                "type": "string",
                                "format": "date"
                              },
                              "gender": {
                                "type": "string"
                              },
                              "nationality": {
                                "type": "string"
                              },
                              "address": {
                                "type": "string"
                              },
                              "place_of_birth": {
                                "type": "string"
                              }
                            }
                          },
                          "authenticity": {
                            "type": "object",
                            "properties": {
                              "sod_integrity": {
                                "type": "boolean"
                              },
                              "dg_integrity": {
                                "type": "boolean"
                              }
                            }
                          },
                          "certificate_summary": {
                            "type": "object",
                            "properties": {
                              "issuer": {
                                "type": "string"
                              },
                              "subject": {
                                "type": "string"
                              },
                              "serial_number": {
                                "type": "string"
                              },
                              "not_valid_after": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "not_valid_before": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "liveness_checks": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of liveness reports** produced by liveness steps in the workflow graph. Always a JSON array — never a singular `liveness` object. `null` until at least one liveness step has produced data. Each item is the full report, including `node_id`, feature-level `status`, `method`, `score`, `reference_image`, `video_url`, optional `age_estimation`, cross-session `matches[]`, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "description": "One liveness report — the full report for a single liveness pass.",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Workflow graph node id of the liveness step that produced this report."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ],
                            "description": "Feature-level status of this liveness step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`."
                          },
                          "method": {
                            "type": "string",
                            "description": "Method used for liveness detection"
                          },
                          "score": {
                            "type": "number",
                            "description": "Confidence score of the liveness check"
                          },
                          "reference_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the reference image used"
                          },
                          "video_url": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the liveness check video"
                          },
                          "age_estimation": {
                            "type": "number",
                            "description": "Estimated age of the person"
                          },
                          "matches": {
                            "type": "array",
                            "description": "Similar faces found by the duplicate-face search (top matches, blocklisted/allowlisted entries first). Each entry's `source` tells you where the matching face came from: `session` (another verification session), `imported` (a face uploaded against a vendor user), `list_entry` (an org-managed allow/block list face), or `retained_template` (an image-free biometric template stored on a User, listed under `/v3/biometric-templates/`). `session_id`, `session_number`, `status` and `api_service` are `null` for non-session sources. `imported` matches still populate `vendor_data`, `verification_date` and — when the vendor user has a name on file — `user_details` (with `full_name` only) from the vendor-user record; `retained_template` matches populate `vendor_user_id`, `vendor_data`, `biometric_template_id` and `verification_date`, while their image and identity fields are `null`; `list_entry` matches return all of these as `null`.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "session_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true,
                                  "description": "Session ID of the matching face. `null` when `source` is `imported`, `list_entry`, or `retained_template`."
                                },
                                "session_number": {
                                  "type": "integer",
                                  "nullable": true
                                },
                                "similarity_percentage": {
                                  "type": "number",
                                  "description": "Face similarity between the two images, clamped to 0–100."
                                },
                                "vendor_data": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "`vendor_data` of the matching session or linked User for imported and retained-template faces."
                                },
                                "vendor_user_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true,
                                  "description": "Linked User id for `imported` and `retained_template` matches and for session matches linked to a User. `null` for list entries and sessions without a User."
                                },
                                "biometric_template_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true,
                                  "description": "Id of the retained biometric template. Set only when `source` is `retained_template`; `null` otherwise."
                                },
                                "verification_date": {
                                  "type": "string",
                                  "format": "date-time",
                                  "nullable": true,
                                  "description": "When the matching face was captured, or when a retained template was created. `null` for list entries."
                                },
                                "user_details": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Identity data from the matching session or imported User profile. Always `null` for `retained_template` and `list_entry` matches.",
                                  "properties": {
                                    "full_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "document_type": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "document_number": {
                                      "type": "string",
                                      "nullable": true
                                    }
                                  }
                                },
                                "match_image_url": {
                                  "type": "string",
                                  "format": "uri",
                                  "nullable": true,
                                  "description": "Reference image for image-backed matches. Always `null` for `retained_template` matches because retained templates contain no image."
                                },
                                "status": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Lifecycle status of the matching session. `null` for non-session sources."
                                },
                                "is_blocklisted": {
                                  "type": "boolean",
                                  "description": "Whether the matching face is on a blocklist."
                                },
                                "is_allowlisted": {
                                  "type": "boolean",
                                  "description": "Whether the matching face is on an allowlist."
                                },
                                "api_service": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Standalone API service of the matching session (e.g. `PASSIVE_LIVENESS`, `FACE_MATCH`); `null` for workflow sessions and non-session sources."
                                },
                                "source": {
                                  "type": "string",
                                  "enum": [
                                    "session",
                                    "imported",
                                    "list_entry",
                                    "retained_template"
                                  ],
                                  "description": "Origin of the matching face: `session`, `imported` (User face upload), `list_entry` (allow/block list), or `retained_template` (an image-free biometric template stored on a User, listed under `/v3/biometric-templates/`)."
                                }
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          },
                          "face_quality": {
                            "type": "number",
                            "nullable": true,
                            "description": "Face image quality score (0-100%). Only available for passive liveness."
                          },
                          "face_luminance": {
                            "type": "number",
                            "nullable": true,
                            "description": "Face luminance/brightness score (0-100%). Only available for passive liveness."
                          }
                        }
                      }
                    },
                    "face_matches": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of face-match reports** produced by face-match steps in the workflow graph. Always a JSON array — never a singular `face_match` object. `null` until at least one face-match step has produced data. Each item is the full report, including `node_id`, feature-level `status`, similarity `score`, `source_image`, `target_image`, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "description": "One face-match report — the full report.",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Workflow graph node id of the face-match step that produced this report."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ],
                            "description": "Feature-level status of this face-match step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`."
                          },
                          "score": {
                            "type": "number",
                            "description": "Confidence score of the face match"
                          },
                          "source_image_session_id": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true,
                            "description": "Session id under which the source (reference) portrait is stored. In biometric-authentication flows this is the session's own id (the submitted portrait is stored under the new session). `null` when the source image is the same session's document portrait."
                          },
                          "source_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the source image used for comparison"
                          },
                          "target_image": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the target image used for comparison"
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            },
                            "description": "Face match verification warnings"
                          }
                        }
                      }
                    },
                    "phone_verifications": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of phone verification reports** — always a JSON array, never a singular `phone` object. `null` until at least one phone step has produced data. Each item is the full report, including `node_id`, feature-level `status`, the phone number and country metadata, `lifecycle[]`, `matches[]`, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this phone step in the workflow graph."
                          },
                          "status": {
                            "type": "string",
                            "description": "Feature-level status of this phone verification step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`.",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Expired"
                            ]
                          },
                          "phone_number_prefix": {
                            "type": "string",
                            "description": "Country calling code prefix"
                          },
                          "phone_number": {
                            "type": "string",
                            "description": "Phone number without country prefix"
                          },
                          "full_number": {
                            "type": "string",
                            "description": "Complete phone number with country prefix"
                          },
                          "country_code": {
                            "type": "string",
                            "description": "Two-letter country code (ISO 3166-1 alpha-2)"
                          },
                          "country_name": {
                            "type": "string",
                            "description": "Full country name"
                          },
                          "carrier": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "description": "Name of the phone carrier"
                              },
                              "type": {
                                "type": "string",
                                "description": "Type of phone line (mobile, landline, etc)"
                              }
                            }
                          },
                          "is_disposable": {
                            "type": "boolean",
                            "description": "Whether the phone number is from a disposable service"
                          },
                          "is_virtual": {
                            "type": "boolean",
                            "description": "Whether the phone number is virtual"
                          },
                          "verification_method": {
                            "type": "string",
                            "description": "Method used to verify the phone number"
                          },
                          "verification_attempts": {
                            "type": "integer",
                            "description": "Number of verification attempts made"
                          },
                          "verified_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Timestamp when the phone was verified"
                          },
                          "lifecycle": {
                            "type": "array",
                            "description": "Chronological list of events in the phone verification lifecycle.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string"
                                },
                                "timestamp": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "details": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Event-specific payload. Send events carry `status`, `reason`, `channel`, `actual_channel`; delivery events carry `channel`, `status`; code-check events carry `code_tried`, `status`; final status events carry `reason` — or `null` when there is no reason to report (e.g. `PHONE_VERIFICATION_APPROVED`).",
                                  "properties": {
                                    "status": {
                                      "type": "string"
                                    },
                                    "reason": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "channel": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "actual_channel": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "code_tried": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "fee": {
                                  "type": "number"
                                }
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "description": "List of warnings related to phone verification",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          },
                          "matches": {
                            "type": "array",
                            "description": "Matches found for this phone number. Each match has a `source`: `session` (another verification session in your application matched on the same number, returned with `session_id`/`session_number`/`vendor_data`/`verification_date`) or `list_entry` (the number is on an org-managed allow/block list — see `/management-api/lists/overview`). Cross-session matches use different `vendor_data` and are capped at 5.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "session_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true
                                },
                                "session_number": {
                                  "type": "integer",
                                  "nullable": true
                                },
                                "vendor_data": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "verification_date": {
                                  "type": "string",
                                  "format": "date-time",
                                  "nullable": true
                                },
                                "phone_number": {
                                  "type": "string"
                                },
                                "status": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "is_blocklisted": {
                                  "type": "boolean"
                                },
                                "api_service": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "source": {
                                  "type": "string",
                                  "enum": [
                                    "session",
                                    "list_entry"
                                  ],
                                  "description": "Where this match came from. `session` means another verification session in your application matched on this value. `list_entry` means the value was hit against an org-managed list (allowlist/blocklist) — see the management API lists overview at `/management-api/lists/overview` for how to manage those lists."
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "email_verifications": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of email verification reports** — always a JSON array, never a singular `email` object. `null` until at least one email step has produced data. Each item is the full report, including `node_id`, feature-level `status`, the email address, breach data, `lifecycle[]`, `matches[]`, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this email step in the workflow graph."
                          },
                          "status": {
                            "type": "string",
                            "description": "Feature-level status of this email verification step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`.",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Expired"
                            ]
                          },
                          "email": {
                            "type": "string",
                            "description": "The email address being verified"
                          },
                          "is_breached": {
                            "type": "boolean",
                            "description": "Indicates if the email was found in known data breaches"
                          },
                          "breaches": {
                            "type": "array",
                            "description": "List of known breaches this email was found in",
                            "items": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string",
                                  "description": "Name of the breach"
                                },
                                "domain": {
                                  "type": "string",
                                  "description": "Domain affected by the breach"
                                },
                                "logo_path": {
                                  "type": "string",
                                  "description": "URL to the logo of the breached service"
                                },
                                "breach_date": {
                                  "type": "string",
                                  "format": "date",
                                  "description": "Date when the breach occurred"
                                },
                                "description": {
                                  "type": "string",
                                  "description": "Description of the breach"
                                },
                                "is_verified": {
                                  "type": "boolean",
                                  "description": "Whether the breach is verified"
                                },
                                "data_classes": {
                                  "type": "array",
                                  "description": "Types of data exposed in the breach",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "breach_emails_count": {
                                  "type": "integer",
                                  "description": "Number of email addresses affected in the breach"
                                }
                              }
                            }
                          },
                          "is_disposable": {
                            "type": "boolean",
                            "description": "Indicates if the email is from a disposable provider"
                          },
                          "is_undeliverable": {
                            "type": "boolean",
                            "description": "Indicates if the email address is undeliverable"
                          },
                          "verification_attempts": {
                            "type": "integer",
                            "description": "Number of verification attempts for this email"
                          },
                          "verified_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Timestamp when the email was verified"
                          },
                          "warnings": {
                            "type": "array",
                            "description": "List of warnings related to email verification",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          },
                          "lifecycle": {
                            "type": "array",
                            "description": "Chronological list of events in the email verification lifecycle.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "type": {
                                  "type": "string"
                                },
                                "timestamp": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "details": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Event-specific payload. Send events carry `status`, `reason`; code-check events carry `code_tried`, `status`; final status events carry `reason` — or `null` when there is no reason to report (e.g. `EMAIL_VERIFICATION_APPROVED`).",
                                  "properties": {
                                    "status": {
                                      "type": "string"
                                    },
                                    "reason": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "code_tried": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "fee": {
                                  "type": "number"
                                }
                              }
                            }
                          },
                          "matches": {
                            "type": "array",
                            "description": "Matches found for this email address. Each match has a `source`: `session` (another verification session in your application matched on the same email, returned with `session_id`/`session_number`/`vendor_data`/`verification_date`) or `list_entry` (the email is on an org-managed allow/block list — see `/management-api/lists/overview`). Cross-session matches use different `vendor_data` and are capped at 5.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "session_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "nullable": true
                                },
                                "session_number": {
                                  "type": "integer",
                                  "nullable": true
                                },
                                "vendor_data": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "verification_date": {
                                  "type": "string",
                                  "format": "date-time",
                                  "nullable": true
                                },
                                "email": {
                                  "type": "string",
                                  "format": "email"
                                },
                                "status": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "is_blocklisted": {
                                  "type": "boolean"
                                },
                                "api_service": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "source": {
                                  "type": "string",
                                  "enum": [
                                    "session",
                                    "list_entry"
                                  ],
                                  "description": "Where this match came from. `session` means another verification session in your application matched on this value. `list_entry` means the value was hit against an org-managed list (allowlist/blocklist) — see the management API lists overview at `/management-api/lists/overview` for how to manage those lists."
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "poa_verifications": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of Proof of Address (POA) reports** — always a JSON array, never a singular `poa` object. `null` until at least one POA step has produced data. Each item is the full report, including `node_id`, feature-level `status`, the document file URL, issuer, dates, parsed address, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this POA step in the workflow graph."
                          },
                          "status": {
                            "type": "string",
                            "description": "Feature-level status of this Proof of Address step. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`.",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ]
                          },
                          "document_file": {
                            "type": "string",
                            "format": "uri",
                            "description": "URL of the proof of address document"
                          },
                          "issuing_state": {
                            "type": "string",
                            "description": "Two-letter country code of the issuing state"
                          },
                          "document_type": {
                            "type": "string",
                            "description": "Type of proof of address document"
                          },
                          "document_subtype": {
                            "type": "string",
                            "nullable": true,
                            "description": "More specific classification of the POA document within its `document_type`, when one was detected. `null` otherwise."
                          },
                          "document_language": {
                            "type": "string",
                            "description": "Language code of the document"
                          },
                          "document_metadata": {
                            "type": "object",
                            "properties": {
                              "file_size": {
                                "type": "integer",
                                "description": "Size of the document"
                              },
                              "content_type": {
                                "type": "string",
                                "description": "Content type of the document"
                              },
                              "creation_date": {
                                "type": "string",
                                "format": "date",
                                "description": "Date when the document was created"
                              },
                              "modified_date": {
                                "type": "string",
                                "format": "date",
                                "description": "Date when the document was modified"
                              },
                              "overlay_manipulation": {
                                "type": "object",
                                "nullable": true,
                                "description": "PDF forensic analysis for suspected overlay-text manipulation. Null when no overlay manipulation evidence was found or the document was not a PDF.",
                                "properties": {
                                  "detected": {
                                    "type": "boolean",
                                    "description": "Whether overlay-text manipulation evidence was detected."
                                  },
                                  "analyzed": {
                                    "type": "boolean",
                                    "description": "Whether the PDF could be analyzed."
                                  },
                                  "signals": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    },
                                    "description": "Forensic signals that fired, such as duplicate_font_subset or glyph_fragmentation."
                                  },
                                  "manipulated_regions": {
                                    "type": "array",
                                    "description": "Suspected manipulated areas in PDF page coordinates.",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "page": {
                                          "type": "integer"
                                        },
                                        "x": {
                                          "type": "number"
                                        },
                                        "y": {
                                          "type": "number"
                                        },
                                        "width": {
                                          "type": "number"
                                        },
                                        "height": {
                                          "type": "number"
                                        },
                                        "page_width": {
                                          "type": "number"
                                        },
                                        "page_height": {
                                          "type": "number"
                                        }
                                      }
                                    }
                                  }
                                }
                              },
                              "creator": {
                                "type": "string",
                                "nullable": true,
                                "description": "Creator application recorded in the document metadata."
                              },
                              "producer": {
                                "type": "string",
                                "nullable": true,
                                "description": "Producer software recorded in the PDF metadata."
                              },
                              "software": {
                                "type": "string",
                                "nullable": true,
                                "description": "Editing/processing software recorded in the file metadata."
                              },
                              "encryption": {
                                "type": "string",
                                "nullable": true,
                                "description": "Encryption scheme of the document, when encrypted."
                              },
                              "is_signed": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "Whether the PDF carries a digital signature."
                              },
                              "is_tampered": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "Whether signature validation indicates the file was modified after signing."
                              },
                              "signature_info": {
                                "type": "object",
                                "nullable": true,
                                "description": "Details of the digital signature(s), when present."
                              },
                              "exif_original_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "EXIF original capture date, for image uploads."
                              },
                              "exif_digitized_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "EXIF digitization date, for image uploads."
                              },
                              "processed_by_known_editor": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "Whether the file metadata indicates processing by a known document editor."
                              },
                              "has_different_creation_mod_date": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "Whether the creation and modification dates differ — a common manipulation signal."
                              }
                            },
                            "description": "File-forensics metadata extracted from the uploaded POA document. Always contains the keys below (values are `null` when not applicable, e.g. EXIF dates for PDFs). `null` when no metadata could be extracted.",
                            "nullable": true
                          },
                          "issuer": {
                            "type": "string",
                            "description": "Name of the document issuer"
                          },
                          "issue_date": {
                            "type": "string",
                            "format": "date",
                            "description": "Date when the document was issued"
                          },
                          "expiration_date": {
                            "type": "string",
                            "format": "date",
                            "nullable": true,
                            "description": "Expiration date of the document, if available"
                          },
                          "poa_address": {
                            "type": "string",
                            "description": "Raw address from the proof of address document"
                          },
                          "poa_formatted_address": {
                            "type": "string",
                            "description": "Formatted address from the proof of address document"
                          },
                          "poa_parsed_address": {
                            "type": "object",
                            "properties": {
                              "address_type": {
                                "type": "string",
                                "description": "Type of address (Street, Avenue, etc)"
                              },
                              "street_1": {
                                "type": "string",
                                "description": "Primary street address"
                              },
                              "street_2": {
                                "type": "string",
                                "nullable": true,
                                "description": "Secondary street address"
                              },
                              "city": {
                                "type": "string",
                                "description": "City name"
                              },
                              "region": {
                                "type": "string",
                                "description": "Region or state name"
                              },
                              "country": {
                                "type": "string",
                                "description": "Two-letter country code"
                              },
                              "postal_code": {
                                "type": "string",
                                "description": "Postal code"
                              },
                              "document_location": {
                                "type": "object",
                                "properties": {
                                  "latitude": {
                                    "type": "number",
                                    "description": "Latitude coordinate"
                                  },
                                  "longitude": {
                                    "type": "number",
                                    "description": "Longitude coordinate"
                                  }
                                }
                              }
                            }
                          },
                          "name_on_document": {
                            "type": "string",
                            "nullable": true,
                            "description": "Account-holder / addressee name extracted from the POA document, used for name matching. `null` when no name could be extracted."
                          },
                          "name_match_score_expected_details": {
                            "type": "number",
                            "nullable": true,
                            "description": "Similarity score (0-100) between `name_on_document` and the expected name supplied at session creation. `null` when either side is missing."
                          },
                          "name_match_score_id_verification": {
                            "type": "number",
                            "nullable": true,
                            "description": "Similarity score (0-100) between `name_on_document` and the name extracted by the ID verification step. `null` when either side is missing."
                          },
                          "expected_details_address": {
                            "type": "string",
                            "nullable": true,
                            "description": "Expected raw address for verification"
                          },
                          "expected_details_formatted_address": {
                            "type": "string",
                            "nullable": true,
                            "description": "Expected formatted address for verification"
                          },
                          "expected_details_parsed_address": {
                            "type": "object",
                            "description": "Expected parsed address details for verification"
                          },
                          "extra_fields": {
                            "type": "object",
                            "description": "Additional banking and contact details extracted from the document.",
                            "properties": {
                              "bank_account_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "bank_iban": {
                                "type": "string",
                                "nullable": true
                              },
                              "bank_sort_code": {
                                "type": "string",
                                "nullable": true
                              },
                              "bank_routing_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "bank_swift_bic": {
                                "type": "string",
                                "nullable": true
                              },
                              "bank_branch_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "bank_branch_address": {
                                "type": "string",
                                "nullable": true
                              },
                              "document_phone_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "additional_names": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "extra_files": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "format": "uri"
                            },
                            "description": "Additional proof of address files"
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          },
                          "detected_codes": {
                            "type": "array",
                            "description": "QR codes and barcodes detected across every processed page of the document. Empty when none are found. A located but undecodable QR code has `parsed_payload: null`.",
                            "items": {
                              "$ref": "#/components/schemas/DocumentAIDetectedCode"
                            }
                          }
                        }
                      }
                    },
                    "document_ai_documents": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Document AI reports grouped by workflow node** — always a JSON array, never a singular object. `null` until at least one Document AI step has produced data. Present only when `session_kind = user`. Each item is a node group with an aggregate `status`, the `node_id`, an `items[]` array of the per-document results (extracted data keyed by the configured field key), and `warnings`.",
                      "items": {
                        "type": "object",
                        "description": "Document AI results grouped by workflow node.",
                        "properties": {
                          "status": {
                            "type": "string",
                            "description": "Aggregate Document AI status for this node, rolled up from its `items[]`.",
                            "enum": [
                              "Approved",
                              "Declined",
                              "In Review",
                              "Not Finished"
                            ]
                          },
                          "node_id": {
                            "type": "string",
                            "nullable": true,
                            "description": "Unique identifier for this Document AI step in the workflow graph."
                          },
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "uuid": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "node_id": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Workflow graph node that produced this document."
                                },
                                "document_key": {
                                  "type": "string",
                                  "description": "Key of the configured Document AI document this file corresponds to."
                                },
                                "original_filename": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Filename as uploaded by the user."
                                },
                                "file_size": {
                                  "type": "integer",
                                  "nullable": true,
                                  "description": "File size in bytes."
                                },
                                "file_url": {
                                  "type": "string",
                                  "format": "uri",
                                  "nullable": true,
                                  "description": "Short-lived presigned link to the uploaded file."
                                },
                                "status": {
                                  "type": "string",
                                  "enum": [
                                    "Approved",
                                    "Declined",
                                    "In Review",
                                    "Not Finished"
                                  ],
                                  "description": "Per-document Document AI status."
                                },
                                "extracted_data": {
                                  "type": "object",
                                  "additionalProperties": true,
                                  "nullable": true,
                                  "description": "Values extracted by Document AI, keyed by the configured field `key`. Each value is a string, number, or `null`."
                                },
                                "detected_codes": {
                                  "type": "array",
                                  "description": "QR codes and barcodes detected across every processed page. Empty when none are found. A located but undecodable QR code has `parsed_payload: null`.",
                                  "items": {
                                    "$ref": "#/components/schemas/DocumentAIDetectedCode"
                                  }
                                },
                                "fields": {
                                  "type": "array",
                                  "description": "The configured extraction fields for this document.",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "key": {
                                        "type": "string",
                                        "description": "Stable field key used as the key in `extracted_data`."
                                      },
                                      "name": {
                                        "type": "string",
                                        "description": "Human-readable field name."
                                      },
                                      "instruction": {
                                        "type": "string",
                                        "description": "Extraction instruction shown to the model."
                                      },
                                      "type": {
                                        "type": "string",
                                        "enum": [
                                          "text",
                                          "number",
                                          "date"
                                        ],
                                        "description": "Expected value type of the extracted field."
                                      },
                                      "required": {
                                        "type": "boolean",
                                        "description": "Whether this field is required."
                                      }
                                    }
                                  }
                                },
                                "document_metadata": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "File-forensics metadata extracted from the uploaded document (e.g. `is_tampered`). `null` when nothing could be extracted."
                                },
                                "cross_check_result": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Cross-reference of the extracted document fields against other session data. `null` when no cross-check was performed."
                                },
                                "created_at": {
                                  "type": "string",
                                  "format": "date-time"
                                }
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "nullable": true,
                            "items": {
                              "type": "object"
                            },
                            "description": "Warning logs raised for this Document AI node."
                          }
                        }
                      }
                    },
                    "questionnaire_responses": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of questionnaire response reports** — always a JSON array, never a singular `questionnaire` object. `null` until at least one questionnaire step has produced data. Each item is the full report, including `node_id`, the questionnaire metadata, sections with form elements, and the user's answers.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this questionnaire step in the workflow graph."
                          },
                          "questionnaire_id": {
                            "type": "string",
                            "description": "Unique identifier for the questionnaire"
                          },
                          "title": {
                            "type": "string",
                            "description": "Title of the questionnaire"
                          },
                          "description": {
                            "type": "string",
                            "description": "Description of the questionnaire"
                          },
                          "languages": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "Supported languages"
                          },
                          "default_language": {
                            "type": "string",
                            "description": "Default language"
                          },
                          "is_active": {
                            "type": "boolean",
                            "description": "Whether the questionnaire is active"
                          },
                          "is_simple_questionnaire": {
                            "type": "boolean",
                            "description": "Whether the questionnaire is a simple linear form (no branching graph)."
                          },
                          "questionnaire_group_id": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true,
                            "description": "Stable identifier of the questionnaire group across versions."
                          },
                          "version": {
                            "type": "integer",
                            "nullable": true,
                            "description": "Version number of the questionnaire that was answered."
                          },
                          "published_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true,
                            "description": "Timestamp at which this questionnaire version was published."
                          },
                          "sections": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "title": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Section title"
                                },
                                "description": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Section description"
                                },
                                "items": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "uuid": {
                                        "type": "string",
                                        "description": "Unique identifier for the item"
                                      },
                                      "value": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Stable node identifier of this form element within the questionnaire graph."
                                      },
                                      "element_type": {
                                        "type": "string",
                                        "description": "Type of the questionnaire element"
                                      },
                                      "is_required": {
                                        "type": "boolean",
                                        "description": "Whether the item is required"
                                      },
                                      "title": {
                                        "type": "string",
                                        "description": "Title of the item"
                                      },
                                      "description": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Description of the item"
                                      },
                                      "placeholder": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Placeholder text"
                                      },
                                      "choices": {
                                        "type": "array",
                                        "nullable": true,
                                        "items": {
                                          "type": "object",
                                          "properties": {
                                            "label": {
                                              "type": "string"
                                            },
                                            "value": {
                                              "type": "string"
                                            },
                                            "requires_text_input": {
                                              "type": "boolean",
                                              "description": "Whether this choice requires additional text input",
                                              "nullable": true
                                            }
                                          },
                                          "required": [
                                            "label",
                                            "value"
                                          ]
                                        },
                                        "description": "Choices for dropdown or single choice elements"
                                      },
                                      "max_files": {
                                        "type": "integer",
                                        "description": "Maximum number of files allowed",
                                        "nullable": true
                                      },
                                      "answer": {
                                        "type": "object",
                                        "description": "Answer provided for the item",
                                        "properties": {
                                          "value": {
                                            "type": "string",
                                            "nullable": true
                                          },
                                          "text": {
                                            "type": "string",
                                            "nullable": true
                                          },
                                          "files": {
                                            "type": "array",
                                            "items": {
                                              "type": "string"
                                            },
                                            "nullable": true
                                          }
                                        }
                                      },
                                      "required_if": {
                                        "type": "object",
                                        "nullable": true,
                                        "description": "Conditional-requirement rule, when the element is only required for certain answers."
                                      },
                                      "repeatable_config": {
                                        "type": "object",
                                        "nullable": true,
                                        "description": "Configuration for repeatable element groups, when applicable."
                                      }
                                    },
                                    "required": [
                                      "uuid",
                                      "value",
                                      "element_type",
                                      "is_required",
                                      "title"
                                    ]
                                  }
                                }
                              }
                            }
                          },
                          "status": {
                            "type": "string",
                            "description": "Status of the questionnaire"
                          }
                        }
                      }
                    },
                    "aml_screenings": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of AML screening reports** — always a JSON array, never a singular `aml` object. `null` until at least one AML step has produced data. Each item is the full report, including `node_id`, feature-level `status`, `total_hits`, `entity_type`, `hits[]`, `score`, `screened_data`, `is_ongoing_monitoring_enabled`, and `warnings[]`.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this AML step in the workflow graph."
                          },
                          "status": {
                            "type": "string",
                            "description": "Feature-level status of this AML screening. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`.",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ]
                          },
                          "total_hits": {
                            "type": "integer",
                            "description": "Total number of matches found"
                          },
                          "entity_type": {
                            "type": "string",
                            "description": "Type of entity screened: person or company"
                          },
                          "hits": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Unique identifier of the match"
                                },
                                "url": {
                                  "type": "string",
                                  "format": "uri",
                                  "description": "Source URL for the match"
                                },
                                "match": {
                                  "type": "boolean",
                                  "description": "Whether this is a confirmed match"
                                },
                                "score": {
                                  "type": "number",
                                  "format": "float",
                                  "nullable": true,
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Deprecated weighted match score in the 0-1 range (e.g. `0.73`). Use `match_score` (0-100) instead.",
                                  "deprecated": true
                                },
                                "target": {
                                  "type": "boolean",
                                  "nullable": true,
                                  "description": "Whether the matched entity is the direct target of the listing (as opposed to a related party). `null` when the source does not specify it."
                                },
                                "caption": {
                                  "type": "string",
                                  "description": "Caption or title of the match"
                                },
                                "datasets": {
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "enum": [
                                      "PEP",
                                      "PEP Level 1",
                                      "PEP Level 2",
                                      "PEP Level 3",
                                      "PEP Level 4",
                                      "Sanctions",
                                      "Adverse Media",
                                      "Warnings and Regulatory Enforcement",
                                      "Fitness and Probity",
                                      "SIP",
                                      "SIE",
                                      "Insolvency"
                                    ]
                                  },
                                  "description": "List of dataset categories where the match was found. Indicates whether the entity appeared in PEP lists (with level), sanctions databases, adverse media, warnings/regulatory enforcement, or other compliance datasets."
                                },
                                "features": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Additional features of the match"
                                },
                                "rca_name": {
                                  "type": "string",
                                  "description": "RCA name if applicable"
                                },
                                "last_seen": {
                                  "type": "string",
                                  "format": "date-time",
                                  "description": "Date when match was last seen"
                                },
                                "risk_view": {
                                  "type": "object",
                                  "properties": {
                                    "crimes": {
                                      "type": "object",
                                      "properties": {
                                        "score": {
                                          "type": "integer"
                                        },
                                        "weightage": {
                                          "type": "integer"
                                        },
                                        "risk_level": {
                                          "type": "string"
                                        },
                                        "risk_scores": {
                                          "type": "object"
                                        }
                                      }
                                    },
                                    "countries": {
                                      "type": "object",
                                      "properties": {
                                        "score": {
                                          "type": "integer"
                                        },
                                        "weightage": {
                                          "type": "integer"
                                        },
                                        "risk_level": {
                                          "type": "string"
                                        },
                                        "risk_scores": {
                                          "type": "object"
                                        }
                                      }
                                    },
                                    "categories": {
                                      "type": "object",
                                      "properties": {
                                        "score": {
                                          "type": "integer"
                                        },
                                        "weightage": {
                                          "type": "integer"
                                        },
                                        "risk_level": {
                                          "type": "string"
                                        },
                                        "risk_scores": {
                                          "type": "object"
                                        }
                                      }
                                    },
                                    "custom_list": {
                                      "type": "object"
                                    }
                                  }
                                },
                                "first_seen": {
                                  "type": "string",
                                  "format": "date-time",
                                  "description": "Date when match was first seen"
                                },
                                "properties": {
                                  "type": "object",
                                  "properties": {
                                    "name": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "alias": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "notes": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "title": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "gender": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "height": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "topics": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "weight": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "address": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "country": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "website": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "eyeColor": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "keywords": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "lastName": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "position": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "religion": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "birthDate": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "education": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "ethnicity": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "firstName": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "hairColor": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "weakAlias": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "birthPlace": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "modifiedAt": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "wikidataId": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "citizenship": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "nationality": {
                                      "type": "string",
                                      "nullable": true
                                    }
                                  }
                                },
                                "match_score": {
                                  "type": "number",
                                  "description": "Weighted identity confidence score (0-100) calculated from name similarity, date of birth, and country matching. Used to determine if hit is a False Positive or Possible Match.",
                                  "format": "float",
                                  "nullable": true
                                },
                                "risk_score": {
                                  "type": "number",
                                  "description": "Entity risk score (0-100). Used to determine final AML status (Approved/In Review/Declined) based on the highest risk_score among non-False-Positive hits."
                                },
                                "review_status": {
                                  "type": "string",
                                  "description": "Review status for this hit. Can be 'Unreviewed', 'Confirmed Match', 'False Positive', or 'Inconclusive'.",
                                  "enum": [
                                    "Unreviewed",
                                    "Confirmed Match",
                                    "False Positive",
                                    "Inconclusive"
                                  ]
                                },
                                "score_breakdown": {
                                  "type": "object",
                                  "description": "Detailed breakdown of how the match_score was calculated.",
                                  "properties": {
                                    "name_score": {
                                      "type": "integer",
                                      "description": "Raw name similarity percentage (0-100)."
                                    },
                                    "name_weight": {
                                      "type": "integer",
                                      "description": "Original weight for name from config (0-100)."
                                    },
                                    "name_weight_normalized": {
                                      "type": "number",
                                      "description": "Normalized weight for name after re-weighting for missing data (0-100)."
                                    },
                                    "name_contribution": {
                                      "type": "number",
                                      "description": "Points contributed by name to the total score."
                                    },
                                    "dob_score": {
                                      "type": "integer",
                                      "description": "DOB match score (-100 to 100)."
                                    },
                                    "dob_weight": {
                                      "type": "integer",
                                      "description": "Original weight for DOB from config (0-100)."
                                    },
                                    "dob_weight_normalized": {
                                      "type": "number",
                                      "description": "Normalized weight for DOB after re-weighting for missing data (0-100)."
                                    },
                                    "dob_contribution": {
                                      "type": "number",
                                      "description": "Points contributed by DOB to the total score."
                                    },
                                    "country_score": {
                                      "type": "integer",
                                      "description": "Country match score (-100 to 100)."
                                    },
                                    "country_weight": {
                                      "type": "integer",
                                      "description": "Original weight for country from config (0-100)."
                                    },
                                    "country_weight_normalized": {
                                      "type": "number",
                                      "description": "Normalized weight for country after re-weighting for missing data (0-100)."
                                    },
                                    "country_contribution": {
                                      "type": "number",
                                      "description": "Points contributed by country to the total score."
                                    },
                                    "document_number_match_type": {
                                      "type": "string",
                                      "description": "Result of document number 'Golden Key' evaluation.",
                                      "enum": [
                                        "MATCH",
                                        "NEUTRAL",
                                        "HARD_MISMATCH"
                                      ]
                                    },
                                    "document_number_effect": {
                                      "type": "string",
                                      "description": "Human-readable description of the document number effect on the score."
                                    },
                                    "total_score": {
                                      "type": "integer",
                                      "description": "Final weighted match score (0-100)."
                                    }
                                  }
                                },
                                "pep_matches": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "aliases": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "education": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "list_name": {
                                        "type": "string"
                                      },
                                      "publisher": {
                                        "type": "string"
                                      },
                                      "source_url": {
                                        "type": "string",
                                        "format": "uri"
                                      },
                                      "description": {
                                        "type": "string"
                                      },
                                      "matched_name": {
                                        "type": "string"
                                      },
                                      "pep_position": {
                                        "type": "string"
                                      },
                                      "date_of_birth": {
                                        "type": "string"
                                      },
                                      "other_sources": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "place_of_birth": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                },
                                "linked_entities": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "name": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "active": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "status": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "details": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "relation": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  }
                                },
                                "warning_matches": {
                                  "type": "array",
                                  "description": "List of warning and regulatory enforcement matches. Includes entries from categories: Warning, SIP, Warnings and Regulatory Enforcement, Fitness and Probity, SIE, and Insolvency.",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "list_name": {
                                        "type": "string",
                                        "description": "Name of the warning list publisher"
                                      },
                                      "matched_name": {
                                        "type": "string",
                                        "description": "Name matched in the warning list"
                                      },
                                      "description": {
                                        "type": "string",
                                        "description": "Description of the warning entry"
                                      },
                                      "publisher": {
                                        "type": "string",
                                        "description": "Publisher or source of the warning"
                                      },
                                      "source_url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "URL to the source of the warning"
                                      },
                                      "other_sources": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Additional source URLs"
                                      },
                                      "countries": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "nullable": true,
                                        "description": "Countries associated with the warning"
                                      },
                                      "created_at": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Date the warning entry was created"
                                      },
                                      "updated_at": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Date the warning entry was last updated"
                                      },
                                      "additional_data": {
                                        "type": "object",
                                        "description": "Additional data from the warning source. May contain a `data` object with `case_details` array.",
                                        "properties": {
                                          "data": {
                                            "type": "object",
                                            "properties": {
                                              "case_details": {
                                                "type": "array",
                                                "description": "Details of warning cases associated with this match",
                                                "items": {
                                                  "type": "object",
                                                  "properties": {
                                                    "case_type": {
                                                      "type": "string",
                                                      "description": "Type of the warning case",
                                                      "enum": [
                                                        "Accusation",
                                                        "Arrest",
                                                        "Bribery",
                                                        "Criminal",
                                                        "Fraud",
                                                        "Illegal Fundraising",
                                                        "Non-conviction Terror",
                                                        "Proclaimed Offender",
                                                        "Regulatory Enforcement",
                                                        "Terrorism",
                                                        "Terrorism-related",
                                                        "Terrorism-related listing"
                                                      ]
                                                    }
                                                  }
                                                }
                                              }
                                            }
                                          }
                                        }
                                      }
                                    }
                                  }
                                },
                                "sanction_matches": {
                                  "type": "array",
                                  "description": "List of sanction list matches found for this entity.",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "list_name": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "nullable": true,
                                        "description": "Name(s) of the sanction list(s)"
                                      },
                                      "matched_name": {
                                        "type": "string",
                                        "description": "Name matched in the sanction list"
                                      },
                                      "description": {
                                        "type": "string",
                                        "description": "Description of the sanction entry"
                                      },
                                      "reason": {
                                        "type": "string",
                                        "nullable": true,
                                        "description": "Free-text reason why the entity was sanctioned. Joined from the sanction list's reason entries. Examples: 'Executive Order 13224 (Terrorism)', 'Support for actions undermining Ukraine's sovereignty', 'Listed due to national security concerns.'"
                                      },
                                      "source_url": {
                                        "type": "string",
                                        "format": "uri",
                                        "description": "URL to the source of the sanction"
                                      },
                                      "other_sources": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Additional source URLs"
                                      },
                                      "details": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Additional details about the sanction"
                                      },
                                      "legal_basis": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Legal basis for the sanction"
                                      },
                                      "listed_on": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "nullable": true,
                                        "description": "Date(s) when the entity was listed"
                                      },
                                      "sanction_list": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "nullable": true,
                                        "description": "Sanction list identifier(s)"
                                      },
                                      "sanction_program": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Sanction program(s) the entity is listed under"
                                      },
                                      "sanctioning_authority": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Authority/authorities that imposed the sanction"
                                      },
                                      "updated_on": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        },
                                        "description": "Date(s) when the sanction entry was last updated"
                                      },
                                      "additional_data": {
                                        "type": "object",
                                        "description": "Additional data from the sanction source not captured in the main fields"
                                      }
                                    }
                                  }
                                },
                                "adverse_media_details": {
                                  "type": "object",
                                  "properties": {
                                    "sentiment": {
                                      "type": "string"
                                    },
                                    "entity_type": {
                                      "type": "string"
                                    },
                                    "sentiment_score": {
                                      "type": "integer"
                                    },
                                    "adverse_keywords": {
                                      "type": "object",
                                      "additionalProperties": {
                                        "type": "integer"
                                      }
                                    }
                                  }
                                },
                                "adverse_media_matches": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "country": {
                                        "type": "string"
                                      },
                                      "summary": {
                                        "type": "string"
                                      },
                                      "headline": {
                                        "type": "string"
                                      },
                                      "sentiment": {
                                        "type": "string"
                                      },
                                      "thumbnail": {
                                        "type": "string",
                                        "format": "uri"
                                      },
                                      "source_url": {
                                        "type": "string",
                                        "format": "uri"
                                      },
                                      "author_name": {
                                        "type": "string",
                                        "nullable": true
                                      },
                                      "other_sources": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "adverse_keywords": {
                                        "type": "array",
                                        "items": {
                                          "type": "string"
                                        }
                                      },
                                      "sentiment_score": {
                                        "type": "integer"
                                      },
                                      "publication_date": {
                                        "type": "string",
                                        "format": "date-time"
                                      }
                                    }
                                  }
                                },
                                "additional_information": {
                                  "type": "object"
                                }
                              }
                            }
                          },
                          "score": {
                            "type": "number",
                            "format": "float",
                            "nullable": true,
                            "minimum": 0,
                            "maximum": 100,
                            "description": "Overall AML screening score — the highest risk score across all hits (float, 0-100). `null` until computed."
                          },
                          "screened_data": {
                            "type": "object",
                            "properties": {
                              "full_name": {
                                "type": "string"
                              },
                              "nationality": {
                                "type": "string"
                              },
                              "date_of_birth": {
                                "type": "string",
                                "format": "date"
                              },
                              "document_number": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          },
                          "is_ongoing_monitoring_enabled": {
                            "type": "boolean",
                            "description": "Whether AML ongoing monitoring is enabled for this screening. When `true`, the entity is re-screened periodically and any new hits update the report."
                          },
                          "next_ongoing_monitoring_bill_date": {
                            "type": "string",
                            "format": "date",
                            "nullable": true,
                            "description": "Date (YYYY-MM-DD) when this ongoing-monitoring subscription will next be billed. Computed as the date of the last ongoing-monitoring billing plus 365 days when `is_ongoing_monitoring_enabled = true`; otherwise `null`. This is a billing date, not a screening date - use `last_ongoing_screening_at` for that."
                          },
                          "last_ongoing_screening_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true,
                            "description": "When ongoing monitoring last completed a re-screening of this record, whether or not the result changed. `null` when the record has never been re-screened; it is never back-filled from the enablement or billing date."
                          },
                          "last_ongoing_screening_datasets_updated_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true,
                            "description": "The most recent AML dataset update date the provider reported at the time of that screening. `null` when the provider reported no dataset dates; never estimated."
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Within an AML screening this is typically `AML`, but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "ip_analyses": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of Device & IP Analysis reports** — always a JSON array, never a singular `ip_analysis` object. `null` until at least one IP-analysis step has produced data. Each item is the full report, including `node_id`, feature-level `status`, IP and geolocation data, device fingerprint, and `warnings[]`. Entries with duplicate `(node_id, ip_address, device_fingerprint)` are deduplicated server-side.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this Device & IP Analysis step in the workflow graph."
                          },
                          "status": {
                            "type": "string",
                            "description": "Feature-level status of this Device & IP Analysis entry. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`.",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ]
                          },
                          "device_brand": {
                            "type": "string",
                            "description": "Brand of the device used"
                          },
                          "device_model": {
                            "type": "string",
                            "description": "Model of the device used"
                          },
                          "browser_family": {
                            "type": "string",
                            "description": "Browser family used"
                          },
                          "os_family": {
                            "type": "string",
                            "description": "Operating system family"
                          },
                          "platform": {
                            "type": "string",
                            "description": "Platform type (mobile, desktop, etc)"
                          },
                          "device_fingerprint": {
                            "type": "string",
                            "nullable": true,
                            "description": "Unique device fingerprint identifier"
                          },
                          "ip_country": {
                            "type": "string",
                            "description": "Country detected from IP"
                          },
                          "ip_country_code": {
                            "type": "string",
                            "description": "Two-letter country code from IP"
                          },
                          "ip_state": {
                            "type": "string",
                            "description": "State/region detected from IP"
                          },
                          "ip_city": {
                            "type": "string",
                            "description": "City detected from IP"
                          },
                          "latitude": {
                            "type": "number",
                            "description": "Latitude coordinate of IP location"
                          },
                          "longitude": {
                            "type": "number",
                            "description": "Longitude coordinate of IP location"
                          },
                          "ip_address": {
                            "type": "string",
                            "description": "IP address"
                          },
                          "isp": {
                            "type": "string",
                            "nullable": true,
                            "description": "Internet Service Provider"
                          },
                          "organization": {
                            "type": "string",
                            "nullable": true,
                            "description": "Organization associated with IP"
                          },
                          "is_vpn_or_tor": {
                            "type": "boolean",
                            "description": "Whether IP is from VPN or Tor network"
                          },
                          "is_data_center": {
                            "type": "boolean",
                            "description": "Whether IP is from a data center"
                          },
                          "time_zone": {
                            "type": "string",
                            "description": "Time zone detected from IP"
                          },
                          "time_zone_offset": {
                            "type": "string",
                            "description": "Time zone offset"
                          },
                          "ip": {
                            "type": "object",
                            "description": "IP geolocation of this entry plus great-circle distances (km) to the ID document address and the POA document address. Distances are `null` when either side has no resolvable location.",
                            "properties": {
                              "location": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "latitude": {
                                    "type": "number",
                                    "example": 41.2706327
                                  },
                                  "longitude": {
                                    "type": "number",
                                    "example": 1.9770097
                                  }
                                },
                                "description": "Coordinates, or `null` when unavailable."
                              },
                              "distance_from_id_document": {
                                "type": "number",
                                "nullable": true,
                                "example": 23.4
                              },
                              "distance_from_poa_document": {
                                "type": "number",
                                "nullable": true,
                                "example": 12.3
                              }
                            }
                          },
                          "id_document": {
                            "type": "object",
                            "description": "Location extracted from the ID document address plus distances (km) to the IP geolocation and the POA document address. `location` is `null` when no document address could be geocoded.",
                            "properties": {
                              "location": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "latitude": {
                                    "type": "number",
                                    "example": 41.2706327
                                  },
                                  "longitude": {
                                    "type": "number",
                                    "example": 1.9770097
                                  }
                                },
                                "description": "Coordinates, or `null` when unavailable."
                              },
                              "distance_from_ip": {
                                "type": "number",
                                "nullable": true,
                                "example": 23.4
                              },
                              "distance_from_poa_document": {
                                "type": "number",
                                "nullable": true,
                                "example": 18.7
                              }
                            }
                          },
                          "poa_document": {
                            "type": "object",
                            "description": "Location extracted from the Proof of Address document plus distances (km) to the IP geolocation and the ID document address. `location` is `null` when the session has no POA step or the address could not be geocoded.",
                            "properties": {
                              "location": {
                                "type": "object",
                                "nullable": true,
                                "properties": {
                                  "latitude": {
                                    "type": "number",
                                    "example": 41.2706327
                                  },
                                  "longitude": {
                                    "type": "number",
                                    "example": 1.9770097
                                  }
                                },
                                "description": "Coordinates, or `null` when unavailable."
                              },
                              "distance_from_ip": {
                                "type": "number",
                                "nullable": true,
                                "example": 12.3
                              },
                              "distance_from_id_document": {
                                "type": "number",
                                "nullable": true,
                                "example": 18.7
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            }
                          },
                          "matches": {
                            "type": "array",
                            "description": "Cross-session matches found for this entry's IP address or device identity. Every match is another verification session in your application (`source` is always `session`) that shares the same value, always belonging to a different vendor user / `vendor_data` than the current session, capped at 5 per collector (`device_fingerprint` sums two independently capped collectors, so up to 10 entries are possible). Every item carries `match_source`, `confidence`, `match_mode`, `device_info` and `location_info`; the keys `recovery_similarity`, `tls_ja4_corroborated` and `recovery_gate_reason` are present only when `match_source` is `recovered_high`.",
                            "items": {
                              "type": "object",
                              "additionalProperties": false,
                              "properties": {
                                "session_id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "description": "Session ID of the matching session."
                                },
                                "session_number": {
                                  "type": "integer",
                                  "description": "Sequential number of the matching session."
                                },
                                "vendor_data": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "`vendor_data` of the matching session — always different from the current session's vendor user."
                                },
                                "verification_date": {
                                  "type": "string",
                                  "format": "date-time",
                                  "nullable": true,
                                  "description": "Creation date of the matching session (`YYYY-MM-DDTHH:MM:SSZ`)."
                                },
                                "match_type": {
                                  "type": "string",
                                  "enum": [
                                    "ip_address",
                                    "device_fingerprint"
                                  ],
                                  "description": "Whether the match was on IP address or device fingerprint"
                                },
                                "match_source": {
                                  "type": "string",
                                  "enum": [
                                    "ip_address",
                                    "persistent_id",
                                    "legacy_fp",
                                    "recovered_high"
                                  ],
                                  "description": "How this match was reached: `ip_address` (shared IP address — network co-location, not a device-identity claim), `persistent_id` (exact stored persistent device identifier), `legacy_fp` (legacy `didit-fp-*` device-fingerprint hash), or `recovered_high` (high-confidence fuzzy fingerprint-recovery hit). Lower-confidence recovery candidates surface as risk warnings only, never in this array."
                                },
                                "matched_value": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "The value that matched: the shared IP address, the persistent device identifier or legacy fingerprint hash, or — for `recovered_high` — the UUID of the recovered device."
                                },
                                "status": {
                                  "type": "string",
                                  "description": "Lifecycle status of the matching session."
                                },
                                "is_blocklisted": {
                                  "type": "boolean",
                                  "description": "Whether the matched value is on a blocklist. Currently always `false` for device/IP matches."
                                },
                                "api_service": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Standalone API service of the matching session; `null` for workflow sessions."
                                },
                                "source": {
                                  "type": "string",
                                  "enum": [
                                    "session"
                                  ],
                                  "description": "Always `session` for device/IP matches — every match is another verification session in your application."
                                },
                                "device_info": {
                                  "type": "object",
                                  "description": "Device details observed on the matching session.",
                                  "properties": {
                                    "device_brand": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "device_model": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "browser_family": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "os_family": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "platform": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "device_fingerprint": {
                                      "type": "string",
                                      "nullable": true
                                    }
                                  }
                                },
                                "location_info": {
                                  "type": "object",
                                  "description": "Network and geolocation details observed on the matching session.",
                                  "properties": {
                                    "ip_address": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "ip_country": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "ip_country_code": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "ip_state": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "ip_city": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "is_vpn_or_tor": {
                                      "type": "boolean"
                                    },
                                    "is_data_center": {
                                      "type": "boolean"
                                    }
                                  }
                                },
                                "confidence": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Server-side identification confidence, computed as `1 - P(false positive)`: `1.0` for deterministic matches (`persistent_id`, or hardware-rooted `recovered_high`), `0.5` for `legacy_fp`, `0.0` for `ip_address` (co-location only), and a corroboration-adjusted value below `1.0` for probabilistic recovered matches (higher when the TLS JA4 fingerprint and IP country independently agree)."
                                },
                                "match_mode": {
                                  "type": "string",
                                  "enum": [
                                    "deterministic",
                                    "probabilistic",
                                    "co_occurrence"
                                  ],
                                  "description": "Evidence class of the match: `deterministic` (exact stored or hardware-rooted identifier that cannot collide between physical devices), `probabilistic` (fuzzy fingerprint evidence), or `co_occurrence` (shared network only, no device-identity claim)."
                                },
                                "recovery_similarity": {
                                  "type": "number",
                                  "description": "Cosine similarity of the fingerprint-recovery match, rounded to 4 decimals. Present only when `match_source` is `recovered_high`."
                                },
                                "tls_ja4_corroborated": {
                                  "type": "boolean",
                                  "description": "Whether the TLS JA4 fingerprints of the two observations agree — a server-observed signal the browser cannot spoof. Present only when `match_source` is `recovered_high`."
                                },
                                "recovery_gate_reason": {
                                  "type": "string",
                                  "description": "Why the recovery match passed the false-positive hard gate: `hardware_root_match` (a hardware-rooted device identifier matched exactly) or, on configurations that admit probe-only evidence, `exact_composite_plus_<n>_families` / `very_high_similarity_plus_<n>_families`. Present only when `match_source` is `recovered_high`."
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "database_validations": {
                      "type": "array",
                      "nullable": true,
                      "description": "**Array of Database Validation reports** — always a JSON array, never a singular `database_validation` object. `null` until at least one DB validation step has produced data. Each item is the full report, including `node_id`, feature-level `status`, `screened_data`, the per-service `validations[]` (each with its registry `source_data`), and `warnings[]`. The `screened_data` and `source_data` fields vary by country:\n\n**ARG (Argentina)**: screened_data: {document_number, selfie, gender, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name, date_of_birth, date_of_death, tax_id, tax_id_type, face_match_score, sit_1_since, banks, last_position, highest_position, rejected_checks}. Uses RENAPER biometric face-match validation. Gender is auto-inferred from face analysis or given name when not present in the document (e.g., driver licenses)\n\n**BOL (Bolivia)**: screened_data: {document_number, date_of_birth, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name, date_of_birth, gender}\n\n**BRA (Brazil)**: screened_data: {tax_number, first_name, last_name, date_of_birth}. source_data always includes {identification_number, first_name, last_name, date_of_birth, lgpd_minor, minor_under_18, minor_under_16} for successful CPF matches. Successful adult lookups set those flags to false. The Receita Federal Consulta CPF service may return HTTP 422 (minor under 18) or 451 (under 16) with LGPD-withheld data; in those cases source_data sets the minor flags to true as appropriate, includes the upstream HTTP status, and field-level validation is no_match. See the Brazil section of the Database Validation Outcome Codes reference for the full code list.\n\n**CHL (Chile)**: screened_data: {personal_number, first_name, last_name, date_of_birth}. source_data: {identification_number, first_name, last_name, date_of_birth, gender}\n\n**COL (Colombia)**: screened_data: {document_number, document_type, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name, date_of_birth, document_type}\n\n**CRI (Costa Rica)**: screened_data: {personal_number, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name}\n\n**DOM (Dominican Republic)**: screened_data: {personal_number}. source_data: {identification_number} (returns valid/invalid only)\n\n**ECU (Ecuador)**: screened_data: {personal_number, first_name, last_name}. source_data: {identification_number, first_name, last_name, street, formatted_address, gender, nationality, education, marital_status, spouse, mother_name, father_name, profession}\n\n**ESP (Spain)**: screened_data: {personal_number, document_type, expiration_date, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name, document_type, expiration_date}\n\n**GTM (Guatemala)**: screened_data: {document_number, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name}\n\n**HND (Honduras)**: screened_data: {document_number, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name}\n\n**MEX (Mexico)**: screened_data: {personal_number (CURP), first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name, date_of_birth, gender, nationality, curp_status, state_of_birth, doc_probatorio, registration_year, registration_state, registration_municipality, num_acta, crip, issuing_state_code, foreign_registry_number, folio_carta, folio_certificado}. Uses the RENAPO civil registry. A separate INE validity-check service is also available for MEX as an additional one-by-one validation.\n\n**PAN (Panama)**: screened_data: {personal_number, selfie}. source_data: {identification_number}. Uses SIB biometric validation\n\n**PER (Peru)**: screened_data: {personal_number (DNI), first_name, last_name}. source_data: {identification_number, first_name, last_name, paternal_name, maternal_name, verification_number, verification_letter}\n\n**PRY (Paraguay)**: screened_data: {document_number, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name}\n\n**SLV (El Salvador)**: screened_data: {document_number, date_of_birth, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name}\n\n**URY (Uruguay)**: screened_data: {personal_number, date_of_birth, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name}\n\n**VEN (Venezuela)**: screened_data: {document_number, first_name, last_name}. source_data: {identification_number, first_name, last_name, full_name, gender, date_of_birth, document_type}",
                      "items": {
                        "type": "object",
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Unique identifier for this database validation step in the workflow graph."
                          },
                          "issuing_state": {
                            "type": "string",
                            "description": "ISO 3166-1 alpha-3 code of the country whose government/registry sources were queried (e.g. `BRA`, `MEX`, `ESP`, `NGA`, `IDN`). Database Validation covers 60+ countries across the Americas, Europe, Africa, the Middle East and Asia-Pacific, plus global multi-country sources — coverage expands regularly, so treat the value as an open set rather than a fixed enum."
                          },
                          "validation_type": {
                            "type": "string",
                            "enum": [
                              "one_by_one",
                              "two_by_two",
                              "not_enabled"
                            ],
                            "description": "How the result was corroborated: `one_by_one` (single-service outcome), `two_by_two` (two or more distinct services independently full-matched the identification number), or `not_enabled` (persisted when no service produced a usable match). The value is never `null`. Dedicated biometric 2x2 validation modes are currently available for `ECU` and `PER`."
                          },
                          "screened_data": {
                            "type": "object",
                            "description": "The input data used for validation. Fields vary by country — see the Database Validation docs (`/core-technology/database-validation/overview`) for country-specific formats.",
                            "properties": {
                              "last_name": {
                                "type": "string"
                              },
                              "first_name": {
                                "type": "string"
                              },
                              "tax_number": {
                                "type": "string",
                                "description": "Brazil: CPF (11 digits)"
                              },
                              "personal_number": {
                                "type": "string",
                                "description": "Chile: RUT, DOM: Cédula (11 digits), ECU: Cédula (10 digits), ESP: DNI/NIE, MEX: CURP (18 chars), PER: DNI (8 digits), URY: CI"
                              },
                              "document_number": {
                                "type": "string",
                                "description": "ARG: DNI, BOL: CI, COL: Cédula, GTM: DPI, HND: DNI, PAN: Cédula, PRY: CI, SLV: DUI, VEN: Cédula"
                              },
                              "date_of_birth": {
                                "type": "string",
                                "format": "date"
                              },
                              "document_type": {
                                "type": "string",
                                "description": "COL: CC/CE/TI/NIT, ESP: ID/PASSPORT"
                              },
                              "expiration_date": {
                                "type": "string",
                                "format": "date",
                                "description": "Required for ESP"
                              }
                            }
                          },
                          "validations": {
                            "type": "array",
                            "description": "One entry per registry service that returned a validation payload. Each entry identifies the service (`service_id`, `service_name`) and carries the per-field `validation` comparison, the service `outcome_code` / `outcome_detail` when reported, and the normalised registry record in `source_data`.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "service_id": {
                                  "type": "string",
                                  "description": "Identifier of the registry service that produced this validation result.",
                                  "example": "bra_cpf"
                                },
                                "service_name": {
                                  "type": "string",
                                  "description": "Human-readable name of the registry service.",
                                  "example": "Brazil - CPF status check"
                                },
                                "validation": {
                                  "type": "object",
                                  "description": "The results of the field validations.",
                                  "properties": {
                                    "full_name": {
                                      "type": "string",
                                      "description": "Match result for full name (e.g., 'full_match', 'partial_match', 'no_match')."
                                    },
                                    "date_of_birth": {
                                      "type": "string",
                                      "description": "Match result for date of birth."
                                    },
                                    "identification_number": {
                                      "type": "string",
                                      "description": "Match result for identification number."
                                    }
                                  }
                                },
                                "outcome_code": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Machine-readable outcome of the registry lookup (e.g. `MATCH`, `NO_MATCH`, `PARTIAL_MATCH`, `INCONCLUSIVE`, source-specific codes). Present when the service reports one."
                                },
                                "outcome_detail": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Human-readable explanation of `outcome_code`, when provided by the service."
                                },
                                "source_data": {
                                  "type": "object",
                                  "description": "The data returned from the government database. Common fields: identification_number, first_name, last_name, full_name, date_of_birth, gender. Additional fields by country: BRA always includes lgpd_minor, minor_under_18, and minor_under_16 on successful CPF matches; it also includes the upstream HTTP status when CPF data is withheld under LGPD (HTTP 422/451). ECU adds street, formatted_address, nationality, education, marital_status, spouse, mother_name, father_name, profession. PER adds paternal_name, maternal_name, verification_number, verification_letter. ESP adds document_type, expiration_date. VEN/COL add document_type.",
                                  "additionalProperties": true
                                }
                              }
                            }
                          },
                          "errors": {
                            "type": "array",
                            "description": "Errors returned by registry services while validating, each tagged with the `service_id` that produced it. **This key is omitted entirely when there are no errors.**",
                            "items": {
                              "type": "object",
                              "description": "The upstream service's error object spread as-is — its keys vary by service (commonly a message/code and any provider-specific details) — plus `service_id` identifying the service that errored.",
                              "properties": {
                                "service_id": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Identifier of the registry service that errored."
                                }
                              },
                              "additionalProperties": true
                            }
                          },
                          "match_type": {
                            "type": "string",
                            "enum": [
                              "no_match",
                              "partial_match",
                              "full_match"
                            ],
                            "nullable": true,
                            "description": "The aggregate match outcome across the queried services. `null` until the validation has been evaluated."
                          },
                          "status": {
                            "type": "string",
                            "description": "Feature-level status of this database validation. Independent of the top-level session `status` — a session can reach its overall decision while an individual feature stays `In Review`.",
                            "enum": [
                              "Not Finished",
                              "Approved",
                              "Declined",
                              "In Review",
                              "Resub Requested"
                            ]
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "feature": {
                                  "type": "string",
                                  "enum": [
                                    "ID_VERIFICATION",
                                    "NFC",
                                    "LIVENESS",
                                    "FACEMATCH",
                                    "PROOF_OF_ADDRESS",
                                    "PHONE",
                                    "EMAIL",
                                    "AML",
                                    "LOCATION",
                                    "DATABASE_VALIDATION",
                                    "QUESTIONNAIRE",
                                    "DOCUMENT_AI",
                                    "KYB_REGISTRY",
                                    "KYB_DOCUMENTS",
                                    "KYB_KEY_PEOPLE"
                                  ],
                                  "description": "The feature that generated this warning. The value identifies the feature block the warning belongs to. Each module's warnings array typically uses the value matching its module (e.g. `PHONE` inside `phone_verifications[].warnings`), but the enum above is authoritative across all feature warnings on the decision payload."
                                },
                                "risk": {
                                  "type": "string"
                                },
                                "additional_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "log_type": {
                                  "type": "string"
                                },
                                "short_description": {
                                  "type": "string"
                                },
                                "long_description": {
                                  "type": "string"
                                },
                                "node_id": {
                                  "type": "string",
                                  "description": "The workflow graph node ID that generated this warning"
                                }
                              }
                            },
                            "description": "Warnings related to the database validation."
                          }
                        }
                      }
                    },
                    "reviews": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user": {
                            "type": "string",
                            "description": "Who performed the review. Usually the console reviewer's identifier (their email), but the value is `\"API Client\"` for status updates made with an API key and `\"Unknown\"` when no actor could be resolved — so do not parse this field as an email address."
                          },
                          "new_status": {
                            "type": "string"
                          },
                          "comment": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Timestamp at which the session was created (ISO 8601, UTC)."
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "Timestamp at which this session is scheduled to expire. Set on User Verification (KYC) sessions when an expiration was configured at creation time (or once `Approved` status triggers KYC expiry computation). `null` for sessions without a configured expiration, and for kinds that do not use expiry (e.g. Business Verification (KYB) sessions that never received an `expires_at`)."
                    },
                    "registry_checks": {
                      "type": "array",
                      "nullable": true,
                      "description": "Company registry checks. Present only when `session_kind = business`. Each item wraps the full company-registry payload.",
                      "items": {
                        "type": "object",
                        "description": "One company registry check — the full company-registry payload enriched with ownership structure and warnings. Present only when `session_kind = business`.",
                        "properties": {
                          "status": {
                            "type": "string",
                            "description": "Feature lifecycle status."
                          },
                          "node_id": {
                            "type": "string",
                            "nullable": true
                          },
                          "data_resolved": {
                            "type": "boolean"
                          },
                          "company": {
                            "type": "object",
                            "description": "Full registry payload for the company (registry record merged with any user-provided or console-edited data).",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "node_id": {
                                "type": "string",
                                "nullable": true
                              },
                              "status": {
                                "type": "string"
                              },
                              "registry_status": {
                                "type": "string",
                                "nullable": true
                              },
                              "data_resolved": {
                                "type": "boolean"
                              },
                              "company_name": {
                                "type": "string"
                              },
                              "registration_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "country_code": {
                                "type": "string",
                                "description": "Country of incorporation (ISO 3166-1 alpha-2, e.g. `GB`, `DE`, `US`)."
                              },
                              "region": {
                                "type": "string",
                                "nullable": true,
                                "description": "ISO 3166-2 subdivision code when applicable (e.g. `CA`, `NY` for US states)."
                              },
                              "company_type": {
                                "type": "string",
                                "nullable": true
                              },
                              "incorporation_date": {
                                "type": "string",
                                "format": "date",
                                "nullable": true
                              },
                              "registered_address": {
                                "type": "string",
                                "nullable": true
                              },
                              "tax_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "risk_level": {
                                "type": "string",
                                "enum": [
                                  "LOW",
                                  "MEDIUM",
                                  "HIGH"
                                ],
                                "nullable": true
                              },
                              "verification_status": {
                                "type": "string",
                                "nullable": true
                              },
                              "is_from_registry": {
                                "type": "boolean"
                              },
                              "fetch_status": {
                                "type": "string",
                                "nullable": true
                              },
                              "alternative_names": {
                                "type": "string",
                                "nullable": true,
                                "description": "Alternative, trading, former or original-language company names as text, when reported."
                              },
                              "nature_of_business": {
                                "type": "string",
                                "nullable": true
                              },
                              "registered_capital": {
                                "type": "string",
                                "nullable": true
                              },
                              "registered_capital_amount": {
                                "type": "string",
                                "format": "decimal",
                                "nullable": true,
                                "description": "Registered/share capital amount as a decimal string (e.g. `\"100.00\"`), parsed from the registry filing. `null` when not available."
                              },
                              "registered_capital_currency": {
                                "type": "string",
                                "nullable": true,
                                "description": "ISO 4217 currency code of `registered_capital_amount` (e.g. `\"GBP\"`). `null` when not available."
                              },
                              "website": {
                                "type": "string",
                                "nullable": true
                              },
                              "email": {
                                "type": "string",
                                "format": "email",
                                "nullable": true
                              },
                              "phone": {
                                "type": "string",
                                "nullable": true
                              },
                              "legal_entity_identifier": {
                                "type": "string",
                                "nullable": true
                              },
                              "location_of_registration": {
                                "type": "string",
                                "nullable": true
                              },
                              "vat_number": {
                                "type": "string",
                                "nullable": true,
                                "description": "EU VAT number, when collected during the hosted registry step or edited afterwards."
                              },
                              "vat_validation_status": {
                                "type": "string",
                                "enum": [
                                  "valid",
                                  "invalid",
                                  "format_valid",
                                  "invalid_format",
                                  "could_not_validate",
                                  "not_applicable"
                                ],
                                "description": "Result of validating the VAT number or, when there is none, the `tax_number`, at registry submit. `valid` / `invalid`: decided by the official registry of the country (EU VIES, Norway, Switzerland, Brazil, Colombia, Costa Rica, Ecuador, Paraguay; Poland also by its domestic VAT register). `format_valid` / `invalid_format`: decided by the country's format and check-digit rules where no registry can be queried. `could_not_validate`: the registry was unavailable. `not_applicable`: no number, a country without registry or rules, or a sandbox session."
                              },
                              "vat_validated_number": {
                                "type": "string",
                                "nullable": true,
                                "description": "The number that was checked, as the source knows it (for example the VAT number derived from a French SIREN or a Dutch RSIN). `null` when no check ran."
                              },
                              "vat_validation_source": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "eu_vies",
                                  "pl_vat_white_list",
                                  "no_brreg",
                                  "ch_uid_register",
                                  "br_receita_federal",
                                  "co_rues",
                                  "cr_hacienda",
                                  "ec_sri",
                                  "py_dnit",
                                  "format_rules",
                                  null
                                ],
                                "description": "The source that decided `vat_validation_status`: an official registry, or `format_rules`. `null` when no check ran."
                              },
                              "vat_validated_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Name registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                              },
                              "vat_validated_address": {
                                "type": "string",
                                "nullable": true,
                                "description": "Address registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                              },
                              "vat_checked_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "Timestamp of the check. `null` when no check ran."
                              },
                              "financial_summary": {
                                "type": "object",
                                "nullable": true
                              },
                              "officers": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "uuid": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "name": {
                                      "type": "string"
                                    },
                                    "designation": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "role": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "nationality": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "is_active": {
                                      "type": "boolean"
                                    },
                                    "kyc_status": {
                                      "type": "string",
                                      "enum": [
                                        "Approved",
                                        "Declined",
                                        "Pending"
                                      ],
                                      "nullable": true
                                    },
                                    "kyc_session_url": {
                                      "type": "string",
                                      "format": "uri",
                                      "nullable": true
                                    },
                                    "first_name": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Given name when explicitly reported by the registry; not inferred from the full name."
                                    },
                                    "last_name": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Family name when explicitly reported by the registry."
                                    },
                                    "address": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Officer address reported by the registry."
                                    },
                                    "appointment_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Date the officer was appointed.",
                                      "format": "date"
                                    },
                                    "termination_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Date the appointment ended, when reported.",
                                      "format": "date"
                                    },
                                    "date_of_birth": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Complete registry-reported birth date. Null when only a birth year or month is known.",
                                      "format": "date"
                                    },
                                    "date_of_birth_year": {
                                      "type": "integer",
                                      "nullable": true,
                                      "minimum": 1,
                                      "maximum": 9999,
                                      "description": "Registry-reported birth year, including when the full date is unavailable."
                                    },
                                    "date_of_birth_month": {
                                      "type": "integer",
                                      "nullable": true,
                                      "minimum": 1,
                                      "maximum": 12,
                                      "description": "Registry-reported birth month. Null when only the year is known."
                                    }
                                  }
                                }
                              },
                              "beneficial_owners": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "uuid": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "name": {
                                      "type": "string"
                                    },
                                    "first_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "last_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "entity_type": {
                                      "type": "string",
                                      "enum": [
                                        "person",
                                        "company"
                                      ]
                                    },
                                    "roles": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "ownership_min_shares": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Lower bound of the ownership percentage as reported by the registry. Free-form string (e.g. `\"25.00\"`, `\"50\"`); use `effective_ownership_percent` for a parsed numeric value."
                                    },
                                    "ownership_max_shares": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Upper bound of the ownership percentage as reported by the registry. Free-form string; use `effective_ownership_percent` for a parsed numeric value."
                                    },
                                    "is_active": {
                                      "type": "boolean"
                                    },
                                    "kyc_status": {
                                      "type": "string",
                                      "enum": [
                                        "Approved",
                                        "Declined",
                                        "Pending"
                                      ],
                                      "nullable": true
                                    },
                                    "kyc_session_url": {
                                      "type": "string",
                                      "format": "uri",
                                      "nullable": true
                                    },
                                    "effective_ownership_percent": {
                                      "type": "number",
                                      "nullable": true
                                    },
                                    "company_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "registration_number": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "country_of_birth": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "email": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "nationality": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "designation": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "voting_min_shares": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "voting_max_shares": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "date_of_birth": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Complete birth date when reported.",
                                      "format": "date"
                                    },
                                    "appointment_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Appointment date when reported.",
                                      "format": "date"
                                    },
                                    "shareholding": {
                                      "$ref": "#/components/schemas/KYBRegistryShareholding"
                                    }
                                  }
                                }
                              },
                              "addresses": {
                                "type": "array",
                                "nullable": true,
                                "description": "Every address the registry states, one canonical shape. Null when it states none.",
                                "items": {
                                  "$ref": "#/components/schemas/KYBRegistryAddress"
                                }
                              },
                              "industries": {
                                "type": "array",
                                "nullable": true,
                                "description": "The activities the registry classifies the company under, one canonical shape. Null when it states none.",
                                "items": {
                                  "$ref": "#/components/schemas/KYBRegistryIndustry"
                                }
                              },
                              "accounts": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Registry filing dates, when available. Annual returns and general meetings use last_annual_return_date and last_agm_date; they are distinct from financial accounts."
                              },
                              "registry_data": {
                                "type": "object",
                                "description": "Raw record returned by the registry source, kept for reviewers. Its shape differs by country and source and is not a stable contract: read the canonical fields (`addresses`, `industries`, `ownership`, `beneficial_owners[].shareholding`) instead."
                              },
                              "user_provided_data": {
                                "type": "object",
                                "description": "Data confirmed or edited by the end user."
                              },
                              "confirmed_by_user_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                              },
                              "last_console_edit_at": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true
                              },
                              "is_editable": {
                                "type": "boolean"
                              },
                              "ownership": {
                                "$ref": "#/components/schemas/KYBRegistryOwnership"
                              },
                              "registry_tier": {
                                "type": "string",
                                "nullable": true,
                                "description": "The registry tier the workflow ordered: `basic`, `shareholders` or `ubo`. Also in `ownership.tier_requested`."
                              },
                              "registry_tier_delivered": {
                                "type": "string",
                                "nullable": true,
                                "description": "The tier the registry delivered and that is billed. Also in `ownership.tier_delivered`."
                              },
                              "registry_ownership_status": {
                                "type": "string",
                                "nullable": true,
                                "description": "`not_requested`, `pending`, `delivered` or `unavailable`. Also in `ownership.status`."
                              }
                            }
                          },
                          "ownership_structure": {
                            "type": "object",
                            "description": "Raw ownership snapshot kept for reviewers; its shape differs by registry source and is not a stable contract. Read `company.beneficial_owners` and `company.ownership` instead."
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        }
                      }
                    },
                    "key_people_checks": {
                      "type": "array",
                      "nullable": true,
                      "description": "Aggregate key-people checks. Present only when `session_kind = business`. Each item uses the two-bucket shape (`registry`, `submitted`, `ubo_kyc_summary`).",
                      "items": {
                        "type": "object",
                        "description": "Aggregate check over the company's officers + UBOs. Uses the `registry` / `submitted` shape. Present only when session_kind = business.",
                        "properties": {
                          "status": {
                            "type": "string"
                          },
                          "node_id": {
                            "type": "string",
                            "nullable": true
                          },
                          "registry": {
                            "type": "object",
                            "description": "Parties discovered via the registry check.",
                            "properties": {
                              "officers": {
                                "type": "array",
                                "description": "Officers discovered via the registry check, each enriched with the status of any child KYC session and AML screening spawned for them.",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "uuid": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "Officer's full name as recorded in the registry."
                                    },
                                    "designation": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Free-text designation from the registry (e.g. `Director`, `Company Secretary`)."
                                    },
                                    "role": {
                                      "type": "string",
                                      "enum": [
                                        "director",
                                        "non_executive_director",
                                        "secretary",
                                        "chairman",
                                        "ubo",
                                        "shareholder",
                                        "representative",
                                        "founder",
                                        "legal_advisor",
                                        "authorized_signatory",
                                        "trustee",
                                        "beneficiary",
                                        "settlor",
                                        "protector",
                                        "company_officer",
                                        "investor",
                                        "other"
                                      ],
                                      "description": "Normalized officer role."
                                    },
                                    "nationality": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "appointment_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Date the officer was appointed.",
                                      "format": "date"
                                    },
                                    "termination_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Date the appointment ended, when reported.",
                                      "format": "date"
                                    },
                                    "is_active": {
                                      "type": "boolean"
                                    },
                                    "address": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Officer address reported by the registry."
                                    },
                                    "aml_status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Finished",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Resub Requested"
                                      ],
                                      "nullable": true,
                                      "description": "Status of the AML screening run for this officer. `null` when no AML screening was run."
                                    },
                                    "kyc_status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Started",
                                        "In Progress",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Expired",
                                        "Abandoned",
                                        "Kyc Expired",
                                        "Resubmitted",
                                        "Awaiting User"
                                      ],
                                      "nullable": true,
                                      "description": "Raw lifecycle status of the child KYC session spawned for this officer. This is the full session status enum (not a reduced Approved/Declined/Pending set). `null` when no child KYC session exists."
                                    },
                                    "kyc_session_url": {
                                      "type": "string",
                                      "format": "uri",
                                      "nullable": true,
                                      "description": "Shareable URL of the child KYC session. `null` when no child session exists."
                                    },
                                    "kyc_session_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Session id of the child KYC session. Pass it to this same decision endpoint to fetch the person's full KYC report. `null` when no child session exists."
                                    },
                                    "verification_workflow_type": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Base workflow type of the child session's workflow (e.g. `kyc`). `null` for graph-based workflows or when no child session exists."
                                    },
                                    "verification_workflow_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Workflow id used by the child session. `null` when no child session exists."
                                    },
                                    "verification_workflow_label": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Human-readable label of the child session's workflow. `null` when unset."
                                    },
                                    "verification_workflow_features": {
                                      "type": "array",
                                      "nullable": true,
                                      "description": "Per-feature progress of the child verification session, e.g. `[{\"feature\": \"ID_VERIFICATION\", \"status\": \"Approved\"}]`. `null` when the child session has no resolvable feature list.",
                                      "items": {
                                        "type": "object",
                                        "properties": {
                                          "feature": {
                                            "type": "string",
                                            "description": "Feature display name (e.g. `ID_VERIFICATION`, `LIVENESS`, `AML`)."
                                          },
                                          "status": {
                                            "type": "string",
                                            "enum": [
                                              "Not Finished",
                                              "Approved",
                                              "Declined",
                                              "In Review",
                                              "Resub Requested"
                                            ],
                                            "description": "Feature-level status inside the child session."
                                          }
                                        }
                                      }
                                    },
                                    "didit_internal_id": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Stable internal identifier of the verified individual behind the child session — useful for cross-session linking. `null` when no child session exists or the user has not been resolved yet."
                                    },
                                    "kyc_document_type": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Document type presented in the child KYC session (e.g. `P`, `ID`, `DL`). `null` until the child session has an ID verification result."
                                    },
                                    "kyc_nationality": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Nationality extracted from the document in the child KYC session. `null` until available."
                                    },
                                    "kyc_liveness_passed": {
                                      "type": "boolean",
                                      "nullable": true,
                                      "description": "Whether the child KYC session's liveness check passed. `null` when no liveness check has run."
                                    },
                                    "kyc_verified_at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "nullable": true,
                                      "description": "When the child KYC session reached `Approved`. `null` while the child session has any other status."
                                    },
                                    "kyc_aml_categories": {
                                      "type": "object",
                                      "nullable": true,
                                      "description": "Per-category summary derived from the person's AML hits. `null` when there are no hits.",
                                      "properties": {
                                        "sanctions": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        },
                                        "pep": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        },
                                        "adverse_media": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        },
                                        "warnings": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        }
                                      }
                                    },
                                    "kyc_notification_sent_at": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "ISO 8601 timestamp of the last verification-invite notification sent for this person's child session. `null` when none was sent."
                                    },
                                    "first_name": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Given name when explicitly reported by the registry; not inferred from the full name."
                                    },
                                    "last_name": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Family name when explicitly reported by the registry."
                                    },
                                    "date_of_birth": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Complete registry-reported birth date. Null when only a birth year or month is known.",
                                      "format": "date"
                                    },
                                    "date_of_birth_year": {
                                      "type": "integer",
                                      "nullable": true,
                                      "minimum": 1,
                                      "maximum": 9999,
                                      "description": "Registry-reported birth year, including when the full date is unavailable."
                                    },
                                    "date_of_birth_month": {
                                      "type": "integer",
                                      "nullable": true,
                                      "minimum": 1,
                                      "maximum": 12,
                                      "description": "Registry-reported birth month. Null when only the year is known."
                                    }
                                  }
                                }
                              },
                              "beneficial_owners": {
                                "type": "array",
                                "description": "Beneficial owners discovered via the registry check, each enriched with the status of any child KYC session and AML screening spawned for them.",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "uuid": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "Beneficial owner's full name (or company name for corporate UBOs)."
                                    },
                                    "first_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "last_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "date_of_birth": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Complete birth date when reported.",
                                      "format": "date"
                                    },
                                    "country_of_birth": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "email": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "company_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "registration_number": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "entity_type": {
                                      "type": "string",
                                      "enum": [
                                        "person",
                                        "company"
                                      ]
                                    },
                                    "nationality": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "designation": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "roles": {
                                      "type": "array",
                                      "description": "Role names held by this owner, e.g. `[\"ubo\", \"shareholder\"]`.",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "ownership_min_shares": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Lower bound of the ownership percentage as reported by the registry. Free-form string (e.g. `\"25\"`, `\"25-50%\"`); use `effective_ownership_percent` for a parsed numeric value."
                                    },
                                    "ownership_max_shares": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Upper bound of the ownership percentage as reported by the registry. Free-form string; use `effective_ownership_percent` for a parsed numeric value."
                                    },
                                    "is_active": {
                                      "type": "boolean"
                                    },
                                    "aml_status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Finished",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Resub Requested"
                                      ],
                                      "nullable": true,
                                      "description": "Status of the AML screening run for this beneficial owner. `null` when no AML screening was run."
                                    },
                                    "kyc_status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Started",
                                        "In Progress",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Expired",
                                        "Abandoned",
                                        "Kyc Expired",
                                        "Resubmitted",
                                        "Awaiting User"
                                      ],
                                      "nullable": true,
                                      "description": "Raw lifecycle status of the child KYC session spawned for this beneficial owner. This is the full session status enum (not a reduced Approved/Declined/Pending set). `null` when no child KYC session exists."
                                    },
                                    "kyc_session_url": {
                                      "type": "string",
                                      "format": "uri",
                                      "nullable": true,
                                      "description": "Shareable URL of the child KYC session. `null` when no child session exists."
                                    },
                                    "kyc_session_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Session id of the child KYC session. Pass it to this same decision endpoint to fetch the person's full KYC report. `null` when no child session exists."
                                    },
                                    "verification_workflow_type": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Base workflow type of the child session's workflow (e.g. `kyc`). `null` for graph-based workflows or when no child session exists."
                                    },
                                    "verification_workflow_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Workflow id used by the child session. `null` when no child session exists."
                                    },
                                    "verification_workflow_label": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Human-readable label of the child session's workflow. `null` when unset."
                                    },
                                    "verification_workflow_features": {
                                      "type": "array",
                                      "nullable": true,
                                      "description": "Per-feature progress of the child verification session, e.g. `[{\"feature\": \"ID_VERIFICATION\", \"status\": \"Approved\"}]`. `null` when the child session has no resolvable feature list.",
                                      "items": {
                                        "type": "object",
                                        "properties": {
                                          "feature": {
                                            "type": "string",
                                            "description": "Feature display name (e.g. `ID_VERIFICATION`, `LIVENESS`, `AML`)."
                                          },
                                          "status": {
                                            "type": "string",
                                            "enum": [
                                              "Not Finished",
                                              "Approved",
                                              "Declined",
                                              "In Review",
                                              "Resub Requested"
                                            ],
                                            "description": "Feature-level status inside the child session."
                                          }
                                        }
                                      }
                                    },
                                    "didit_internal_id": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Stable internal identifier of the verified individual behind the child session — useful for cross-session linking. `null` when no child session exists or the user has not been resolved yet."
                                    },
                                    "kyc_document_type": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Document type presented in the child KYC session (e.g. `P`, `ID`, `DL`). `null` until the child session has an ID verification result."
                                    },
                                    "kyc_nationality": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Nationality extracted from the document in the child KYC session. `null` until available."
                                    },
                                    "kyc_liveness_passed": {
                                      "type": "boolean",
                                      "nullable": true,
                                      "description": "Whether the child KYC session's liveness check passed. `null` when no liveness check has run."
                                    },
                                    "kyc_verified_at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "nullable": true,
                                      "description": "When the child KYC session reached `Approved`. `null` while the child session has any other status."
                                    },
                                    "kyc_aml_categories": {
                                      "type": "object",
                                      "nullable": true,
                                      "description": "Per-category summary derived from the person's AML hits. `null` when there are no hits.",
                                      "properties": {
                                        "sanctions": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        },
                                        "pep": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        },
                                        "adverse_media": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        },
                                        "warnings": {
                                          "type": "string",
                                          "enum": [
                                            "match",
                                            "clear"
                                          ]
                                        }
                                      }
                                    },
                                    "kyc_notification_sent_at": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "ISO 8601 timestamp of the last verification-invite notification sent for this person's child session. `null` when none was sent."
                                    },
                                    "child_beneficial_owners": {
                                      "type": "array",
                                      "description": "For corporate UBOs: the owning entity's own beneficial owners, as raw objects extracted from the registry. Empty array when not applicable.",
                                      "items": {
                                        "type": "object"
                                      }
                                    },
                                    "effective_ownership_percent": {
                                      "type": "number",
                                      "nullable": true,
                                      "description": "Parsed numeric ownership percentage — the max bound when available, otherwise the min bound. `null` when neither bound could be parsed."
                                    },
                                    "voting_min_shares": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "voting_max_shares": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "appointment_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Appointment date when reported.",
                                      "format": "date"
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "submitted": {
                            "type": "object",
                            "description": "Parties submitted by the business admin during the Key People flow (BusinessParty rows where source=USER).",
                            "properties": {
                              "parties": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "description": "Party submitted by the business admin via the Key People flow (source=USER).",
                                  "properties": {
                                    "uuid": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "entity_type": {
                                      "type": "string",
                                      "enum": [
                                        "person",
                                        "company"
                                      ]
                                    },
                                    "source": {
                                      "type": "string",
                                      "enum": [
                                        "USER"
                                      ],
                                      "description": "Always `USER` here — this bucket only contains parties entered or confirmed by the end user in the Key People flow (registry-discovered people appear under `registry`)."
                                    },
                                    "name": {
                                      "type": "string"
                                    },
                                    "first_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "last_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "company_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "registration_number": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "email": {
                                      "type": "string",
                                      "format": "email",
                                      "nullable": true
                                    },
                                    "nationality": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Nationality for persons; country of incorporation for company parties."
                                    },
                                    "phone_number": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "date_of_birth": {
                                      "type": "string",
                                      "format": "date",
                                      "nullable": true
                                    },
                                    "position": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Free-text job title / position (persons only)."
                                    },
                                    "custom_fields": {
                                      "type": "object",
                                      "description": "Workflow-defined custom fields collected for this party; keys are defined by the workflow's key-people field descriptors."
                                    },
                                    "is_active": {
                                      "type": "boolean"
                                    },
                                    "is_skipped": {
                                      "type": "boolean",
                                      "description": "True when the end user skipped verification for this party (only possible when the role allows skipping)."
                                    },
                                    "requires_verification": {
                                      "type": "boolean",
                                      "description": "True when a child KYC / KYB sub-session is required for this party based on role settings and ownership thresholds."
                                    },
                                    "roles": {
                                      "type": "array",
                                      "description": "All roles held by this party, each with its own ownership and voting percentages. There is no scalar `role`/`ownership_percent` on the party itself.",
                                      "items": {
                                        "type": "object",
                                        "properties": {
                                          "role": {
                                            "type": "string",
                                            "enum": [
                                              "director",
                                              "non_executive_director",
                                              "secretary",
                                              "chairman",
                                              "ubo",
                                              "shareholder",
                                              "representative",
                                              "founder",
                                              "legal_advisor",
                                              "authorized_signatory",
                                              "trustee",
                                              "beneficiary",
                                              "settlor",
                                              "protector",
                                              "company_officer",
                                              "investor",
                                              "other"
                                            ]
                                          },
                                          "ownership_percent": {
                                            "type": "number",
                                            "nullable": true
                                          },
                                          "voting_percent": {
                                            "type": "number",
                                            "nullable": true
                                          }
                                        }
                                      }
                                    },
                                    "kyc_session_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Child KYC session id for person parties requiring verification. `null` otherwise."
                                    },
                                    "kyc_session_status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Started",
                                        "In Progress",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Expired",
                                        "Abandoned",
                                        "Kyc Expired",
                                        "Resubmitted",
                                        "Awaiting User"
                                      ],
                                      "nullable": true,
                                      "description": "Lifecycle status of the child KYC session. `null` when no child KYC session exists."
                                    },
                                    "kyc_session_url": {
                                      "type": "string",
                                      "format": "uri",
                                      "nullable": true
                                    },
                                    "kyb_sub_session_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Child KYB sub-session id for corporate parties requiring verification. `null` otherwise."
                                    },
                                    "kyb_sub_session_status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Started",
                                        "In Progress",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Expired",
                                        "Abandoned",
                                        "Kyc Expired",
                                        "Resubmitted",
                                        "Awaiting User"
                                      ],
                                      "nullable": true,
                                      "description": "Lifecycle status of the child KYB sub-session. `null` when no sub-session exists."
                                    },
                                    "kyb_sub_session_url": {
                                      "type": "string",
                                      "format": "uri",
                                      "nullable": true,
                                      "description": "Shareable URL of the child KYB sub-session. `null` when no sub-session exists."
                                    },
                                    "verification_workflow_type": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Base workflow type of the child session's workflow (KYC session preferred, falling back to the KYB sub-session). `null` for graph-based workflows or when no child session exists."
                                    },
                                    "verification_workflow_id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "nullable": true,
                                      "description": "Workflow id used by the child session. `null` when no child session exists."
                                    },
                                    "verification_workflow_label": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Human-readable label of the child session's workflow. `null` when unset."
                                    },
                                    "verification_workflow_features": {
                                      "type": "array",
                                      "nullable": true,
                                      "description": "Per-feature progress of the child verification session, e.g. `[{\"feature\": \"ID_VERIFICATION\", \"status\": \"Approved\"}]`. `null` when the child session has no resolvable feature list.",
                                      "items": {
                                        "type": "object",
                                        "properties": {
                                          "feature": {
                                            "type": "string",
                                            "description": "Feature display name (e.g. `ID_VERIFICATION`, `LIVENESS`, `AML`)."
                                          },
                                          "status": {
                                            "type": "string",
                                            "enum": [
                                              "Not Finished",
                                              "Approved",
                                              "Declined",
                                              "In Review",
                                              "Resub Requested"
                                            ],
                                            "description": "Feature-level status inside the child session."
                                          }
                                        }
                                      }
                                    },
                                    "didit_internal_id": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Stable internal identifier of the verified individual behind the child session. `null` when not resolved."
                                    }
                                  }
                                }
                              }
                            }
                          },
                          "ubo_kyc_summary": {
                            "type": "object",
                            "nullable": true,
                            "description": "Aggregate UBO KYC progress, or null when no UBOs have linked KYC sessions.",
                            "properties": {
                              "total": {
                                "type": "integer"
                              },
                              "approved": {
                                "type": "integer"
                              },
                              "flagged": {
                                "type": "integer",
                                "description": "UBOs whose KYC is Declined or In Review."
                              },
                              "pending": {
                                "type": "integer"
                              }
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        }
                      }
                    },
                    "document_verifications": {
                      "type": "array",
                      "nullable": true,
                      "description": "Document verification checks grouped by workflow node. Present only when `session_kind = business`.",
                      "items": {
                        "type": "object",
                        "description": "Documents grouped by workflow node. Present only when session_kind = business.",
                        "properties": {
                          "status": {
                            "type": "string"
                          },
                          "node_id": {
                            "type": "string",
                            "nullable": true
                          },
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "uuid": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "document_type": {
                                  "type": "string",
                                  "enum": [
                                    "LEGAL_PRESENCE",
                                    "COMPANY_DETAILS",
                                    "OWNERSHIP_STRUCTURE",
                                    "REPRESENTATIVES_AUTHORIZATION",
                                    "OTHER"
                                  ],
                                  "nullable": true,
                                  "description": "High-level KYB document group the file was classified into. `null` while unclassified."
                                },
                                "document_subtype": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Specific OCR-detected subtype (e.g. `CERTIFICATE_OF_INCORPORATION`, `SHAREHOLDER_REGISTRY`); `UNKNOWN` when the OCR could not confidently classify the document."
                                },
                                "document_group": {
                                  "type": "string",
                                  "enum": [
                                    "LEGAL_PRESENCE",
                                    "COMPANY_DETAILS",
                                    "OWNERSHIP_STRUCTURE",
                                    "REPRESENTATIVES_AUTHORIZATION",
                                    "OTHER"
                                  ],
                                  "nullable": true,
                                  "description": "Alias of `document_type` — the group name used by `groups` and `required_groups`."
                                },
                                "file_url": {
                                  "type": "string",
                                  "format": "uri",
                                  "nullable": true,
                                  "description": "Short-lived presigned link to the uploaded file. `null` for analyst-created document request placeholders (`is_requested = true`) that have not been fulfilled yet."
                                },
                                "original_filename": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Filename as uploaded by the user or analyst."
                                },
                                "file_size": {
                                  "type": "integer",
                                  "nullable": true,
                                  "description": "File size in bytes."
                                },
                                "status": {
                                  "type": "string",
                                  "enum": [
                                    "Not Finished",
                                    "Approved",
                                    "Declined",
                                    "In Review",
                                    "Resub Requested"
                                  ],
                                  "description": "Per-document verification status."
                                },
                                "created_at": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "cross_check_result": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Cross-reference of the OCR-extracted document fields against the registry company profile. An object with `critical`, `non_critical` and `people` sections, each mapping a field name (e.g. `company_name`, `registration_number`, `incorporation_date`, `registered_address`) to a comparison record like `{\"document\": \"...\", \"registry\": \"...\", \"match\": true, \"score\": 0.97}`. `null` when the document had no OCR data or there was no registry company to compare against."
                                },
                                "document_metadata": {
                                  "type": "object",
                                  "nullable": true,
                                  "description": "Metadata extracted from the uploaded corporate document. When metadata extraction succeeded, all 16 keys are always present (individual values are `null` when not applicable to the file type); the whole object is `null` when nothing could be extracted. For PDFs, `overlay_manipulation` carries forensic overlay-text analysis.",
                                  "properties": {
                                    "file_size": {
                                      "type": "integer",
                                      "nullable": true,
                                      "description": "Size of the document."
                                    },
                                    "content_type": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Content type of the document."
                                    },
                                    "creation_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Date when the document was created."
                                    },
                                    "modified_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Date when the document was modified."
                                    },
                                    "creator": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Authoring tool/user recorded in the file metadata (PDF `Creator`)."
                                    },
                                    "producer": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Software that produced the file (PDF `Producer`)."
                                    },
                                    "software": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Editing software recorded in the file metadata."
                                    },
                                    "encryption": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "Encryption scheme of the file, when encrypted."
                                    },
                                    "is_signed": {
                                      "type": "boolean",
                                      "nullable": true,
                                      "description": "Whether the document carries a digital signature."
                                    },
                                    "is_tampered": {
                                      "type": "boolean",
                                      "nullable": true,
                                      "description": "Whether the digital signature failed validation (post-signing modification)."
                                    },
                                    "signature_info": {
                                      "type": "object",
                                      "nullable": true,
                                      "description": "Details of the digital signature(s), when present."
                                    },
                                    "exif_original_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "EXIF original capture date, for image uploads."
                                    },
                                    "exif_digitized_date": {
                                      "type": "string",
                                      "nullable": true,
                                      "description": "EXIF digitization date, for image uploads."
                                    },
                                    "processed_by_known_editor": {
                                      "type": "boolean",
                                      "nullable": true,
                                      "description": "Whether metadata indicates the file passed through a known image/PDF editor."
                                    },
                                    "has_different_creation_mod_date": {
                                      "type": "boolean",
                                      "nullable": true,
                                      "description": "Whether creation and modification dates differ — a possible (but not conclusive) editing signal."
                                    },
                                    "overlay_manipulation": {
                                      "type": "object",
                                      "nullable": true,
                                      "description": "PDF forensic analysis for suspected overlay-text manipulation. Null when no overlay manipulation evidence was found or the document was not a PDF.",
                                      "properties": {
                                        "detected": {
                                          "type": "boolean",
                                          "description": "Whether overlay-text manipulation evidence was detected."
                                        },
                                        "analyzed": {
                                          "type": "boolean",
                                          "description": "Whether the PDF could be analyzed."
                                        },
                                        "signals": {
                                          "type": "array",
                                          "items": {
                                            "type": "string"
                                          },
                                          "description": "Forensic signals that fired, such as duplicate_font_subset or glyph_fragmentation."
                                        },
                                        "manipulated_regions": {
                                          "type": "array",
                                          "description": "Suspected manipulated areas in PDF page coordinates.",
                                          "items": {
                                            "type": "object",
                                            "properties": {
                                              "page": {
                                                "type": "integer"
                                              },
                                              "x": {
                                                "type": "number"
                                              },
                                              "y": {
                                                "type": "number"
                                              },
                                              "width": {
                                                "type": "number"
                                              },
                                              "height": {
                                                "type": "number"
                                              },
                                              "page_width": {
                                                "type": "number"
                                              },
                                              "page_height": {
                                                "type": "number"
                                              }
                                            }
                                          }
                                        }
                                      }
                                    }
                                  }
                                },
                                "description": {
                                  "type": "string",
                                  "nullable": true,
                                  "description": "Analyst-provided label or reason for a document request. `null` for regular uploads."
                                },
                                "is_requested": {
                                  "type": "boolean",
                                  "description": "True for analyst-created document request placeholders awaiting an upload."
                                },
                                "ocr_data": {
                                  "type": "object",
                                  "nullable": true
                                },
                                "is_console_upload": {
                                  "type": "boolean",
                                  "description": "True for documents uploaded from the console rather than the end-user flow. Console uploads never change the feature-level aggregate status."
                                },
                                "is_confirmed": {
                                  "type": "boolean",
                                  "description": "Console uploads start `false` and flip `true` once the admin confirms them; end-user uploads are always `true`."
                                }
                              }
                            }
                          },
                          "groups": {
                            "type": "object",
                            "description": "Per-group progress counters keyed by group name (e.g. legal_presence, ownership_structure).",
                            "additionalProperties": {
                              "type": "object",
                              "properties": {
                                "total": {
                                  "type": "integer"
                                },
                                "approved": {
                                  "type": "integer"
                                },
                                "pending": {
                                  "type": "integer"
                                },
                                "declined": {
                                  "type": "integer"
                                },
                                "in_review": {
                                  "type": "integer"
                                },
                                "other": {
                                  "type": "integer"
                                },
                                "missing": {
                                  "type": "integer",
                                  "description": "Requested placeholders with no file uploaded yet."
                                }
                              }
                            }
                          },
                          "required_groups": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        }
                      }
                    },
                    "environment": {
                      "type": "string",
                      "enum": [
                        "live",
                        "sandbox"
                      ],
                      "description": "Whether the session was created by a live application (`live`) or a sandbox application (`sandbox`). Sandbox sessions are free, fully simulated, and never bill credits."
                    },
                    "resubmissions": {
                      "type": "array",
                      "description": "Returned only with `include=resubmissions`, for user and business sessions. One entry per resubmission request, oldest first. Each entry carries the results the resubmitted steps returned before the request, so earlier submissions stay readable. Deleting the session deletes every submission.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "number": {
                            "type": "integer",
                            "description": "1 for the first resubmission of the session, 2 for the second, and so on."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the resubmission was requested."
                          },
                          "previous_status": {
                            "type": "string",
                            "description": "The session status just before the request."
                          },
                          "nodes": {
                            "type": "array",
                            "description": "The workflow steps sent back to the user.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "node_id": {
                                  "type": "string"
                                },
                                "feature": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "reasons": {
                            "type": "object",
                            "nullable": true,
                            "additionalProperties": {
                              "type": "string"
                            },
                            "description": "The reason given for each step, keyed by `node_id`."
                          },
                          "requested_by": {
                            "type": "object",
                            "nullable": true,
                            "description": "Who requested the resubmission.",
                            "properties": {
                              "name": {
                                "type": "string"
                              },
                              "email": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string"
                              }
                            }
                          },
                          "results": {
                            "type": "object",
                            "additionalProperties": true,
                            "description": "What the resubmitted steps returned before the request, under the same keys and in the same shape as the current results of this response (`id_verifications`, `nfc_verifications`, `liveness_checks`, `face_matches`, `poa_verifications`, `phone_verifications`, `email_verifications`, `aml_screenings`, `ip_analyses`, `database_validations`, `questionnaire_responses`, `document_ai_documents`, `geolocation_checks`; for business sessions also `document_verifications`). Only the keys of the steps that were sent back appear."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Authentication or authorization failed. **This endpoint never returns `401`** — Didit's API-key authentication does not emit a `WWW-Authenticate` challenge, so missing or invalid credentials also surface as `403`. Two `detail` strings distinguish the failure modes:\n\n- `\"Authentication credentials were not provided or are invalid.\"` — no `x-api-key` header (and no `Authorization: Bearer` token), or the supplied credential failed introspection (revoked, expired, or malformed).\n- `\"You do not have permission to perform this action.\"` — the credential is valid but not allowed to read this session: a console-user Bearer token lacks the `read:sessions` permission or cannot access the owning application, or an API key belongs to a different organization than the session.\n\nNote that for a completely unknown `sessionId` the endpoint resolves the owning application before validating credentials, so a missing session returns `404` even when the credential is missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "Authentication credentials were not provided or are invalid."
                    }
                  }
                },
                "examples": {
                  "Missing or invalid credentials": {
                    "summary": "No x-api-key header, or the key failed introspection",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Insufficient permissions": {
                    "summary": "Valid credential lacking read:sessions or access to the owning application",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Session not found. Returned when no live session matches the supplied `sessionId` as either a User Verification (KYC) or a Business Verification (KYB) session — a session that has been deleted also lands here. Body is the standard `{\"detail\": ...}` envelope.\n\n**Two distinct `detail` strings.** If the `sessionId` is unknown as both a KYC and a KYB session, the pre-auth owner lookup fails and you receive `{\"detail\": \"Not found.\"}` — this happens before credential validation, so it is returned even for unauthenticated calls. If the session exists but cannot be retrieved under the authenticated application (for example a stale or just-deleted record), the view returns `{\"detail\": \"Session not found.\"}`. Both indicate the same outcome — the session is not accessible — so match on the `404` status code rather than the string.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "Not found."
                    }
                  }
                },
                "examples": {
                  "Unknown session id": {
                    "summary": "sessionId is unknown to this application",
                    "value": {
                      "detail": "Not found."
                    }
                  },
                  "Session not retrievable": {
                    "summary": "Session exists but is not retrievable for this application",
                    "value": {
                      "detail": "Session not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. GET requests are limited to **600 per minute per credential** (API key, Bearer token, or source IP when unauthenticated). Inspect `Retry-After` / `X-RateLimit-Reset` and back off before retrying. If you hit this limit while polling for decisions, switch to the `status.updated` webhook and fetch the decision once per status change instead.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "minimum": 1,
                  "example": 30
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of requests allowed in the current window (600 for GET requests).",
                "schema": {
                  "type": "integer",
                  "example": 600
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the current window resets.",
                "schema": {
                  "type": "integer",
                  "example": 1750000000
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation of the rate-limit breach.",
                      "example": "GET request rate limit exceeded. You can make up to 600 requests per minute."
                    }
                  }
                },
                "examples": {
                  "Throttled": {
                    "summary": "More than 600 GET requests in one minute from the same credential",
                    "value": {
                      "detail": "GET request rate limit exceeded. You can make up to 600 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "UUID of the verification session whose decision you want to retrieve. This is the `session_id` returned by `POST /v3/session/`. The same path works for both User Verification (KYC) and Business Verification (KYB) sessions — the server resolves the id against both session types.\n\n**Must be a valid UUID.** The route only matches well-formed UUIDs, so a malformed value is rejected by the URL router before any application code runs and the response is a `404` **HTML** page rather than the JSON `{\"detail\": ...}` envelope shown below. Validate the UUID format client-side so you can distinguish an input error from a genuine missing-session `404`.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of extra payload sections. Supported values: `events` and `resubmissions`, alone or together (`events,resubmissions`). When `include=events` is passed, the response additionally contains the session event timeline (`events`, including the `WORKFLOW_BRANCH_EVALUATED` / `WORKFLOW_STATUS_NODE_REACHED` routing events described on the Retrieve Session page), the full activity log (`activity_reviews`), blocklist flags (`blocklisted`), a per-session `cost_breakdown`, workflow metadata (`workflow_type`, `workflow_version`, `workflow_version_id`, and `workflow_terminal_node_id` - the last recorded workflow status node that set a session status, or `null` if none has been recorded; historical provenance that is not cleared by manual approvals, declines or resubmissions, and is replaced by a later workflow status node), and session metadata (`api_service` — string or `null`, set only for standalone-API sessions; `session_type` — `API`, `HOSTED`, or `MIGRATED`; `has_device_nfc_support` — boolean). Two fields change relative to the plain shape: the top-level `session_kind` discriminator is **omitted** (the events shape only exists for user sessions), and the `features` array switches from plain strings to `{feature, node_id}` objects — where the email feature is reported as `EMAIL` instead of `EMAIL_VERIFICATION`. This expanded shape is primarily used by the Didit Console; most API integrations should omit the parameter. **KYB limitation:** `include=events` only applies to user (KYC) sessions. Business sessions (`session_kind = \"business\"`) always return the standard business decision shape — `events`, `activity_reviews`, `blocklisted`, `cost_breakdown` and the extra `workflow_*`/session metadata are never returned for business sessions, and their `features` array stays a plain string array. With `include=resubmissions` (user and business sessions alike) the response also contains `resubmissions`: one entry per resubmission request, oldest first, each with `number`, `created_at`, `previous_status`, `nodes`, `reasons`, `requested_by` and `results` (what the resubmitted steps returned before the request, under the same keys and in the same shape as the current results). Each `cost_breakdown` item carries `usage_type`, `price`, `details` and `created_at`: a resubmitted step that runs again is billed as a new item.",
            "schema": {
              "type": "string",
              "enum": [
                "events",
                "resubmissions",
                "events,resubmissions"
              ],
              "example": "events"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET 'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/decision/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Accept: application/json'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nsession_id = \"11111111-2222-3333-4444-555555555555\"\nurl = f\"https://verification.didit.me/v3/session/{session_id}/decision/\"\nheaders = {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(url, headers=headers, timeout=15)\nresponse.raise_for_status()\ndecision = response.json()\n\nprint(\"session_kind:\", decision[\"session_kind\"])\nprint(\"top-level status:\", decision[\"status\"])\n\n# nfc_verifications is ALWAYS an array — never a singular `nfc` field.\nfor nfc in decision.get(\"nfc_verifications\") or []:\n    print(\"nfc node_id:\", nfc[\"node_id\"], \"status:\", nfc[\"status\"])\n\nfor id_check in decision.get(\"id_verifications\") or []:\n    print(\"id node_id:\", id_check[\"node_id\"], \"status:\", id_check[\"status\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const sessionId = '11111111-2222-3333-4444-555555555555';\nconst response = await fetch(\n  `https://verification.didit.me/v3/session/${sessionId}/decision/`,\n  {\n    method: 'GET',\n    headers: {\n      'x-api-key': 'YOUR_API_KEY',\n      Accept: 'application/json',\n    },\n  }\n);\n\nif (!response.ok) {\n  throw new Error(`Decision fetch failed: ${response.status}`);\n}\nconst decision = await response.json();\n\nconsole.log('session_kind:', decision.session_kind);\nconsole.log('top-level status:', decision.status);\n\n// nfc_verifications is ALWAYS an array — never a singular `nfc` field.\nfor (const nfc of decision.nfc_verifications ?? []) {\n  console.log('nfc node_id:', nfc.node_id, 'status:', nfc.status);\n}\n\nfor (const idCheck of decision.id_verifications ?? []) {\n  console.log('id node_id:', idCheck.node_id, 'status:', idCheck.status);\n}"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/delete/": {
      "delete": {
        "summary": "Delete a verification session (KYC or KYB)",
        "description": "Delete a single verification session, User Verification (KYC) or Business Verification (KYB), by its `session_id`. The id is resolved against KYC sessions first, then KYB sessions, so both kinds are deleted through this one URL.\n\n**What is deleted:**\n- The session and every verification attempt it holds, including results that a resubmission replaced: the decision, extracted data, all related feature records (ID verification, face, liveness, face match, AML, registry checks, IP analysis, and so on), its reviews and its activity log.\n- All stored files owned by the session: document front/back photos (full, cropped, and privacy-blurred variants), document-capture videos, portrait crops, NFC chip portrait and signature images, face reference images, liveness videos, face-match source/target images, Proof of Address documents, and any extra uploaded files (KYC); uploaded company documents and extra files (KYB). Previously issued media URLs (`https://<media-host>/...`) stop resolving.\n- The session's face data. Its face embedding is deleted too, unless you choose to keep an image-free template (see **Face biometric data**).\n- Webhook deliveries still queued for the session, and their retries. Webhooks already delivered are not affected.\n- For a Business Verification (KYB) session: the verifications it created for its key people (KYC) and its corporate owners (KYB), recursively, reported as `deleted_child_verifications`. A verification it only links to, such as an existing approved KYC it reused, is not deleted.\n\nThe session disappears from every read endpoint immediately: `GET /v3/session/{sessionId}/decision/` returns `404` and `GET /v3/sessions/` stops listing it. Ongoing AML monitoring and KYB registry monitoring started by the deleted verifications stop.\n\n**What is not affected:** blocklist entries created from this session (face or document) are **not** removed; manage those with the blocklist endpoints. Share tokens issued for the session are not revoked, but there is nothing left for them to import: an import with one returns `400` with `{\"share_token\": [\"Original session does not exist.\"]}`. Credits already consumed are **not** refunded. The parent User or Business entity is **not** deleted; use `POST /v3/users/delete/` or `POST /v3/businesses/delete/` for those. If the User's profile portrait came from this session, the portrait is removed with it.\n\n**Face biometric data:** by default the session's face embedding is deleted with the session (`face_retention_outcome: deleted`). An application that opted in to biometric-template retention (`face_retention_policy: retain_until_user_deleted` on `PATCH /v3/webhook/`), or a request with `retain_face_embeddings: true`, keeps one separately managed, image-free face biometric template anchored to the session's User (`retained_with_user`) so that duplicate detection, Face Search, and biometric authentication keep working. The template never contains the face image, media, identity fields, the decision, or the deleted session's id; it is biometric data deleted at `biometric_template_expires_at`, or earlier on User deletion, privacy erasure, or an explicit purge through `/v3/biometric-templates/`. A session without a linked User cannot retain a template (`ineligible_no_vendor_user`). Send `deletion_instruction: privacy_erasure` for data-subject requests: it purges every retained template for that User and never retains a new one.\n\n**Irreversible:** deletion is permanent and there is no restore endpoint. Export anything you need (for example a decision PDF) before you call it.\n\n**Side effects:** no webhook is emitted for deletions.\n\n**Response:** `200 OK` once the deletion has completed, with a JSON body reporting the `face_retention_outcome`, the retained template's expiry and, for a KYB session, `deleted_child_verifications`. Earlier versions of this endpoint returned `204 No Content`; update clients that assert on `204`. Keep your `instruction_id` in your own erasure log.\n\n**Idempotency:** not idempotent at the HTTP level: the first call returns `200`; repeating it returns `404` because the session no longer resolves. After a `503` the session is still in place; repeat the same request to finish deleting it.\n\n**Authentication:** send your application's API key in the `x-api-key` header; the session must belong to that application. Console user access tokens (`Authorization: Bearer ...`) may also call this endpoint when they carry the `delete:sessions` permission. Authentication and permission failures both return `403`; this API never returns `401`.\n\n**Rate limit:** shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.\n\nTo bulk-delete KYC sessions by their numeric `session_number`, use `POST /v3/sessions/delete/` instead.",
        "operationId": "delete_v3_session_by_id",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID (`session_id`) of the User Verification (KYC) or Business Verification (KYB) session to delete, as returned when the session was created. Must be a canonical hyphenated UUID — a non-UUID value does not match the route and returns `404`.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session deleted. The body reports what happened to the session's face biometric data and, for a KYB session, how many verifications it created were deleted with it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "The deleted session."
                    },
                    "session_number": {
                      "type": "integer",
                      "nullable": true,
                      "description": "The deleted session's number."
                    },
                    "face_retention_outcome": {
                      "type": "string",
                      "enum": [
                        "retained_with_user",
                        "deleted",
                        "none",
                        "ineligible_no_vendor_user"
                      ],
                      "description": "What happened to the session's face biometric data. `deleted`: the face embedding was deleted with the session (default). `retained_with_user`: the session is deleted and one image-free biometric template stays anchored to the User; see `biometric_template_uuid`. `none`: the session had no face embedding (for example a KYB session, or a KYC session without a liveness selfie). `ineligible_no_vendor_user`: retention was requested but the session has no linked User, so the embedding was deleted with the session. A biometric-store failure is never reported through this field on this endpoint: it returns `503` and the session is not deleted."
                    },
                    "biometric_template_uuid": {
                      "type": "string",
                      "format": "uuid",
                      "nullable": true,
                      "description": "Id of the retained biometric template when `face_retention_outcome` is `retained_with_user`; `null` otherwise. Manage it through `/v3/biometric-templates/{template_uuid}/`."
                    },
                    "biometric_template_expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "When the retained biometric template is deleted, when `face_retention_outcome` is `retained_with_user`; `null` when no template is retained."
                    },
                    "deleted_child_verifications": {
                      "type": "integer",
                      "description": "For a Business Verification (KYB) session: how many verifications it created (its key people's KYC sessions and its corporate owners' KYB sessions, recursively) were deleted with it. Always `0` for a KYC session."
                    }
                  }
                },
                "examples": {
                  "Deleted (default)": {
                    "value": {
                      "session_id": "4c5c7f3a-3b1d-4b7e-9c39-2b4f7e6a1d02",
                      "session_number": 1024,
                      "face_retention_outcome": "deleted",
                      "biometric_template_uuid": null,
                      "biometric_template_expires_at": null,
                      "deleted_child_verifications": 0
                    }
                  },
                  "Retained with User": {
                    "value": {
                      "session_id": "4c5c7f3a-3b1d-4b7e-9c39-2b4f7e6a1d02",
                      "session_number": 1024,
                      "face_retention_outcome": "retained_with_user",
                      "biometric_template_uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                      "biometric_template_expires_at": "2027-10-09T10:15:00Z",
                      "deleted_child_verifications": 0
                    }
                  },
                  "Ineligible: no User": {
                    "summary": "Retention requested on a session created without vendor_data",
                    "value": {
                      "session_id": "7a1e9c2d-5f4b-4c3a-8e2d-1b0a9f8e7d6c",
                      "session_number": 1031,
                      "face_retention_outcome": "ineligible_no_vendor_user",
                      "biometric_template_uuid": null,
                      "biometric_template_expires_at": null,
                      "deleted_child_verifications": 0
                    }
                  },
                  "KYB session": {
                    "value": {
                      "session_id": "0f3c9b7e-2d1a-4e5f-8c6b-7a9d8e1f2c3b",
                      "session_number": 88,
                      "face_retention_outcome": "none",
                      "biometric_template_uuid": null,
                      "biometric_template_expires_at": null,
                      "deleted_child_verifications": 3
                    },
                    "summary": "A business verification deleted with the three verifications it created for its key people"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — nothing is deleted.",
            "content": {
              "application/json": {
                "examples": {
                  "Privacy erasure cannot retain": {
                    "value": {
                      "retain_face_embeddings": [
                        "Privacy erasure cannot retain biometric templates."
                      ]
                    }
                  },
                  "No finite retention duration": {
                    "summary": "Retention requested without face_retention_days on the request or the application",
                    "value": {
                      "detail": "A finite biometric-template retention duration is required."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Authentication or permission failure. Missing/invalid credentials also return `403` — this API never returns `401`. Exception: when the `sessionId` does not resolve to a live session, the pre-auth owner lookup returns `404` first, even with missing or invalid credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No x-api-key header, or the key is invalid",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Insufficient permission": {
                    "summary": "User token without delete:sessions, or credentials for an application that does not own the session",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No live KYC or KYB session with this `session_id` exists — the id is unknown or the session was already deleted (repeating a successful delete lands here).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Not Found": {
                    "summary": "Unknown or already-deleted session",
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared write rate limit exceeded (300 POST/PATCH/DELETE requests per minute per API key). Inspect `Retry-After` and the `X-RateLimit-*` response headers before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Rate limited": {
                    "summary": "Write budget exhausted",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "The deletion could not finish because a storage service, a biometric store, or a monitoring provider was unavailable. The session is still in place; repeat the same request until it returns `200`. Some of its stored files or its face embedding may already be deleted, so do not rely on them after a `503`. Retries converge on a single template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Session deletion unavailable": {
                    "summary": "A storage service or a monitoring provider was unavailable",
                    "value": {
                      "detail": "The session could not be deleted because a storage service or a monitoring provider is unavailable. The session is still in place; repeat the request to finish deleting it."
                    }
                  },
                  "Biometric store unavailable": {
                    "summary": "A biometric store was unavailable while retaining or purging a template",
                    "value": {
                      "detail": "The biometric-template operation could not finish because an external store is unavailable. The operation is retryable."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl (default policy)",
            "source": "curl -X DELETE \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/delete/ \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "curl",
            "label": "curl (retain template)",
            "source": "curl -X DELETE \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/delete/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"retain_face_embeddings\": true, \"face_retention_days\": 365}'"
          },
          {
            "lang": "curl",
            "label": "curl (privacy erasure)",
            "source": "curl -X DELETE \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/delete/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"deletion_instruction\": \"privacy_erasure\", \"instruction_id\": \"dsar-2026-0142\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.delete(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/delete/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    json={\"retain_face_embeddings\": True, \"face_retention_days\": 365},\n)\nresponse.raise_for_status()\nprint(response.json()[\"face_retention_outcome\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/delete/',\n  {\n    method: 'DELETE',\n    headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n    body: JSON.stringify({ deletion_instruction: 'privacy_erasure', instruction_id: 'dsar-2026-0142' }),\n  },\n);\nconst body = await resp.json();\nconsole.log(body.face_retention_outcome);"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional. Omit the body entirely to follow the application's retention policy with an operational deletion.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "retain_face_embeddings": {
                    "type": "boolean",
                    "nullable": true,
                    "description": "Override the application's `face_retention_policy` for this deletion. `true` keeps one image-free face biometric template anchored to the session's User after the session is deleted; `false` deletes the face embedding with the session; omit or `null` to follow the application policy. Ignored for KYB sessions and for sessions without a face embedding.",
                    "example": true
                  },
                  "face_retention_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3650,
                    "description": "Finite retention duration, in days, for a retained template. Required when a template is retained unless the application already sets `face_retention_days`. The template's `expires_at` is the earliest of this duration, the application's general data-retention window, and `face_retention_deadline`.",
                    "example": 365
                  },
                  "face_retention_deadline": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Optional hard expiry for a retained template. Must be in the future.",
                    "example": "2027-08-28T00:00:00Z"
                  },
                  "deletion_instruction": {
                    "type": "string",
                    "enum": [
                      "operational_session_delete",
                      "privacy_erasure"
                    ],
                    "default": "operational_session_delete",
                    "description": "The class of instruction you are giving. `operational_session_delete` deletes the session and retains a template only when the policy or `retain_face_embeddings` says so. `privacy_erasure` purges every retained biometric template anchored to the session's User before deleting the session, cannot be overridden by the application policy, and cannot be combined with `retain_face_embeddings: true` (`400`).",
                    "example": "operational_session_delete"
                  },
                  "instruction_id": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Your durable reference for this deletion instruction (for example an erasure-ticket id). Recorded on the audit trail and on any retained template. Generated by Didit when omitted.",
                    "example": "dsar-2026-0142"
                  }
                }
              },
              "examples": {
                "Retain a biometric template": {
                  "summary": "Delete the session, keep an image-free template for 365 days",
                  "value": {
                    "retain_face_embeddings": true,
                    "face_retention_days": 365,
                    "instruction_id": "post-approval-cleanup-2026-08"
                  }
                },
                "Force deletion on an opted-in application": {
                  "summary": "Delete the face embedding regardless of the application policy",
                  "value": {
                    "retain_face_embeddings": false
                  }
                },
                "Privacy erasure": {
                  "summary": "Data-subject request: delete the session and purge every retained template for that person",
                  "value": {
                    "deletion_instruction": "privacy_erasure",
                    "instruction_id": "dsar-2026-0142"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/session/{sessionId}/generate-pdf/": {
      "get": {
        "summary": "Download a PDF report for a verification session",
        "description": "Render and download a compliance-ready PDF report for a finished verification session. The same path serves both User Verification (KYC) and Business Verification (KYB) sessions — the server resolves the `sessionId` against both session types and picks the matching report template.\n\n**Eligible statuses.** The session must already carry a final or reviewable status:\n\n- KYC sessions: `Approved`, `Declined`, `In Review`, or `Kyc Expired`.\n- KYB sessions: `Approved`, `Declined`, or `In Review`.\n\nAny other status (`Not Started`, `In Progress`, `Expired`, `Abandoned`, …) returns `403` with an explanatory `detail` string — see the `403` response below.\n\n**What the report contains.** The PDF mirrors the console session view at the moment of the request:\n\n- **KYC** — rolled-up session status, the warnings list, and one section per executed feature: ID Verification (document images plus extracted fields), NFC, Liveness, Face Match, Email Verification, Phone Verification, Proof of Address, Questionnaire answers, Database Validation, AML Screening, and IP Analysis — followed by session tags, console review activity (comments and status changes), and the session event timeline.\n- **KYB** — registry checks (company data), AML screenings, business document verifications, key-people checks, questionnaire responses, phone/email verifications, IP analyses, and the session event timeline, followed by tags and review activity.\n\n**Branding.** If your application has white-label customization, the report is rendered with your logo and links to your privacy-policy URL; otherwise it carries Didit branding. Reports are rendered in English — there is no language parameter.\n\n**No caching.** Every call re-renders the PDF from the current session data, so a report generated after a manual review reflects the reviewer’s decision. Two calls for the same session can produce byte-different files — archive the downloaded file if you need an immutable copy.\n\n**Latency.** Rendering downloads every stored image (document sides, selfies, extra files) before composing the PDF, so media-heavy sessions can take several seconds. Use a generous client read timeout (60 s recommended) and stream the body to disk.\n\n**Trailing slash.** The canonical route ends with a trailing slash (`…/generate-pdf/`). A request without it is served directly with the same response — there is no `301` redirect, so no client has to follow redirects and `curl` does not need `-L`. Use the slashed URL as in the samples.\n\nIf you need the underlying data as JSON instead of a rendered report, use `GET /v3/session/{sessionId}/decision/`. For every reportable session of one user in a single document, use `GET /v3/users/{vendor_data}/generate-pdf/`.",
        "operationId": "get_v3_session_generate_pdf",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "UUID of the User Verification (KYC) or Business Verification (KYB) session to render — the `session_id` returned by `POST /v3/session/`. The same path works for both session kinds; use the `Content-Disposition` filename on the response to tell which report type you received.\n\n**Must be a well-formed, lowercase UUID.** The route only matches valid UUIDs, so a malformed value is rejected by the URL router before any application code runs and the response is a `404` **HTML** page rather than the JSON `{\"detail\": ...}` envelope shown below. The route's UUID converter only matches the canonical lowercase form — uppercase-hex UUIDs are rejected with the HTML 404.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The rendered PDF document, returned directly as binary `application/pdf` — there is no JSON wrapper and no download-URL indirection. The body starts with the `%PDF` magic bytes (PDF 1.7). Save it to a `.pdf` file or stream it through to your caller.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=session_{sessionId}.pdf` for KYC sessions, `attachment; filename=business_{sessionId}.pdf` for KYB sessions — the prefix tells you which report template was rendered.",
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=session_11111111-2222-3333-4444-555555555555.pdf"
                }
              },
              "Content-Length": {
                "description": "Total size of the PDF in bytes; the body is not chunked.",
                "schema": {
                  "type": "integer",
                  "example": 25191
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "403": {
            "description": "Authentication, authorization, or session-status failure. **This endpoint never returns `401`** — Didit's API-key authentication does not emit a `WWW-Authenticate` challenge, so missing or invalid credentials also surface as `403`. Distinguish the failure modes by the `detail` string:\n\n- `\"Authentication credentials were not provided or are invalid.\"` — no `x-api-key` header (and no `Authorization: Bearer` token), or the supplied credential failed introspection (revoked, expired, or malformed).\n- `\"You do not have permission to perform this action.\"` — the credential is valid but cannot read this session: a console-user Bearer token lacks the `read:sessions` permission or cannot access the owning application, or an API key belongs to a different organization than the session.\n- `\"You can only generate a PDF for sessions in review, declined, approved or kyc expired\"` — the KYC session exists but is not in an eligible status yet (for example `Not Started` or `In Progress`). Wait for the `status.updated` webhook before requesting the report.\n- `\"You can only generate a PDF for sessions in review, declined or approved\"` — same condition for KYB sessions.\n\nNote that for a completely unknown `sessionId` the endpoint resolves the owning application before validating credentials, so a missing session returns `404` even when the credential is missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "You can only generate a PDF for sessions in review, declined, approved or kyc expired"
                    }
                  }
                },
                "examples": {
                  "Missing or invalid credentials": {
                    "summary": "No x-api-key header, or the key failed introspection",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Insufficient permissions": {
                    "summary": "Valid credential lacking read:sessions or access to the owning application",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "KYC session not finished": {
                    "summary": "KYC session still Not Started / In Progress",
                    "value": {
                      "detail": "You can only generate a PDF for sessions in review, declined, approved or kyc expired"
                    }
                  },
                  "KYB session not finished": {
                    "summary": "KYB session still Not Started / In Progress",
                    "value": {
                      "detail": "You can only generate a PDF for sessions in review, declined or approved"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No active session with this `sessionId` exists — it was never created, or it has been deleted. Owner resolution happens before credential validation, so this `404` is returned even for unauthenticated requests. Depending on which lookup misses, the `detail` string is `\"Not found.\"` (the common case) or `\"Session not found.\"`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "Not found."
                    }
                  }
                },
                "examples": {
                  "Unknown session": {
                    "summary": "sessionId does not match any KYC or KYB session",
                    "value": {
                      "detail": "Not found."
                    }
                  },
                  "Recently deleted session": {
                    "summary": "Session was deleted between lookups",
                    "value": {
                      "detail": "Session not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. PDF generation has a dedicated limit of **50 requests per minute per credential** (API key, Bearer token, or source IP when unauthenticated), in addition to the global 600/min GET limit. Wait `Retry-After` seconds (also reflected in the `X-RateLimit-*` headers), then retry. Reports are not cached server-side, so download each report once and store the file instead of re-fetching it.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "minimum": 1,
                  "example": 30
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of PDF generations allowed in the current window (50).",
                "schema": {
                  "type": "integer",
                  "example": 50
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the current window resets.",
                "schema": {
                  "type": "integer",
                  "example": 1750000000
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation of the rate-limit breach.",
                      "example": "Session PDF generation rate limit exceeded. You can make up to 50 requests per minute."
                    }
                  }
                },
                "examples": {
                  "Throttled": {
                    "summary": "More than 50 PDF generations in one minute from the same credential",
                    "value": {
                      "detail": "Session PDF generation rate limit exceeded. You can make up to 50 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --fail \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  --output report.pdf"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.get(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    stream=True,\n    timeout=60,\n)\nresponse.raise_for_status()\nwith open(\"report.pdf\", \"wb\") as fh:\n    for chunk in response.iter_content(chunk_size=8192):\n        fh.write(chunk)"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import { writeFile } from 'node:fs/promises';\n\nconst response = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/generate-pdf/',\n  { headers: { 'x-api-key': 'YOUR_API_KEY' } },\n);\nif (!response.ok) throw new Error(`PDF generation failed: HTTP ${response.status}`);\nawait writeFile('report.pdf', Buffer.from(await response.arrayBuffer()));"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/sandbox/arm/": {
      "post": {
        "summary": "Arm a sandbox scenario on a session",
        "description": "Persist a sandbox scenario on a `Not Started` session and expand its bundled magic values (email, phone, or `expected_details` fields) onto the session, so the mocked providers reproduce the scenario's outcome once the flow runs. This is the endpoint the pre-flow scenario picker in Didit's hosted verification UI calls when a tester chooses an outcome before starting capture. Build your own picker against it, or call it directly from a sandbox test harness.\n\nAuthenticate with the session's own `Session-Token` (returned in `session_token` by [Create Session](/sessions-api/create-session)), not your application `x-api-key`: this endpoint is meant to be called from the client, not your backend. A scenario is only accepted while `status` is `Not Started`. Calling it again while still `Not Started` re-arms the session: it swaps in the new scenario's magic values and clears only the values the *previous* scenario wrote, so any value the user already typed by hand (email, first name, etc.) survives the re-arm. Arming a session that has moved past `Not Started`, or that belongs to a live (non-sandbox) application, is rejected.\n\nSee [Sandbox & Test Data](/integration/sandbox-testing) for the full scenario catalog and the other two ways to drive an outcome: `sandbox_scenario` at session create, and typing magic values directly.",
        "operationId": "post_v3_session_sandbox_arm",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "SessionTokenAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the sandbox verification session to arm. Must match the session encoded in the Session-Token used to authenticate.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "scenario"
                ],
                "properties": {
                  "scenario": {
                    "type": "string",
                    "description": "Slug of the scenario to arm. See the catalog at GET /v1/sandbox/scenarios/ or the scenario table in [Sandbox & Test Data](/integration/sandbox-testing).",
                    "example": "decline_document_expired"
                  }
                }
              },
              "examples": {
                "Arm": {
                  "summary": "Arm the AML PEP-hit scenario",
                  "value": {
                    "scenario": "decline_aml_hit"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scenario armed. Its magic values are now on the session. `status` reflects the session's current status, which this call never changes: it is always `Not Started` on success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "scenario": {
                      "type": "string",
                      "description": "The armed scenario slug (echoes the request)."
                    },
                    "status": {
                      "type": "string",
                      "example": "Not Started"
                    }
                  }
                },
                "examples": {
                  "Armed": {
                    "summary": "Scenario armed on a Not Started session",
                    "value": {
                      "session_id": "11111111-2222-3333-4444-555555555555",
                      "scenario": "decline_aml_hit",
                      "status": "Not Started"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error: an unknown scenario slug, or the session has already progressed past `Not Started`.",
            "content": {
              "application/json": {
                "examples": {
                  "Unknown Scenario": {
                    "summary": "scenario is not in the catalog",
                    "value": {
                      "scenario": [
                        "Unknown sandbox scenario: 'not-a-real-scenario'."
                      ]
                    }
                  },
                  "Already Started": {
                    "summary": "Session moved past Not Started",
                    "value": [
                      "Scenario can only be armed before the verification starts."
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "The Session-Token does not resolve to this `session_id`, or the session belongs to a live (non-sandbox) application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not Found": {
                    "summary": "Live session, or session_id / token mismatch",
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/sandbox/arm/ \\\n  -H 'Session-Token: YOUR_SESSION_TOKEN' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"scenario\": \"decline_aml_hit\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/sandbox/arm/\",\n    headers={\n        \"Session-Token\": \"YOUR_SESSION_TOKEN\",\n        \"Content-Type\": \"application/json\",\n    },\n    json={\"scenario\": \"decline_aml_hit\"},\n)\nresponse.raise_for_status()\nprint(response.json())  # {'session_id': '...', 'scenario': 'decline_aml_hit', 'status': 'Not Started'}"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/sandbox/arm/',\n  {\n    method: 'POST',\n    headers: {\n      'Session-Token': sessionToken,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({ scenario: 'decline_aml_hit' }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst { session_id, scenario, status } = await response.json();"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/update-status/": {
      "patch": {
        "summary": "Approve, decline, or request resubmission for a verification session",
        "description": "Manually override the final decision of a KYC or KYB verification session. Set `new_status` to `Approved` or `Declined` to record a manual decision, or to `Resubmitted` to clear specific verification steps and let the user redo them through the same verification URL. The endpoint accepts both user (KYC) and business (KYB) session IDs.\n\nCall it once a session has reached a reviewable state: the current status must be `Approved`, `Declined`, `In Review`, `Kyc Expired`, `Abandoned`, or `Resubmitted`. Sessions that are still `Not Started`, `In Progress`, or `Awaiting User`, or that ended as `Expired`, return `400`. The new status must differ from the current one, and your API key's organization needs the `write:sessions` permission. The eligible-state check runs before body validation, so an ineligible session returns the `Wrong Current Status` error even when the payload is also invalid.\n\nFor `Resubmitted`, pass `nodes_to_resubmit` to choose which workflow steps the user must redo, or omit it to auto-select existing feature attempts in a resubmittable state (`Declined`, `In Review`, `Not Finished`, `Expired`). Never-attempted features are not auto-selected — list them explicitly in `nodes_to_resubmit`, or the request returns `400` when no recorded attempt needs resubmission. Captured data for the selected steps is deleted, the steps are reordered to match the workflow graph, the session's expiration window restarts, and the original verification URL becomes usable again. Backend-only steps (`AML`, `DATABASE_VALIDATION`, `IP_ANALYSIS`) at the head of the list run immediately without user interaction; if every resubmitted step is backend-only, the session re-finalizes within the same request. `KYB_REGISTRY` and `KYB_KEY_PEOPLE` cannot be resubmitted directly — resubmit the relevant child KYC sessions instead and the parent business session recomputes automatically.\n\nEvery successful call fires the `status.updated` [webhook](/integration/webhooks) once the change commits and appends an activity entry — with actor attribution and your `comment` — to the session's `reviews`, visible in [Get Decision](#get-/v3/session/-sessionId-/decision/) and in the console activity timeline. The user-profile aggregates linked to the session's `vendor_data` update as well. Declining disables ongoing AML monitoring for the session; re-approving re-enables it (from `Resubmitted`, `Declined`, or `Kyc Expired`) when the workflow has monitoring turned on. Approving or declining a child KYC that belongs to a KYB key-people check recomputes the parent business session's status. Set `send_email: true` (with `email_address`) to notify the user: a status notice for `Approved`/`Declined`, or a resubmission email containing the verification link and per-step reasons for `Resubmitted`.\n\nThe operation is intentionally not repeatable with the same value: re-sending the current status returns `400` (`The new status is the same as the current status.`), so accidental double-submissions are harmless. Authentication and permission failures both return `403` — this API never responds `401`.",
        "operationId": "patch_v3_session_update_status",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the verification session to update. Accepts both user (KYC) and business (KYB) session IDs — the service resolves the ID across both session types.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "new_status"
                ],
                "properties": {
                  "new_status": {
                    "type": "string",
                    "description": "Target status. `Approved` and `Declined` record a final manual decision (each can also overturn the other). `Resubmitted` clears the selected steps and sends the session back to the user. Any other value returns `400`.",
                    "enum": [
                      "Approved",
                      "Declined",
                      "Resubmitted"
                    ],
                    "example": "Approved"
                  },
                  "comment": {
                    "type": "string",
                    "description": "Free-text reason for the change, stored on the session's review trail and returned in the `reviews` array of [Get Decision](#get-/v3/session/-sessionId-/decision/). For example `Duplicated user`.",
                    "example": "All checks passed manual review"
                  },
                  "nodes_to_resubmit": {
                    "type": "array",
                    "description": "Workflow steps the user must redo. Only acted on when `new_status` is `Resubmitted`. For `Approved`/`Declined` the entries are still schema-validated (an invalid `feature` value returns `400`) but schema-valid entries are semantically ignored. If omitted, the server auto-selects existing OCR, Liveness, Face Match, POA, Phone, Email, AML, Database Validation, and Questionnaire attempts whose status is `Declined`, `In Review`, `Not Finished`, or `Expired` (NFC, IP analysis, age estimation, face search, and KYB document attempts are never auto-selected; non-face-match face attempts are selected as `LIVENESS`) — features the user never attempted (no recorded attempt) are NOT selected, so a session with zero attempts returns `400` (\"No features found that need resubmission\") even though nothing was approved; pass `nodes_to_resubmit` explicitly in that case. Steps are executed in workflow-graph order regardless of the order you send them. `KYB_REGISTRY`, `KYB_KEY_PEOPLE`, and the `KYB` alias are rejected with `400` — those parent checks recompute from their child KYC sessions.",
                    "items": {
                      "type": "object",
                      "required": [
                        "node_id",
                        "feature"
                      ],
                      "properties": {
                        "node_id": {
                          "type": "string",
                          "description": "Node identifier as it appears in the session's workflow definition (for example `feature_ocr`, `feature_liveness`).",
                          "example": "feature_ocr"
                        },
                        "feature": {
                          "type": "string",
                          "description": "Feature type of the node. The aliases `ID_VERIFICATION`, `POA`, `PHONE`, and `EMAIL` are normalized server-side to `OCR`, `PROOF_OF_ADDRESS`, `PHONE_VERIFICATION`, and `EMAIL_VERIFICATION`. `KYB_REGISTRY`, `KYB_KEY_PEOPLE`, and `KYB` pass schema validation but are always rejected with the business-rule `400` shown in the examples.",
                          "enum": [
                            "OCR",
                            "OCR_BACK",
                            "NFC",
                            "AML",
                            "FACE",
                            "LIVENESS",
                            "FACE_MATCH",
                            "IP_ANALYSIS",
                            "AGE_ESTIMATION",
                            "PROOF_OF_ADDRESS",
                            "PHONE_VERIFICATION",
                            "EMAIL_VERIFICATION",
                            "FACE_SEARCH",
                            "DATABASE_VALIDATION",
                            "QUESTIONNAIRE",
                            "DOCUMENT_AI",
                            "KYB_DOCUMENTS",
                            "ID_VERIFICATION",
                            "POA",
                            "PHONE",
                            "EMAIL",
                            "KYB_REGISTRY",
                            "KYB_KEY_PEOPLE",
                            "KYB"
                          ],
                          "example": "OCR"
                        }
                      }
                    }
                  },
                  "send_email": {
                    "type": "boolean",
                    "description": "Whether to email the user about the change. Requires `email_address`. For `Approved`/`Declined` the user receives a status notice; for `Resubmitted` the email includes the verification link and the per-step resubmission reasons.",
                    "default": false,
                    "example": false
                  },
                  "email_address": {
                    "type": "string",
                    "format": "email",
                    "description": "Recipient for the notification email. **Required when `send_email` is `true`** — omitting it returns `400`.",
                    "example": "user@example.com"
                  },
                  "email_language": {
                    "type": "string",
                    "description": "Language for the notification email. Accepts any string at schema level; unsupported codes silently fall back to English (`en`).",
                    "default": "en",
                    "example": "en"
                  },
                  "email_preview_token": {
                    "type": "string",
                    "writeOnly": true,
                    "minLength": 1,
                    "maxLength": 512,
                    "description": "Optional signed receipt from Preview Resubmission Email. When supplied with send_email=true and new_status=Resubmitted, the recipient, language, checks, current session state, sender and message must still match the preview. A changed or expired receipt returns 409 before changing the session or sending email. Existing integrations may omit this field."
                  }
                }
              },
              "examples": {
                "Approve Session": {
                  "summary": "Approve a session after manual review",
                  "value": {
                    "new_status": "Approved",
                    "comment": "All checks passed manual review"
                  }
                },
                "Decline Session": {
                  "summary": "Decline a session",
                  "value": {
                    "new_status": "Declined",
                    "comment": "Suspected fraud"
                  }
                },
                "Resubmit Specific Steps": {
                  "summary": "Request resubmission of chosen steps, with email",
                  "value": {
                    "new_status": "Resubmitted",
                    "nodes_to_resubmit": [
                      {
                        "node_id": "feature_ocr",
                        "feature": "OCR"
                      },
                      {
                        "node_id": "feature_liveness",
                        "feature": "LIVENESS"
                      }
                    ],
                    "send_email": true,
                    "email_address": "user@example.com",
                    "email_language": "en"
                  }
                },
                "Resubmit Auto-select": {
                  "summary": "Request resubmission (auto-select non-approved steps)",
                  "value": {
                    "new_status": "Resubmitted"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status updated. The response contains only the `session_id` — fetch the updated session via [Get Decision](#get-/v3/session/-sessionId-/decision/). The `status.updated` webhook fires once the change commits.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "UUID of the updated session."
                    }
                  }
                },
                "examples": {
                  "Updated": {
                    "summary": "Returned for Approved, Declined, and Resubmitted alike",
                    "value": {
                      "session_id": "3472fb7c-8f7c-4d1a-9cf4-cf3d74ce1a60"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field errors arrive as `{\"<field>\": [\"<message>\"]}` (some business-rule rejections use a string value instead: `{\"nodes_to_resubmit\": \"<message>\"}`), cross-state errors as `{\"detail\": \"<message>\"}`, and the same-status error as a bare JSON array.",
            "content": {
              "application/json": {
                "examples": {
                  "Wrong Current Status": {
                    "summary": "Session is not in an updatable state",
                    "value": {
                      "detail": "Only sessions with status Approved, Declined, In Review, Kyc Expired, Abandoned, Resubmitted can be updated. Current status: In Progress"
                    }
                  },
                  "Invalid Status Value": {
                    "summary": "new_status is a real session status but not one of Approved/Declined/Resubmitted",
                    "value": {
                      "new_status": [
                        "You can only update the status to 'Approved', 'Declined', or 'Resubmitted'."
                      ]
                    }
                  },
                  "Missing new_status": {
                    "summary": "Required field omitted",
                    "value": {
                      "new_status": [
                        "This field is required."
                      ]
                    }
                  },
                  "Same Status": {
                    "summary": "New status equals the current status",
                    "value": [
                      "The new status is the same as the current status."
                    ]
                  },
                  "Email Address Required": {
                    "summary": "send_email true without email_address",
                    "value": {
                      "email_address": [
                        "Email address is required when send_email is true."
                      ]
                    }
                  },
                  "Non-resubmittable Feature": {
                    "summary": "Resubmit targets a KYB parent check",
                    "value": {
                      "nodes_to_resubmit": "The following features cannot be resubmitted directly: KYB_REGISTRY. Resubmit the relevant child KYC sessions instead; the parent will recompute automatically."
                    }
                  },
                  "Nothing To Resubmit": {
                    "summary": "Auto-select found no non-approved features",
                    "value": {
                      "nodes_to_resubmit": "No features found that need resubmission. All features are already approved."
                    }
                  },
                  "Invalid Feature Choice": {
                    "summary": "Unknown feature in nodes_to_resubmit",
                    "value": {
                      "nodes_to_resubmit": [
                        {
                          "feature": [
                            "\"BOGUS\" is not a valid choice. Valid choices are: OCR, OCR_BACK, NFC, AML, FACE, LIVENESS, FACE_MATCH, IP_ANALYSIS, AGE_ESTIMATION, PROOF_OF_ADDRESS, PHONE_VERIFICATION, EMAIL_VERIFICATION, FACE_SEARCH, DATABASE_VALIDATION, QUESTIONNAIRE, KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE, ID_VERIFICATION, POA, PHONE, EMAIL, KYB"
                          ]
                        }
                      ]
                    }
                  },
                  "Invalid Status Value (not a status at all)": {
                    "summary": "new_status is not a valid StatusChoices value",
                    "value": {
                      "new_status": [
                        "\"Bogus\" is not a valid choice."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "API key lacks write:sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No KYC or KYB session with this `session_id` exists in your application (deleted sessions also return `404`).",
            "content": {
              "application/json": {
                "examples": {
                  "Not Found": {
                    "summary": "Unknown session_id",
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "A resubmit targeting only backend-only features (AML, DATABASE_VALIDATION, IP_ANALYSIS) was repeated within the 30-second cooldown window; an immediate repeat cannot change the outcome. Back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Backend-only resubmit throttled": {
                    "value": {
                      "detail": "This session was already resubmitted for backend-only features within the last 30 seconds; repeating it cannot change the outcome. Wait before resubmitting again."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "The email preview changed or expired. Generate a new preview before confirming; no session changes or email delivery occur."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-status/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"new_status\": \"Approved\",\n    \"comment\": \"All checks passed manual review\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-status/\",\n    headers={\n        \"x-api-key\": \"YOUR_API_KEY\",\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"new_status\": \"Resubmitted\",\n        \"nodes_to_resubmit\": [\n            {\"node_id\": \"feature_ocr\", \"feature\": \"OCR\"},\n            {\"node_id\": \"feature_liveness\", \"feature\": \"LIVENESS\"},\n        ],\n        \"send_email\": True,\n        \"email_address\": \"user@example.com\",\n        \"email_language\": \"en\",\n    },\n)\nresponse.raise_for_status()\nprint(response.json())  # {'session_id': '11111111-2222-3333-4444-555555555555'}"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-status/',\n  {\n    method: 'PATCH',\n    headers: {\n      'x-api-key': process.env.DIDIT_API_KEY,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      new_status: 'Declined',\n      comment: 'Suspected fraud',\n    }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst { session_id } = await response.json();"
          }
        ]
      }
    },
    "/v3/id-verification/": {
      "post": {
        "summary": "ID Verification (document OCR + fraud checks)",
        "description": "OCR an identity document and run document fraud checks in one call — returns the extracted holder fields, the parsed MRZ, an `Approved`/`Declined` `status`, and a `warnings` list explaining every issue found. Supports 14,000+ document types from 220+ countries and territories.\n\n**How it works.** Send the document's `front_image` (required) and, for two-sided documents, the `back_image`. Upload uncropped photos with all four corners of the document visible — the service detects, aligns, and crops the document itself, so do not pre-crop. The document is classified automatically (you never declare the country or document type), the visual zone is read with OCR, and the MRZ and any barcodes are decoded. Cross-checks then validate dates, number formats, and MRZ check digits, and compare the visual zone against the MRZ. With `perform_document_liveness=true`, the images are additionally screened for screen replays, printed copies, and portrait manipulation.\n\n**Decision logic.** `status` is `Approved` unless at least one warning resolves to a decline. Fraud and hard-failure risks always decline: `DOCUMENT_EXPIRED`, `SCREEN_CAPTURE_DETECTED`, `PRINTED_COPY_DETECTED`, `PORTRAIT_MANIPULATION_DETECTED`, `PUBLIC_DOCUMENT_IMAGE_DETECTED`, plus extraction failures (`NAME_NOT_DETECTED`, `DATE_OF_BIRTH_NOT_DETECTED`, `DOCUMENT_NUMBER_NOT_DETECTED`). (`PORTRAIT_IMAGE_NOT_DETECTED`, `COULD_NOT_DETECT_DOCUMENT_TYPE`, `INVALID_DATE`, and `MRZ_NOT_DETECTED` exist in workflow sessions but are never produced by this standalone endpoint.) Three risk groups are configurable per request via `invalid_mrz_action`, `inconsistent_data_action`, and `expiration_date_not_detected_action` (`DECLINE` or `NO_ACTION`). All other warnings (e.g. `POSSIBLE_DUPLICATED_USER`) are informational and never decline on their own. A document that cannot be processed at all returns `400` with `{\"error\": \"COULD_NOT_RECOGNIZE_DOCUMENT\"}`; a readable but problematic document returns `200` with `status: \"Declined\"` — always inspect `id_verification.status` and `id_verification.warnings`, not just the HTTP code.\n\n**Billing.** Each `200` response consumes one ID Verification API credit (standalone APIs have no free tier). When the organization's balance cannot cover the call, the endpoint returns `403` with the not-enough-credits error before any image processing.\n\n**Session persistence (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session: it appears in the Business Console, the returned `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/`, the cropped document/portrait images are stored and returned as short-lived media URLs (`https://<media-host>/ocr/...`), and a `status.updated` webhook is emitted to your configured webhook endpoints. When `false`, nothing is stored, `request_id` is a one-off correlation UUID, and `portrait_image`/`front_image`/`back_image` are returned inline as base64-encoded JPEG strings.\n\n**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload (a fictional \"Sandbox User\" USA identity card), no session is persisted, and no credits are consumed.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.",
        "operationId": "post_v3id-verification",
        "tags": [
          "Standalone APIs"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "front_image"
                ],
                "properties": {
                  "front_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Front side of the identity document. Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `webp`, `pdf`. Maximum upload size: **10 MB** (larger files are rejected with `400`). PDFs are rendered to an image before OCR; encrypted PDFs require `front_image_password`. Images are automatically compressed to ~0.5 MB and EXIF orientation is applied. Upload the full, uncropped capture with all four corners of the document visible."
                  },
                  "front_image_password": {
                    "type": "string",
                    "description": "Password to decrypt `front_image` when it is an encrypted PDF. Sending an encrypted PDF without (or with a wrong) password returns `400`.",
                    "writeOnly": true
                  },
                  "back_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Back side of the document — send it whenever the document has one (many ID cards carry the MRZ or a barcode on the back; omitting it simply leaves the MRZ and back-side fields empty in the response — this endpoint does not raise a missing-MRZ warning). Same format and size limits as `front_image`. When omitted, `back_image` and back-side fields are `null` in the response."
                  },
                  "back_image_password": {
                    "type": "string",
                    "description": "Password to decrypt `back_image` when it is an encrypted PDF.",
                    "writeOnly": true
                  },
                  "perform_document_liveness": {
                    "type": "boolean",
                    "default": true,
                    "description": "Screens both images for presentation fraud: screen replays (`SCREEN_CAPTURE_DETECTED`), printed copies (`PRINTED_COPY_DETECTED`), and portrait manipulation (`PORTRAIT_MANIPULATION_DETECTED`). Any of these auto-declines. Enabled by default; set to `false` to skip fraud screening and reduce latency.",
                    "example": true
                  },
                  "minimum_age": {
                    "type": "integer",
                    "nullable": true,
                    "default": null,
                    "minimum": 1,
                    "maximum": 120,
                    "description": "Accepted and validated (1–120) but **currently not applied** by this endpoint — it never produces a `MINIMUM_AGE_NOT_MET` warning from this field. Enforce age rules from the returned `date_of_birth`/`age`, or use a verification-session workflow with age restrictions."
                  },
                  "expiration_date_not_detected_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when no expiration date can be read (`EXPIRATION_DATE_NOT_DETECTED`). Default `NO_ACTION` because many identity documents print no expiry date. Note: a *detected and past* expiry date always declines (`DOCUMENT_EXPIRED`), regardless of this option."
                  },
                  "invalid_mrz_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when the extracted MRZ fails check-digit validation (`MRZ_VALIDATION_FAILED`). A missing MRZ raises no warning on this endpoint. Only relevant for documents that carry an MRZ. `REVIEW` is not supported on this endpoint and returns `400`."
                  },
                  "inconsistent_data_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when extracted data is internally inconsistent: `DATA_INCONSISTENT`, `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` (visual zone disagrees with the MRZ), or `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS`."
                  },
                  "critical_field_occlusion_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when a critical printed field was physically covered on the capture (`CRITICAL_FIELD_OCCLUSION_DETECTED`) - an identity number, a name, the date of birth, or the expiry date. Declines by default, like this endpoint's other document-integrity risks: covering the numbers a report is reconciled against is what a redacted document looks like. The value read for a covered field is dropped from the extraction either way, so the matching `*_NOT_DETECTED` warning usually accompanies it. `REVIEW` is not supported on this endpoint and returns `400`."
                  },
                  "document_or_personal_number_format_mismatch_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when a number does not match the format its issuing authority uses for that document type (`DOCUMENT_NUMBER_FORMAT_MISMATCH`, `PERSONAL_NUMBER_FORMAT_MISMATCH`). Default `NO_ACTION`, which reports the warning without changing the status. `REVIEW` is not supported on this endpoint and returns `400`."
                  },
                  "preferred_characters": {
                    "type": "string",
                    "enum": [
                      "latin",
                      "non_latin"
                    ],
                    "default": "latin",
                    "description": "Preferred script for name/address fields on documents that print both Latin and non-Latin text (Arabic, Cyrillic, CJK, …). `latin` returns transliterated/Latin values; `non_latin` prefers the native script."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session — visible in the Business Console, retrievable via `GET /v3/session/{sessionId}/decision/` using the returned `request_id`, announced through a `status.updated` webhook, and with document images returned as media URLs. When `false`, nothing is stored, `request_id` is a transient UUID, and images are returned inline as base64 JPEG strings.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. `metadata={\"flow\":\"onboarding\"}`) — it is parsed into an object.",
                    "example": {
                      "flow": "onboarding"
                    }
                  }
                }
              },
              "example": {
                "front_image": "(binary JPEG/PNG/PDF of the document front)",
                "back_image": "(binary JPEG/PNG/PDF of the document back)",
                "perform_document_liveness": true,
                "save_api_request": true,
                "vendor_data": "user-123",
                "metadata": {
                  "flow": "onboarding"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document processed. `id_verification.status` is `Approved` or `Declined`; every detected issue is itemized in `id_verification.warnings`. A problematic document still returns `200` with `status: \"Declined\"` — inspect the body, not just the HTTP code. When `save_api_request=true`, `request_id` is the persisted session id and image fields are short-lived media URLs; with `save_api_request=false` they are inline base64 JPEG strings.",
            "content": {
              "application/json": {
                "examples": {
                  "Approved": {
                    "summary": "Two-sided ID card read cleanly (saved — images as media URLs)",
                    "value": {
                      "request_id": "11d219ed-d59c-4b1d-8d65-9b933f12d5b8",
                      "id_verification": {
                        "status": "Approved",
                        "document_type": "Identity Card",
                        "document_subtype": "ID_CARD_GENERIC",
                        "document_number": "CBX164224",
                        "personal_number": "20446581H",
                        "portrait_image": "https://<media-host>/ocr/11d219ed-d59c-4b1d-8d65-9b933f12d5b8-portrait_image-8c2f.jpg?signature=...",
                        "front_image": "https://<media-host>/ocr/11d219ed-d59c-4b1d-8d65-9b933f12d5b8-front_image-4a1e.jpg?signature=...",
                        "back_image": "https://<media-host>/ocr/11d219ed-d59c-4b1d-8d65-9b933f12d5b8-back_image-77b0.jpg?signature=...",
                        "front_image_camera_front": null,
                        "back_image_camera_front": null,
                        "front_image_camera_front_face_match_score": null,
                        "back_image_camera_front_face_match_score": null,
                        "front_image_quality_score": {
                          "focus_score": 78.0,
                          "brightness_score": 83.2,
                          "brightness_issue": "ok",
                          "is_document_fully_visible": true,
                          "resolution_score": 40.7,
                          "overall_score": 70.2
                        },
                        "back_image_quality_score": {
                          "focus_score": 100.0,
                          "brightness_score": 95.6,
                          "brightness_issue": "ok",
                          "is_document_fully_visible": true,
                          "resolution_score": 43.0,
                          "overall_score": 84.4
                        },
                        "date_of_birth": "1980-01-13",
                        "age": 46,
                        "expiration_date": "2032-03-31",
                        "date_of_issue": "2022-03-31",
                        "issuing_state": "ESP",
                        "issuing_state_name": "Spain",
                        "first_name": "Julio Francisco",
                        "last_name": "Fores Sena",
                        "full_name": "Julio Francisco Fores Sena",
                        "gender": "M",
                        "address": "Brda. Urb. El Cardonal 0052 52 Po3 B,Taco,San Cristobal De La Laguna,Santa Cruz De Tenerife",
                        "formatted_address": "Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz de Tenerife, Spain",
                        "place_of_birth": "Valencia, Valencia",
                        "marital_status": "UNKNOWN",
                        "nationality": "ESP",
                        "extra_fields": {
                          "first_surname": "Fores",
                          "second_surname": "Sena"
                        },
                        "mrz": {
                          "surname": "FORES SENA",
                          "name": "JULIO FRANCISCO",
                          "country": "ESP",
                          "nationality": "ESP",
                          "birth_date": "800113",
                          "expiry_date": "320331",
                          "sex": "M",
                          "document_type": "ID",
                          "document_number": "CBX164224",
                          "optional_data": "20446581H",
                          "optional_data_2": "",
                          "birth_date_hash": "9",
                          "expiry_date_hash": "8",
                          "document_number_hash": "3",
                          "final_hash": "3",
                          "personal_number": "20446581H",
                          "warnings": [],
                          "errors": [],
                          "mrz_type": "TD1",
                          "mrz_string": "IDESPCBX164224320446581H<<<<<<\n8001139M3203318ESP<<<<<<<<<<<3\nFORES<SENA<<JULIO<FRANCISCO<<<",
                          "mrz_key": "CBX164224380011393203318"
                        },
                        "parsed_address": {
                          "street_1": "Avenida el Cardonal 52",
                          "street_2": "b",
                          "city": "La Laguna",
                          "region": "Canarias",
                          "country": "ES",
                          "postal_code": "38108",
                          "address_type": "Avenida",
                          "formatted_address": "Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz de Tenerife, Spain",
                          "raw_results": {
                            "address_components": [
                              {
                                "long_name": "b",
                                "short_name": "b",
                                "types": [
                                  "subpremise"
                                ]
                              },
                              {
                                "long_name": "52",
                                "short_name": "52",
                                "types": [
                                  "street_number"
                                ]
                              },
                              {
                                "long_name": "Avenida el Cardonal",
                                "short_name": "Av. el Cardonal",
                                "types": [
                                  "route"
                                ]
                              },
                              {
                                "long_name": "La Laguna",
                                "short_name": "La Laguna",
                                "types": [
                                  "locality",
                                  "political"
                                ]
                              },
                              {
                                "long_name": "Spain",
                                "short_name": "ES",
                                "types": [
                                  "country",
                                  "political"
                                ]
                              },
                              {
                                "long_name": "38108",
                                "short_name": "38108",
                                "types": [
                                  "postal_code"
                                ]
                              }
                            ],
                            "formatted_address": "Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz de Tenerife, Spain",
                            "geometry": {
                              "location": {
                                "lat": 28.4501161,
                                "lng": -16.3004407
                              },
                              "location_type": "ROOFTOP"
                            },
                            "types": [
                              "street_address",
                              "subpremise"
                            ]
                          },
                          "document_location": {
                            "latitude": 28.4501161,
                            "longitude": -16.3004407
                          },
                          "label": "Spain Identity Card Address",
                          "is_verified": true,
                          "category": "Residential"
                        },
                        "warnings": [],
                        "barcodes": []
                      },
                      "vendor_data": "user-123",
                      "metadata": {
                        "flow": "onboarding"
                      },
                      "created_at": "2026-06-12T02:21:56.013573+00:00"
                    }
                  },
                  "Declined - expired document": {
                    "summary": "Front-only upload of an expired ID card",
                    "value": {
                      "request_id": "f61681b8-9422-4378-ac3e-04c6a247fb45",
                      "id_verification": {
                        "status": "Declined",
                        "document_type": "Identity Card",
                        "document_subtype": "ID_CARD_GENERIC",
                        "document_number": "BNK123072",
                        "personal_number": "21771255F",
                        "portrait_image": "https://<media-host>/ocr/f61681b8-9422-4378-ac3e-04c6a247fb45-portrait_image-1d9a.jpg?signature=...",
                        "front_image": "https://<media-host>/ocr/f61681b8-9422-4378-ac3e-04c6a247fb45-front_image-5c2b.jpg?signature=...",
                        "back_image": null,
                        "front_image_camera_front": null,
                        "back_image_camera_front": null,
                        "front_image_camera_front_face_match_score": null,
                        "back_image_camera_front_face_match_score": null,
                        "front_image_quality_score": {
                          "focus_score": 100.0,
                          "brightness_score": 95.7,
                          "brightness_issue": "ok",
                          "is_document_fully_visible": true,
                          "resolution_score": 22.2,
                          "overall_score": 79.3
                        },
                        "back_image_quality_score": null,
                        "date_of_birth": "1997-01-30",
                        "age": 29,
                        "expiration_date": "2025-11-26",
                        "date_of_issue": null,
                        "issuing_state": "ESP",
                        "issuing_state_name": "Spain",
                        "first_name": "Lucia",
                        "last_name": "Marin Castro",
                        "full_name": "Lucia Marin Castro",
                        "gender": "F",
                        "address": null,
                        "formatted_address": null,
                        "place_of_birth": null,
                        "marital_status": "UNKNOWN",
                        "nationality": "ESP",
                        "extra_fields": {
                          "first_surname": "Marin",
                          "second_surname": "Castro"
                        },
                        "mrz": {},
                        "parsed_address": null,
                        "warnings": [
                          {
                            "risk": "DOCUMENT_EXPIRED",
                            "feature": "ID_VERIFICATION",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Document expired",
                            "long_description": "The document's expiration date has passed, rendering it no longer valid for use."
                          }
                        ],
                        "barcodes": []
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T02:25:48.117204+00:00"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "id_verification": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined"
                          ],
                          "description": "`Approved` when no warning resolves to a decline; `Declined` otherwise — the `warnings` list explains why."
                        },
                        "document_type": {
                          "type": "string",
                          "nullable": true,
                          "description": "Detected document type display name: `Identity Card`, `Passport`, `Driver's License`, `Residence Permit`, `Health Insurance Card`, or `Tax Card`. `null` when the document could not be classified.",
                          "example": "Identity Card"
                        },
                        "document_subtype": {
                          "type": "string",
                          "nullable": true,
                          "description": "Finer-grained subtype when available (e.g. `ID_CARD_GENERIC`, `EPASSPORT`).",
                          "example": "ID_CARD_GENERIC"
                        },
                        "document_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "CBX164224"
                        },
                        "personal_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "Secondary personal/national number printed on some documents.",
                          "example": "20446581H"
                        },
                        "portrait_image": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cropped portrait photo from the document. A short-lived media URL (`https://<media-host>/ocr/...`) when `save_api_request=true` (default); an inline base64-encoded JPEG string when `save_api_request=false`. `null` when no portrait was detected."
                        },
                        "front_image": {
                          "type": "string",
                          "nullable": true,
                          "description": "Aligned crop of the document front. Media URL when saved, inline base64 JPEG otherwise."
                        },
                        "back_image": {
                          "type": "string",
                          "nullable": true,
                          "description": "Aligned crop of the document back. `null` when no `back_image` was uploaded."
                        },
                        "front_image_camera_front": {
                          "type": "string",
                          "nullable": true,
                          "description": "Always `null` on this endpoint (populated only in camera-capture verification sessions)."
                        },
                        "back_image_camera_front": {
                          "type": "string",
                          "nullable": true,
                          "description": "Always `null` on this endpoint."
                        },
                        "front_image_camera_front_face_match_score": {
                          "type": "number",
                          "nullable": true,
                          "description": "Always `null` on this endpoint."
                        },
                        "back_image_camera_front_face_match_score": {
                          "type": "number",
                          "nullable": true,
                          "description": "Always `null` on this endpoint."
                        },
                        "front_image_quality_score": {
                          "type": "object",
                          "nullable": true,
                          "description": "Capture-quality diagnostics for the uploaded image (`null` when the side was not provided or scoring failed). All scores are 0–100.",
                          "properties": {
                            "focus_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Sharpness of the document crop (higher is sharper)."
                            },
                            "brightness_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Exposure quality (higher is better)."
                            },
                            "brightness_issue": {
                              "type": "string",
                              "nullable": true,
                              "description": "`ok` when exposure is fine, otherwise the detected issue (e.g. too dark / too bright)."
                            },
                            "is_document_fully_visible": {
                              "type": "boolean",
                              "nullable": true,
                              "description": "Whether all four corners of the document are inside the frame."
                            },
                            "resolution_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Effective resolution of the document area."
                            },
                            "overall_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Aggregate quality score."
                            }
                          }
                        },
                        "back_image_quality_score": {
                          "type": "object",
                          "nullable": true,
                          "description": "Capture-quality diagnostics for the uploaded image (`null` when the side was not provided or scoring failed). All scores are 0–100.",
                          "properties": {
                            "focus_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Sharpness of the document crop (higher is sharper)."
                            },
                            "brightness_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Exposure quality (higher is better)."
                            },
                            "brightness_issue": {
                              "type": "string",
                              "nullable": true,
                              "description": "`ok` when exposure is fine, otherwise the detected issue (e.g. too dark / too bright)."
                            },
                            "is_document_fully_visible": {
                              "type": "boolean",
                              "nullable": true,
                              "description": "Whether all four corners of the document are inside the frame."
                            },
                            "resolution_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Effective resolution of the document area."
                            },
                            "overall_score": {
                              "type": "number",
                              "format": "float",
                              "description": "Aggregate quality score."
                            }
                          }
                        },
                        "date_of_birth": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "example": "1980-01-13"
                        },
                        "age": {
                          "type": "integer",
                          "nullable": true,
                          "description": "Holder age in years, computed from `date_of_birth`.",
                          "example": 46
                        },
                        "expiration_date": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "example": "2032-03-31"
                        },
                        "date_of_issue": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "example": "2022-03-31"
                        },
                        "issuing_state": {
                          "type": "string",
                          "nullable": true,
                          "description": "Issuing country (ISO 3166-1 alpha-3).",
                          "example": "ESP"
                        },
                        "issuing_state_name": {
                          "type": "string",
                          "nullable": true,
                          "example": "Spain"
                        },
                        "first_name": {
                          "type": "string",
                          "nullable": true,
                          "example": "Julio Francisco"
                        },
                        "last_name": {
                          "type": "string",
                          "nullable": true,
                          "example": "Fores Sena"
                        },
                        "full_name": {
                          "type": "string",
                          "nullable": true,
                          "example": "Julio Francisco Fores Sena"
                        },
                        "gender": {
                          "type": "string",
                          "nullable": true,
                          "description": "`M`, `F`, or `null` when not printed/detected.",
                          "example": "M"
                        },
                        "address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Address exactly as printed on the document."
                        },
                        "formatted_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Geocoded, normalized version of `address`."
                        },
                        "place_of_birth": {
                          "type": "string",
                          "nullable": true,
                          "example": "Valencia, Valencia"
                        },
                        "marital_status": {
                          "type": "string",
                          "nullable": true,
                          "description": "`UNKNOWN` unless the document prints marital status.",
                          "example": "UNKNOWN"
                        },
                        "nationality": {
                          "type": "string",
                          "nullable": true,
                          "description": "Holder nationality (ISO 3166-1 alpha-3).",
                          "example": "ESP"
                        },
                        "extra_fields": {
                          "type": "object",
                          "nullable": true,
                          "additionalProperties": true,
                          "description": "Document-specific extras that have no dedicated column (e.g. `first_surname`/`second_surname` on Spanish IDs, license classes on driving licenses)."
                        },
                        "mrz": {
                          "type": "object",
                          "description": "Parsed machine-readable zone. An **empty object** (`{}`) when the document has no MRZ or it could not be read — also check the `warnings` list in that case. Dates inside the MRZ use the raw `YYMMDD` format.",
                          "properties": {
                            "surname": {
                              "type": "string",
                              "example": "FORES SENA"
                            },
                            "name": {
                              "type": "string",
                              "example": "JULIO FRANCISCO"
                            },
                            "country": {
                              "type": "string",
                              "description": "Issuing country (ISO 3166-1 alpha-3).",
                              "example": "ESP"
                            },
                            "nationality": {
                              "type": "string",
                              "description": "Holder nationality (ISO 3166-1 alpha-3).",
                              "example": "ESP"
                            },
                            "birth_date": {
                              "type": "string",
                              "description": "Raw MRZ date of birth (`YYMMDD`).",
                              "example": "800113"
                            },
                            "expiry_date": {
                              "type": "string",
                              "description": "Raw MRZ expiry date (`YYMMDD`).",
                              "example": "320331"
                            },
                            "sex": {
                              "type": "string",
                              "example": "M"
                            },
                            "document_type": {
                              "type": "string",
                              "description": "MRZ document-type code (e.g. `ID`, `P`).",
                              "example": "ID"
                            },
                            "document_number": {
                              "type": "string",
                              "example": "CBX164224"
                            },
                            "optional_data": {
                              "type": "string",
                              "nullable": true,
                              "example": "20446581H"
                            },
                            "optional_data_2": {
                              "type": "string",
                              "nullable": true,
                              "example": ""
                            },
                            "birth_date_hash": {
                              "type": "string",
                              "description": "MRZ check digit for the birth date.",
                              "example": "9"
                            },
                            "expiry_date_hash": {
                              "type": "string",
                              "description": "MRZ check digit for the expiry date.",
                              "example": "8"
                            },
                            "document_number_hash": {
                              "type": "string",
                              "description": "MRZ check digit for the document number.",
                              "example": "3"
                            },
                            "final_hash": {
                              "type": "string",
                              "description": "Composite MRZ check digit.",
                              "example": "3"
                            },
                            "personal_number": {
                              "type": "string",
                              "nullable": true,
                              "example": "20446581H"
                            },
                            "warnings": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "Non-fatal MRZ parsing warnings."
                            },
                            "errors": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "MRZ check-digit/parsing errors. Non-empty errors surface as an `MRZ_VALIDATION_FAILED` warning."
                            },
                            "mrz_type": {
                              "type": "string",
                              "description": "MRZ layout: `TD1` (ID cards, 3 lines), `TD2`, or `TD3` (passports, 2 lines).",
                              "example": "TD1"
                            },
                            "mrz_string": {
                              "type": "string",
                              "description": "Raw MRZ text as read, lines separated by `\\n`."
                            },
                            "mrz_key": {
                              "type": "string",
                              "description": "Composite key (document number + check digits) used for cross-checks."
                            }
                          }
                        },
                        "parsed_address": {
                          "type": "object",
                          "nullable": true,
                          "description": "Structured, geocoded breakdown of `address`. `null` when the document carries no address or it could not be parsed.",
                          "properties": {
                            "street_1": {
                              "type": "string",
                              "nullable": true,
                              "example": "Avenida el Cardonal 52"
                            },
                            "street_2": {
                              "type": "string",
                              "nullable": true,
                              "example": "b"
                            },
                            "city": {
                              "type": "string",
                              "nullable": true,
                              "example": "La Laguna"
                            },
                            "region": {
                              "type": "string",
                              "nullable": true,
                              "example": "Canarias"
                            },
                            "country": {
                              "type": "string",
                              "nullable": true,
                              "description": "ISO 3166-1 alpha-2 country code.",
                              "example": "ES"
                            },
                            "postal_code": {
                              "type": "string",
                              "nullable": true,
                              "example": "38108"
                            },
                            "address_type": {
                              "type": "string",
                              "nullable": true,
                              "example": "Avenida"
                            },
                            "formatted_address": {
                              "type": "string",
                              "nullable": true,
                              "description": "Canonical geocoded address string.",
                              "example": "Av. el Cardonal, 52, b, 38108 La Laguna, Santa Cruz de Tenerife, Spain"
                            },
                            "raw_results": {
                              "type": "object",
                              "additionalProperties": true,
                              "description": "Raw geocoding payload (`address_components`, `geometry.location`, `place_id`, …) for advanced consumers."
                            },
                            "document_location": {
                              "type": "object",
                              "nullable": true,
                              "properties": {
                                "latitude": {
                                  "type": "number"
                                },
                                "longitude": {
                                  "type": "number"
                                }
                              },
                              "description": "Geocoded coordinates of the document address."
                            },
                            "label": {
                              "type": "string",
                              "nullable": true,
                              "description": "Which document field the address was read from.",
                              "example": "Spain Identity Card Address"
                            },
                            "is_verified": {
                              "type": "boolean",
                              "description": "Whether geocoding confirmed the address exists."
                            },
                            "category": {
                              "type": "string",
                              "nullable": true,
                              "description": "Address category (e.g. `Residential`, `Commercial`).",
                              "example": "Residential"
                            }
                          }
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Empty on a clean approval. Every entry explains one detected risk; entries with `log_type: \"error\"` set `status` to `Declined`.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "description": "Machine-readable risk code. Always-decline risks: `DOCUMENT_EXPIRED`, `MINIMUM_AGE_NOT_MET`, `PORTRAIT_IMAGE_NOT_DETECTED`, `SCREEN_CAPTURE_DETECTED`, `PRINTED_COPY_DETECTED`, `PORTRAIT_MANIPULATION_DETECTED`, `PUBLIC_DOCUMENT_IMAGE_DETECTED`, `INVALID_DATE`, `COULD_NOT_RECOGNIZE_DOCUMENT` (400-only, never a warning), `DOCUMENT_NUMBER_NOT_DETECTED`, `COULD_NOT_DETECT_DOCUMENT_TYPE`, `NAME_NOT_DETECTED`, `DATE_OF_BIRTH_NOT_DETECTED`. Governed by request options: `MRZ_NOT_DETECTED` / `MRZ_VALIDATION_FAILED` (`invalid_mrz_action`), `DATA_INCONSISTENT` / `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` / `DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS` (`inconsistent_data_action`), `EXPIRATION_DATE_NOT_DETECTED` (`expiration_date_not_detected_action`). Other risks (e.g. `POSSIBLE_DUPLICATED_USER`) are informational.",
                                "example": "DOCUMENT_EXPIRED"
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "ID_VERIFICATION"
                                ],
                                "description": "Feature that raised the warning. Always `ID_VERIFICATION` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Extra context for some risks (e.g. `POSSIBLE_DUPLICATED_USER` includes `duplicated_session_id`); `null` for most."
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error",
                                  "warning",
                                  "information"
                                ],
                                "description": "Severity. `error` warnings drive `status` to `Declined`; `information` entries are advisory and never decline on their own. (`warning` is not produced by this endpoint — its options only accept `DECLINE` or `NO_ACTION`.)"
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-line summary of the risk."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation of the risk."
                              }
                            }
                          }
                        },
                        "barcodes": {
                          "type": "array",
                          "description": "Barcodes decoded from the document (PDF417, QR, …). Empty when the document has none or none could be read.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string",
                                "description": "Barcode type (e.g. `PDF417`, `QR_CODE`, `UNKNOWN`)."
                              },
                              "position": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Location of the barcode in the image, when available."
                              },
                              "data": {
                                "type": "string",
                                "description": "Decoded payload."
                              },
                              "data_raw": {
                                "type": "string",
                                "description": "Raw (undecoded) payload, when different."
                              },
                              "side": {
                                "type": "string",
                                "nullable": true,
                                "description": "`front` or `back`."
                              }
                            }
                          }
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp (UTC) of when the response was generated."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or processing error. Field-level problems return DRF's standard envelope (one array of messages per offending field). Encrypted-PDF problems return `{\"detail\": ...}`. A document image in which no document can be recognized at all returns `{\"error\": \"COULD_NOT_RECOGNIZE_DOCUMENT\"}`. PDF uploads can additionally fail with \"The submitted PDF file is corrupted or invalid.\" or a no-pages error.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing front image": {
                    "summary": "`front_image` not included in the form data",
                    "value": {
                      "front_image": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Unsupported file extension": {
                    "summary": "File extension outside tiff/jpg/jpeg/png/webp/pdf",
                    "value": {
                      "front_image": [
                        "File extension “txt” is not allowed. Allowed extensions are: tiff, jpg, jpeg, png, webp, pdf."
                      ]
                    }
                  },
                  "File too large": {
                    "summary": "Upload exceeds the 10 MB limit",
                    "value": {
                      "front_image": [
                        "File size should not exceed 10 MB"
                      ]
                    }
                  },
                  "Invalid option value": {
                    "summary": "Options only accept DECLINE or NO_ACTION",
                    "value": {
                      "invalid_mrz_action": [
                        "\"REVIEW\" is not a valid choice."
                      ]
                    }
                  },
                  "Encrypted PDF": {
                    "summary": "PDF uploaded without the required password",
                    "value": {
                      "detail": "The PDF is encrypted. Please upload a decrypted PDF or a photo instead."
                    }
                  },
                  "Wrong PDF password": {
                    "summary": "`front_image_password` / `back_image_password` does not decrypt the PDF",
                    "value": {
                      "detail": "The PDF password is incorrect. Please provide the correct password."
                    }
                  },
                  "Document not recognized": {
                    "summary": "No identity document could be detected in the image",
                    "value": {
                      "error": "COULD_NOT_RECOGNIZE_DOCUMENT"
                    }
                  },
                  "PDF conversion failure": {
                    "summary": "Uploaded PDF could not be converted to an image",
                    "value": {
                      "error": "Failed to convert front image PDF."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any image processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/id-verification/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'front_image=@./id_front.jpg' \\\n  -F 'back_image=@./id_back.jpg' \\\n  -F 'perform_document_liveness=true' \\\n  -F 'save_api_request=true' \\\n  -F 'vendor_data=user-123'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = 'https://verification.didit.me/v3/id-verification/'\nheaders = {'x-api-key': 'YOUR_API_KEY'}\n\nwith open('id_front.jpg', 'rb') as front_f, open('id_back.jpg', 'rb') as back_f:\n    files = {\n        'front_image': ('id_front.jpg', front_f, 'image/jpeg'),\n        'back_image': ('id_back.jpg', back_f, 'image/jpeg'),\n    }\n    data = {\n        'perform_document_liveness': 'true',\n        'save_api_request': 'true',\n        'vendor_data': 'user-123',\n    }\n    resp = requests.post(url, headers=headers, files=files, data=data, timeout=120)\n\nresp.raise_for_status()\nid_v = resp.json()['id_verification']\nprint('status:', id_v['status'])\nprint('name:', id_v.get('full_name'))\nprint('document:', id_v.get('document_type'), id_v.get('document_number'))\nfor w in id_v.get('warnings', []):\n    print('warning:', w['risk'], '-', w['log_type'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import fs from 'node:fs';\n\nconst form = new FormData();\nform.append('front_image', new Blob([fs.readFileSync('./id_front.jpg')]), 'id_front.jpg');\nform.append('back_image', new Blob([fs.readFileSync('./id_back.jpg')]), 'id_back.jpg');\nform.append('perform_document_liveness', 'true');\nform.append('save_api_request', 'true');\nform.append('vendor_data', 'user-123');\n\nconst response = await fetch('https://verification.didit.me/v3/id-verification/', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n  body: form,\n});\n\nif (!response.ok) throw new Error(`ID verification failed: ${response.status}`);\nconst body = await response.json();\nconsole.log('status:', body.id_verification.status);\nconsole.log('warnings:', body.id_verification.warnings.map((w) => w.risk));"
          }
        ]
      }
    },
    "/v3/face-match/": {
      "post": {
        "summary": "Face Match",
        "description": "Compare two face images (1:1) and get back a similarity `score` (0–100) plus an `Approved`/`Declined` `status`.\n\n**How it works.** Both images are decoded and analyzed by a biometric model (set `rotate_image=true` if captures may be sideways or upside down), then a similarity score between the two faces is computed. A score **strictly above** `face_match_score_decline_threshold` (default `30`) returns `status: \"Approved\"`; a score at or below it returns `Declined` with a `LOW_FACE_MATCH_SIMILARITY` warning. If no face pair can be scored at all, the call still returns `200` with `status: \"Declined\"` and a `NO_REFERENCE_IMAGE` warning — `score` is `null` on the default save path, or `0` with `save_api_request=false`. Submit one clear, front-facing face per image for best results.\n\n**Billing.** Each `200` response consumes one Face Match API credit (standalone APIs have no free tier). When the organization's balance cannot cover the call, the endpoint returns `403` with the not-enough-credits error before any image processing.\n\n**Session persistence (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session: it appears in the Business Console, the returned `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/`, both images are stored as the session's face-match source/target images, and a `status.updated` webhook is emitted to your configured webhook endpoints. When `false`, nothing is stored and `request_id` is a one-off correlation UUID that cannot be looked up later.\n\n**Face search index.** This endpoint never enrolls faces into your face search index and never runs blocklist or duplicate screening — use `POST /v3/passive-liveness/` or `POST /v3/face-search/` for those.\n\n**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload, no session is persisted, and no credits are consumed.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.",
        "operationId": "post_v3face-match",
        "tags": [
          "Standalone APIs"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "user_image",
                  "ref_image"
                ],
                "properties": {
                  "user_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Live or candidate face image to verify (e.g. a selfie). Submit a single front-facing photo with the subject's face clearly visible and well lit. Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `webp`. Maximum upload size: **5 MB** (larger files are rejected with `400`). Images are automatically compressed to ~0.5 MB before processing, so very high resolutions do not improve accuracy."
                  },
                  "ref_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Reference face image to compare against (e.g. an ID document portrait or a previously enrolled photo). Same format and size limits as `user_image`."
                  },
                  "face_match_score_decline_threshold": {
                    "type": "number",
                    "format": "float",
                    "default": 30,
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Similarity threshold (0–100) that drives the response `status`. A computed score **at or below** this value sets `status` to `Declined` and adds a `LOW_FACE_MATCH_SIMILARITY` warning; a score strictly above it returns `Approved`. Default `30` is permissive — raise it (e.g. `50`–`60`) for stricter verification. Values outside 0–100 return `400`.",
                    "example": 50
                  },
                  "rotate_image": {
                    "type": "boolean",
                    "default": false,
                    "description": "When `true`, the service tries the input images in 90-degree increments (0, 90, 180, 270) and uses the orientation that yields the best face detection — useful for mobile captures with missing EXIF orientation. Adds latency, so only enable it if you cannot guarantee upright images.",
                    "example": false
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session — visible in the Business Console, retrievable via `GET /v3/session/{sessionId}/decision/` using the returned `request_id`, and announced through a `status.updated` webhook. When `false`, nothing is stored and `request_id` is a transient UUID for response correlation only.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. `metadata={\"flow\":\"login\"}`) — it is parsed into an object.",
                    "example": {
                      "flow": "login",
                      "device_id": "abc123"
                    }
                  }
                }
              },
              "example": {
                "user_image": "(binary JPEG/PNG of the live selfie)",
                "ref_image": "(binary JPEG/PNG of the reference photo)",
                "face_match_score_decline_threshold": 50,
                "rotate_image": false,
                "save_api_request": true,
                "vendor_data": "user-123",
                "metadata": {
                  "flow": "login"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Face match computed. `face_match.score` is a 0–100 float (two decimals); `status` is `Approved` when the score is strictly above `face_match_score_decline_threshold`, otherwise `Declined` with an explanatory warning. A low similarity or unscorable pair still returns `200` — inspect `face_match.status` and `face_match.warnings`, not just the HTTP code. When `save_api_request=true`, `request_id` is the persisted session id.",
            "content": {
              "application/json": {
                "examples": {
                  "Approved": {
                    "summary": "Same person — score above the threshold",
                    "value": {
                      "request_id": "f9f5a777-8002-44c6-baaf-128bcfd6e226",
                      "face_match": {
                        "status": "Approved",
                        "score": 99.41,
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                661,
                                728,
                                1688,
                                2188
                              ],
                              "confidence": 0.732973,
                              "age": 26.91,
                              "gender": "male",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "ref_image": {
                          "entities": [
                            {
                              "bbox": [
                                653,
                                745,
                                1691,
                                2185
                              ],
                              "confidence": 0.722082,
                              "age": 27.0,
                              "gender": "male",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": []
                      },
                      "vendor_data": "user-123",
                      "metadata": {
                        "flow": "login"
                      },
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  },
                  "Declined - low similarity": {
                    "summary": "Score at or below the decline threshold",
                    "value": {
                      "request_id": "7cdda24e-311a-46d3-a3bb-e5d9b564ce73",
                      "face_match": {
                        "status": "Declined",
                        "score": 24.87,
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                661,
                                728,
                                1688,
                                2188
                              ],
                              "confidence": 0.732973,
                              "age": 26.91,
                              "gender": "male",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "ref_image": {
                          "entities": [
                            {
                              "bbox": [
                                156,
                                234,
                                679,
                                898
                              ],
                              "confidence": 0.717775,
                              "age": 41.2,
                              "gender": "male",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": [
                          {
                            "risk": "LOW_FACE_MATCH_SIMILARITY",
                            "feature": "FACEMATCH",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Low face match similarity",
                            "long_description": "The facial features of the provided image don't closely match the reference image, suggesting a potential identity mismatch."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:08:19.859116+00:00"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "face_match": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined"
                          ],
                          "description": "`Approved` when the similarity score is strictly above `face_match_score_decline_threshold` and a score could be computed; `Declined` otherwise (a warning explains why)."
                        },
                        "score": {
                          "type": "number",
                          "format": "float",
                          "nullable": true,
                          "minimum": 0,
                          "maximum": 100,
                          "description": "Similarity score from 0 to 100 — the model's confidence that both images depict the same person. Rounded to two decimals only when `save_api_request` is true; with `save_api_request=false` the raw float is returned. `null` when no face pair could be scored (with the default `save_api_request=true`); with `save_api_request=false` the same condition can surface as `score: 0`. Either way a `NO_REFERENCE_IMAGE` warning is present and `status` is `Declined`.",
                          "example": 99.41
                        },
                        "user_image": {
                          "type": "object",
                          "description": "Face-detection results for the analyzed images.",
                          "properties": {
                            "entities": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "bbox": {
                                    "type": "array",
                                    "items": {
                                      "type": "integer"
                                    },
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "description": "Bounding box of the detected face as `[x_min, y_min, x_max, y_max]` pixel coordinates in the processed image.",
                                    "example": [
                                      661,
                                      728,
                                      1688,
                                      2188
                                    ]
                                  },
                                  "confidence": {
                                    "type": "number",
                                    "format": "float",
                                    "minimum": 0,
                                    "maximum": 1,
                                    "description": "Face-detection confidence (0–1).",
                                    "example": 0.732973
                                  },
                                  "age": {
                                    "type": "number",
                                    "format": "float",
                                    "description": "Model-estimated age of the detected face, in years. Informational only — it does not affect the face-match decision.",
                                    "example": 26.91
                                  },
                                  "gender": {
                                    "type": "string",
                                    "description": "Model-predicted gender of the detected face (`male` or `female`). Informational only.",
                                    "example": "male"
                                  },
                                  "race": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Reserved field — always `null` in responses from this endpoint.",
                                    "example": null
                                  }
                                }
                              },
                              "description": "One entry per detected face."
                            },
                            "best_angle": {
                              "type": "integer",
                              "description": "Rotation (degrees: 0, 90, 180, or 270) that produced the best face detection. Only non-zero when `rotate_image=true` corrected the orientation.",
                              "example": 0
                            }
                          }
                        },
                        "ref_image": {
                          "type": "object",
                          "description": "Face-detection results for the reference image, same shape as `user_image`.",
                          "properties": {
                            "entities": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "bbox": {
                                    "type": "array",
                                    "items": {
                                      "type": "integer"
                                    },
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "description": "Bounding box of the detected face as `[x_min, y_min, x_max, y_max]` pixel coordinates in the processed image.",
                                    "example": [
                                      661,
                                      728,
                                      1688,
                                      2188
                                    ]
                                  },
                                  "confidence": {
                                    "type": "number",
                                    "format": "float",
                                    "minimum": 0,
                                    "maximum": 1,
                                    "description": "Face-detection confidence (0–1).",
                                    "example": 0.732973
                                  },
                                  "age": {
                                    "type": "number",
                                    "format": "float",
                                    "description": "Model-estimated age of the detected face, in years. Informational only — it does not affect the face-match decision.",
                                    "example": 26.91
                                  },
                                  "gender": {
                                    "type": "string",
                                    "description": "Model-predicted gender of the detected face (`male` or `female`). Informational only.",
                                    "example": "male"
                                  },
                                  "race": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Reserved field — always `null` in responses from this endpoint.",
                                    "example": null
                                  }
                                }
                              },
                              "description": "One entry per detected face."
                            },
                            "best_angle": {
                              "type": "integer",
                              "example": 0
                            }
                          }
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Empty on a clean approval. `NO_REFERENCE_IMAGE` (`error`) — no face pair could be scored; `LOW_FACE_MATCH_SIMILARITY` (`error`) — score at or below the decline threshold. Any of these sets `status` to `Declined`.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "enum": [
                                  "NO_REFERENCE_IMAGE",
                                  "LOW_FACE_MATCH_SIMILARITY"
                                ],
                                "description": "Machine-readable risk code."
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "FACEMATCH"
                                ],
                                "description": "Feature that raised the warning. Always `FACEMATCH` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Always `null` for face-match warnings."
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error",
                                  "warning",
                                  "information"
                                ],
                                "description": "Severity. `error` warnings drive `status` to `Declined`; `warning` and `information` entries are advisory and never decline on their own."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-line summary of the risk."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation of the risk."
                              }
                            }
                          }
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp (UTC) of when the response was generated, e.g. `2026-06-12T01:04:42.763237+00:00`."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Returned when a required image is missing, exceeds 5 MB, has an unsupported extension, or when an option is out of range. The body is DRF's standard field-error envelope: one array of messages per offending field.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing required image": {
                    "summary": "`ref_image` (or `user_image`) not included in the form data",
                    "value": {
                      "ref_image": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Unsupported file extension": {
                    "summary": "File extension outside tiff/jpg/jpeg/png/webp",
                    "value": {
                      "user_image": [
                        "File extension “txt” is not allowed. Allowed extensions are: tiff, jpg, jpeg, png, webp."
                      ]
                    }
                  },
                  "File too large": {
                    "summary": "Upload exceeds the 5 MB limit",
                    "value": {
                      "user_image": [
                        "File size should not exceed 5 MB"
                      ]
                    }
                  },
                  "Threshold out of range": {
                    "summary": "`face_match_score_decline_threshold` outside 0–100",
                    "value": {
                      "face_match_score_decline_threshold": [
                        "Ensure this value is less than or equal to 100."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any image processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/face-match/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'user_image=@./selfie.jpg' \\\n  -F 'ref_image=@./id_portrait.jpg' \\\n  -F 'face_match_score_decline_threshold=50' \\\n  -F 'save_api_request=true' \\\n  -F 'vendor_data=user-123'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = 'https://verification.didit.me/v3/face-match/'\nheaders = {'x-api-key': 'YOUR_API_KEY'}\n\nwith open('selfie.jpg', 'rb') as user_f, open('id_portrait.jpg', 'rb') as ref_f:\n    files = {\n        'user_image': ('selfie.jpg', user_f, 'image/jpeg'),\n        'ref_image': ('id_portrait.jpg', ref_f, 'image/jpeg'),\n    }\n    data = {\n        'face_match_score_decline_threshold': 50,\n        'save_api_request': 'true',\n        'vendor_data': 'user-123',\n    }\n    resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)\n\nresp.raise_for_status()\nbody = resp.json()\nprint('status:', body['face_match']['status'])\nprint('score:', body['face_match']['score'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import fs from 'node:fs';\n\nconst form = new FormData();\nform.append('user_image', new Blob([fs.readFileSync('./selfie.jpg')]), 'selfie.jpg');\nform.append('ref_image', new Blob([fs.readFileSync('./id_portrait.jpg')]), 'id_portrait.jpg');\nform.append('face_match_score_decline_threshold', '50');\nform.append('save_api_request', 'true');\nform.append('vendor_data', 'user-123');\n\nconst response = await fetch('https://verification.didit.me/v3/face-match/', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n  body: form,\n});\n\nif (!response.ok) throw new Error(`Face match failed: ${response.status}`);\nconst body = await response.json();\nconsole.log('status:', body.face_match.status, 'score:', body.face_match.score);"
          }
        ]
      }
    },
    "/v3/age-estimation/": {
      "post": {
        "summary": "Age Estimation (face age + passive liveness)",
        "description": "Estimate a person's age from a single face photo and run a passive liveness check in the same call — returns the model-predicted `age_estimation` (in years), a liveness `score` (0–100), and an `Approved`/`Declined` `status`. The age is **model-predicted from the face, not verified against a document** — use it for age gates and low-friction checks, not as legal proof of age.\n\n**How it works.** The image is analyzed for faces (set `rotate_image=true` if captures may be sideways or upside down); each detected face gets an estimated age, and the largest face in the frame drives `age_estimation`. In parallel, a passive liveness model scores whether the photo shows a live person (no user challenge required) and detects presentation attacks (photos of photos, screens, masks). Submit one clear, front-facing, well-lit face per image for best results.\n\n**Decision logic.** Any warning declines: `status` is `Approved` only when the `warnings` array is empty. A liveness `score` at or below `face_liveness_score_decline_threshold` (default `30`) adds `LOW_LIVENESS_SCORE`; a detected attack adds `LIVENESS_FACE_ATTACK`; no face found by the liveness model adds `NO_FACE_DETECTED`; no estimable face age adds `AGE_NOT_DETECTED` (`age_estimation` is `null`); an estimated age below `age_estimation_decline_threshold` (default `18`) adds `AGE_BELOW_MINIMUM`. Borderline ages near your threshold deserve a fallback to document-based verification — the model's error grows for faces close to the limit.\n\n**Billing.** Each `200` response consumes one Age Estimation API credit (standalone APIs have no free tier). When the organization's balance cannot cover the call, the endpoint returns `403` with the not-enough-credits error before any image processing.\n\n**Session persistence (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session: it appears in the Business Console, the returned `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/` (the result is exposed there in `liveness_checks[]`, with `features: [\"AGE_ESTIMATION\"]`), the face crop and reference image are stored, the face embedding is added to your application's face index (used by face search and duplicate detection), and a `status.updated` webhook is emitted. When `false`, nothing is stored and `request_id` is a one-off correlation UUID that cannot be looked up later.\n\n**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload (`age_estimation: 30`, no warnings), no session is persisted, and no credits are consumed.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.",
        "operationId": "post_v3age-estimation",
        "tags": [
          "Standalone APIs"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "user_image"
                ],
                "properties": {
                  "user_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Face photo to analyze (e.g. a selfie). Submit a single front-facing photo with the subject's face clearly visible and well lit. Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `webp` (no PDF). Maximum upload size: **5 MB** (larger files are rejected with `400`). Images are automatically compressed to ~0.3 MB before processing, so very high resolutions do not improve accuracy."
                  },
                  "face_liveness_score_decline_threshold": {
                    "type": "number",
                    "format": "float",
                    "default": 30,
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Liveness threshold (0–100). A liveness `score` **at or below** this value adds a `LOW_LIVENESS_SCORE` warning and declines. Raise it for stricter anti-spoofing; values outside 0–100 return `400`.",
                    "example": 30
                  },
                  "age_estimation_decline_threshold": {
                    "type": "integer",
                    "default": 18,
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Minimum acceptable estimated age in years. An estimated age **below** this value adds an `AGE_BELOW_MINIMUM` warning and declines. Set `0` to disable the age check (the call then only runs liveness + age estimation without an age-based decision).",
                    "example": 18
                  },
                  "rotate_image": {
                    "type": "boolean",
                    "default": false,
                    "description": "When `true`, the service tries the input image in 90-degree increments (0, 90, 180, 270) and uses the orientation that yields the best face detection — useful for mobile captures with missing EXIF orientation. Adds latency, so only enable it if you cannot guarantee upright images.",
                    "example": false
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session — visible in the Business Console, retrievable via `GET /v3/session/{sessionId}/decision/` using the returned `request_id`, announced through a `status.updated` webhook, and with the detected face added to your application's face index. When `false`, nothing is stored and `request_id` is a transient UUID for response correlation only.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. `metadata={\"flow\":\"age-gate\"}`) — it is parsed into an object.",
                    "example": {
                      "flow": "age-gate"
                    }
                  }
                }
              },
              "example": {
                "user_image": "(binary JPEG/PNG of the selfie)",
                "face_liveness_score_decline_threshold": 30,
                "age_estimation_decline_threshold": 18,
                "rotate_image": false,
                "save_api_request": true,
                "vendor_data": "user-123",
                "metadata": {
                  "flow": "age-gate"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Age estimation and passive liveness completed. `age_estimation.age_estimation` is the model-predicted age in years of the largest detected face (`null` if none); `age_estimation.score` is the passive-liveness score (0–100); `status` is `Approved` only when `warnings` is empty. An underage or spoofed capture still returns `200` with `status: \"Declined\"` — inspect the body, not just the HTTP code. When `save_api_request=true`, `request_id` is the persisted session id.",
            "content": {
              "application/json": {
                "examples": {
                  "Approved": {
                    "summary": "Live adult face — both checks passed",
                    "value": {
                      "request_id": "0c40ba43-64ab-4e2e-b4b8-7d1f12f81bc1",
                      "age_estimation": {
                        "status": "Approved",
                        "method": "PASSIVE",
                        "score": 97.5,
                        "user_image": {
                          "entities": [
                            {
                              "age": 27.33,
                              "bbox": [
                                40,
                                40,
                                100,
                                100
                              ],
                              "confidence": 0.7177750468254089,
                              "gender": "male"
                            }
                          ],
                          "best_angle": 0
                        },
                        "age_estimation": 27.33,
                        "warnings": []
                      },
                      "vendor_data": "user-123",
                      "metadata": {
                        "flow": "age-gate"
                      },
                      "created_at": "2026-06-12T02:24:11.512941+00:00"
                    }
                  },
                  "Declined - age below threshold": {
                    "summary": "Estimated age below `age_estimation_decline_threshold`",
                    "value": {
                      "request_id": "9be41a6f-2f4e-4f57-92f4-b3a4f6f0a1c2",
                      "age_estimation": {
                        "status": "Declined",
                        "method": "PASSIVE",
                        "score": 95.0,
                        "user_image": {
                          "entities": [
                            {
                              "age": 16.5,
                              "bbox": [
                                40,
                                40,
                                100,
                                100
                              ],
                              "confidence": 0.7177750468254089,
                              "gender": "female"
                            }
                          ],
                          "best_angle": 0
                        },
                        "age_estimation": 16.5,
                        "warnings": [
                          {
                            "risk": "AGE_BELOW_MINIMUM",
                            "feature": "LIVENESS",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Age below minimum",
                            "long_description": "The age of the face is below the minimum age threshold for the application."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T02:26:40.118332+00:00"
                    }
                  },
                  "Declined - liveness too low": {
                    "summary": "Liveness score at or below the decline threshold (possible spoof)",
                    "value": {
                      "request_id": "5f6f2f1f-7c4f-43b9-8d62-0a8f4c2d9e77",
                      "age_estimation": {
                        "status": "Declined",
                        "method": "PASSIVE",
                        "score": 5.0,
                        "user_image": {
                          "entities": [
                            {
                              "age": 25.0,
                              "bbox": [
                                40,
                                40,
                                100,
                                100
                              ],
                              "confidence": 0.7177750468254089,
                              "gender": "male"
                            }
                          ],
                          "best_angle": 0
                        },
                        "age_estimation": 25.0,
                        "warnings": [
                          {
                            "risk": "LOW_LIVENESS_SCORE",
                            "feature": "LIVENESS",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Low liveness score",
                            "long_description": "The liveness check resulted in a low score, indicating potential use of non-live facial representations or poor-quality biometric data."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T02:27:02.901547+00:00"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "age_estimation": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined"
                          ],
                          "description": "`Approved` when no warnings were raised; `Declined` otherwise (every warning this endpoint produces declines)."
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "PASSIVE"
                          ],
                          "description": "Liveness method. Always `PASSIVE` on this endpoint (single-image, no user challenge)."
                        },
                        "score": {
                          "type": "number",
                          "format": "float",
                          "nullable": true,
                          "minimum": 0,
                          "maximum": 100,
                          "description": "Passive-liveness score from 0 to 100 — the model's confidence that the photo shows a live person. Compared against `face_liveness_score_decline_threshold`; at or below it the call declines with `LOW_LIVENESS_SCORE`. `null` when the liveness model returns no confidence — the call still declines with `LOW_LIVENESS_SCORE` because null is treated as 0 for the threshold comparison.",
                          "example": 97.5
                        },
                        "user_image": {
                          "type": "object",
                          "description": "Face-detection results for the analyzed image.",
                          "properties": {
                            "entities": {
                              "type": "array",
                              "description": "One entry per detected face. Empty when no face was found (then `age_estimation` is `null` and an `AGE_NOT_DETECTED` warning is added).",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "age": {
                                    "type": "number",
                                    "format": "float",
                                    "description": "Model-estimated age of this face, in years.",
                                    "example": 27.33
                                  },
                                  "bbox": {
                                    "type": "array",
                                    "items": {
                                      "type": "integer"
                                    },
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "description": "Bounding box of the detected face as `[x_min, y_min, x_max, y_max]` pixel coordinates in the processed image.",
                                    "example": [
                                      40,
                                      40,
                                      100,
                                      100
                                    ]
                                  },
                                  "confidence": {
                                    "type": "number",
                                    "format": "float",
                                    "minimum": 0,
                                    "maximum": 1,
                                    "description": "Face-detection confidence (0–1).",
                                    "example": 0.7177750468254089
                                  },
                                  "gender": {
                                    "type": "string",
                                    "description": "Model-predicted gender of the detected face (`male` or `female`). Informational only.",
                                    "example": "male"
                                  }
                                }
                              }
                            },
                            "best_angle": {
                              "type": "integer",
                              "nullable": true,
                              "description": "Rotation (degrees: 0, 90, 180, or 270) that produced the best face detection. Only non-zero when `rotate_image=true` corrected the orientation.",
                              "example": 0
                            }
                          }
                        },
                        "age_estimation": {
                          "type": "number",
                          "format": "float",
                          "nullable": true,
                          "description": "Model-predicted age in years of the **largest** detected face. `null` when no face age could be estimated (an `AGE_NOT_DETECTED` warning is added and the call declines).",
                          "example": 27.33
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Empty on a clean approval. Any entry sets `status` to `Declined`.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "enum": [
                                  "NO_FACE_DETECTED",
                                  "LOW_LIVENESS_SCORE",
                                  "LIVENESS_FACE_ATTACK",
                                  "AGE_NOT_DETECTED",
                                  "AGE_BELOW_MINIMUM"
                                ],
                                "description": "Machine-readable risk code. `NO_FACE_DETECTED` — the liveness model found no face; `LOW_LIVENESS_SCORE` — liveness `score` at or below `face_liveness_score_decline_threshold`; `LIVENESS_FACE_ATTACK` — a presentation attack (photo/screen/mask) was detected; `AGE_NOT_DETECTED` — no face age could be estimated; `AGE_BELOW_MINIMUM` — estimated age below `age_estimation_decline_threshold`. `NO_FACE_DETECTED` and `LOW_LIVENESS_SCORE` are mutually exclusive — when no face is found only `NO_FACE_DETECTED` is emitted."
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "LIVENESS"
                                ],
                                "description": "Feature that raised the warning. Always `LIVENESS` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Always `null` for age-estimation warnings."
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error"
                                ],
                                "description": "Severity. Every warning this endpoint produces is an `error` and sets `status` to `Declined`."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-line summary of the risk."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation of the risk."
                              }
                            }
                          }
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp (UTC) of when the response was generated."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Returned when `user_image` is missing, exceeds 5 MB, has an unsupported extension, or when a threshold is out of range. The body is DRF's standard field-error envelope: one array of messages per offending field.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing user image": {
                    "summary": "`user_image` not included in the form data",
                    "value": {
                      "user_image": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Unsupported file extension": {
                    "summary": "File extension outside tiff/jpg/jpeg/png/webp",
                    "value": {
                      "user_image": [
                        "File extension “txt” is not allowed. Allowed extensions are: tiff, jpg, jpeg, png, webp."
                      ]
                    }
                  },
                  "File too large": {
                    "summary": "Upload exceeds the 5 MB limit",
                    "value": {
                      "user_image": [
                        "File size should not exceed 5 MB"
                      ]
                    }
                  },
                  "Threshold out of range": {
                    "summary": "`face_liveness_score_decline_threshold` outside 0–100",
                    "value": {
                      "face_liveness_score_decline_threshold": [
                        "Ensure this value is less than or equal to 100."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any image processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/age-estimation/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'user_image=@./selfie.jpg' \\\n  -F 'age_estimation_decline_threshold=18' \\\n  -F 'face_liveness_score_decline_threshold=30' \\\n  -F 'save_api_request=true' \\\n  -F 'vendor_data=user-123'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = 'https://verification.didit.me/v3/age-estimation/'\nheaders = {'x-api-key': 'YOUR_API_KEY'}\n\nwith open('selfie.jpg', 'rb') as f:\n    files = {'user_image': ('selfie.jpg', f, 'image/jpeg')}\n    data = {\n        'age_estimation_decline_threshold': 18,\n        'face_liveness_score_decline_threshold': 30,\n        'save_api_request': 'true',\n        'vendor_data': 'user-123',\n    }\n    resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)\n\nresp.raise_for_status()\nresult = resp.json()['age_estimation']\nprint('status:', result['status'])\nprint('estimated age:', result['age_estimation'])\nprint('liveness score:', result['score'])\nfor w in result['warnings']:\n    print('warning:', w['risk'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import fs from 'node:fs';\n\nconst form = new FormData();\nform.append('user_image', new Blob([fs.readFileSync('./selfie.jpg')]), 'selfie.jpg');\nform.append('age_estimation_decline_threshold', '18');\nform.append('face_liveness_score_decline_threshold', '30');\nform.append('save_api_request', 'true');\nform.append('vendor_data', 'user-123');\n\nconst response = await fetch('https://verification.didit.me/v3/age-estimation/', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n  body: form,\n});\n\nif (!response.ok) throw new Error(`Age estimation failed: ${response.status}`);\nconst { age_estimation } = await response.json();\nconsole.log('status:', age_estimation.status, 'age:', age_estimation.age_estimation, 'liveness:', age_estimation.score);"
          }
        ]
      }
    },
    "/v3/poa/": {
      "post": {
        "summary": "Proof of Address (document OCR + address checks)",
        "description": "Extract and validate a Proof of Address document — utility bills, bank statements, and government-issued documents — in one call. Returns the issuer, issue/expiry dates, the holder name, the raw and parsed/geocoded address, an `Approved`/`Declined` `status`, and a `warnings` list explaining every issue found.\n\n**Latency.** Extraction is LLM-based: typical calls take **5–15 seconds**, multi-page PDFs up to **~30 seconds**. Configure a client timeout of **at least 45 seconds** and do not retry before the call completes.\n\n**How it works.** The document (image or PDF, up to 15 MB; encrypted PDFs require `document_password`) is classified into a document type and subtype (e.g. `UTILITY_BILL` / `WATER_BILL`), and the issuer, dates, holder name, and address are extracted with LLM-based extraction. The address is parsed and geocoded into `poa_parsed_address`. PDF/EXIF forensics screen for tampering — modification after digital signing, known PDF editors, overlay-text manipulation, suspicious re-exports — surfacing `SUSPECTED_DOCUMENT_MANIPULATION` or `DOCUMENT_METADATA_MISMATCH`. Document age is validated against `poa_document_age_months`, and the language against `poa_languages_allowed`. If you pass `expected_address`, `expected_country`, or `expected_first_name`/`expected_last_name`, the extracted values are cross-checked and mismatches are flagged.\n\n**Decision logic.** `status` is `Approved` unless at least one warning resolves to a decline. Hard failures always decline: `MISSING_ADDRESS_INFORMATION`, `POA_DOCUMENT_EXPIRED`, `INVALID_DOCUMENT_TYPE`, `UNABLE_TO_VALIDATE_DOCUMENT_AGE`, plus `UNABLE_TO_EXTRACT_ISSUE_DATE` and `POA_NAME_NOT_DETECTED` (not configurable on this endpoint). Five risk groups are configurable per request via the `poa_*_action` options (`DECLINE` or `NO_ACTION`, all defaulting to `DECLINE`). `POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION` and `UNPARSABLE_OR_INVALID_ADDRESS` are informational on this endpoint and never decline. A document that cannot be processed at all returns `400`; a readable but problematic document returns `200` with `status: \"Declined\"` — always inspect `poa.status` and `poa.warnings`, not just the HTTP code.\n\n**Billing.** Each `200` response consumes one Proof of Address API credit (standalone APIs have no free tier). When the organization's balance cannot cover the call, the endpoint returns `403` with the not-enough-credits error before any document processing.\n\n**Session persistence (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session: it appears in the Business Console, the uploaded document is stored, the returned `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/` (the decision additionally exposes `document_file` and the `document_metadata` forensics, which this response omits), and a `status.updated` webhook is emitted. When `false`, nothing is stored and `request_id` is a one-off correlation UUID that cannot be looked up later.\n\n**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload (a fictional \"Sandbox Power Co.\" electricity bill), no session is persisted, and no credits are consumed.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.\n\nNote: `FUTURE_ISSUE_DATE` and `POOR_DOCUMENT_QUALITY` exist in workflow sessions but are never produced by this standalone endpoint — a future-dated document is not auto-declined here.",
        "operationId": "post_v3poa",
        "tags": [
          "Standalone APIs"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "document"
                ],
                "properties": {
                  "document": {
                    "type": "string",
                    "format": "binary",
                    "description": "The Proof of Address document. Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `pdf`, `webp`. Maximum upload size: **15 MB** (larger files are rejected with `400`). Multi-page PDFs are supported (expect higher latency); encrypted PDFs require `document_password`. Images are automatically compressed before processing."
                  },
                  "document_password": {
                    "type": "string",
                    "description": "Password to decrypt `document` when it is an encrypted PDF. Sending an encrypted PDF without (or with a wrong) password returns `400`.",
                    "writeOnly": true
                  },
                  "expected_address": {
                    "type": "string",
                    "description": "Address to verify against the document. It is geocoded and compared with the extracted address; a mismatch (or an expected address that cannot be geocoded/verified) adds `ADDRESS_MISMATCH_WITH_PROVIDED`, governed by `poa_address_mismatch_action`. The geocoded form is echoed back in `expected_details_formatted_address` / `expected_details_parsed_address`.",
                    "example": "Av. Monseñor Tavella 1291, Salta, Argentina"
                  },
                  "expected_country": {
                    "type": "string",
                    "description": "Country to verify against the document (ISO 3166-1 code, e.g. `ARG` or `AR`). A mismatch with the document's country adds `POA_COUNTRY_MISMATCH_WITH_PROVIDED`, governed by `poa_address_mismatch_action`.",
                    "example": "ARG"
                  },
                  "expected_first_name": {
                    "type": "string",
                    "description": "First name to verify against `name_on_document` (fuzzy match, transliteration-aware). A score below the match threshold adds `NAME_MISMATCH_WITH_PROVIDED`, governed by `poa_address_mismatch_action`.",
                    "example": "Sophia"
                  },
                  "expected_last_name": {
                    "type": "string",
                    "description": "Last name to verify against `name_on_document`, combined with `expected_first_name` for the match score.",
                    "example": "Martinez"
                  },
                  "poa_languages_allowed": {
                    "type": "string",
                    "description": "Comma-separated list of accepted document languages as ISO 639-1 codes (e.g. `en,es,fr`). When omitted or blank, **all 51 supported languages** are accepted. A document in a language outside the list adds `UNSUPPORTED_DOCUMENT_LANGUAGE` (governed by `poa_unsupported_language_action`); an unknown code in the list returns `400` with the full set of supported codes.",
                    "example": "en,es"
                  },
                  "poa_document_age_months": {
                    "type": "string",
                    "description": "Comma-separated `key:value` pairs setting the maximum document age in months per document type — keys: `utility_bill`, `bank_statement`, `government_issued_document`, `other_poa_document`; values: `1`–`120`, or `-1` for unlimited (no age check). Defaults when omitted: `utility_bill:3,bank_statement:3,government_issued_document:12,other_poa_document:12`. A document older than its limit declines with `POA_DOCUMENT_EXPIRED`. **Caution:** when you provide this field, list *every* type you accept — omitted types are treated as not accepted (informational `POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION`) and their age check is skipped.",
                    "example": "utility_bill:3,bank_statement:6"
                  },
                  "poa_name_mismatch_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "Accepted but **currently not applied** — name-mismatch warnings (`NAME_MISMATCH_WITH_PROVIDED`) follow `poa_address_mismatch_action` instead. Set `poa_address_mismatch_action` to control both name and address mismatch behavior."
                  },
                  "poa_document_issues_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What to do on file-integrity problems — in practice only `DOCUMENT_METADATA_MISMATCH` is produced by this endpoint."
                  },
                  "poa_document_authenticity_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when document manipulation is suspected (`SUSPECTED_DOCUMENT_MANIPULATION`) — e.g. the PDF was modified after digital signing, processed by a known PDF editor, shows overlay-text manipulation, or has inconsistent EXIF dates."
                  },
                  "poa_unsupported_language_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when the document language is outside `poa_languages_allowed` (`UNSUPPORTED_DOCUMENT_LANGUAGE`)."
                  },
                  "poa_address_mismatch_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when the extracted details disagree with the `expected_*` fields: `ADDRESS_MISMATCH_WITH_PROVIDED`, `NAME_MISMATCH_WITH_PROVIDED`, and `POA_COUNTRY_MISMATCH_WITH_PROVIDED` all follow this action."
                  },
                  "poa_issuer_not_identified_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when no issuing company/organization can be identified on the document (`ISSUER_NOT_IDENTIFIED`)."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session — visible in the Business Console, retrievable via `GET /v3/session/{sessionId}/decision/` using the returned `request_id`, announced through a `status.updated` webhook, and with the uploaded document stored. When `false`, nothing is stored and `request_id` is a transient UUID for response correlation only.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. `metadata={\"flow\":\"onboarding\"}`) — it is parsed into an object.",
                    "example": {
                      "flow": "onboarding"
                    }
                  }
                }
              },
              "example": {
                "document": "(binary JPEG/PNG/PDF of the utility bill or bank statement)",
                "expected_address": "Av. Monseñor Tavella 1291, Salta, Argentina",
                "expected_country": "ARG",
                "expected_first_name": "Sophia",
                "expected_last_name": "Martinez",
                "poa_languages_allowed": "en,es",
                "save_api_request": true,
                "vendor_data": "user-123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document processed. `poa.status` is `Approved` or `Declined`; every detected issue is itemized in `poa.warnings`. An expired, mismatched, or suspicious document still returns `200` with `status: \"Declined\"` — inspect the body, not just the HTTP code. When `save_api_request=true`, `request_id` is the persisted session id.",
            "content": {
              "application/json": {
                "examples": {
                  "Approved": {
                    "summary": "Utility bill read cleanly, no expected-details checks",
                    "value": {
                      "request_id": "4b523a8d-ed32-45e4-8aa8-a89eda459d88",
                      "poa": {
                        "issuing_state": "ARG",
                        "document_type": "UTILITY_BILL",
                        "document_subtype": "WATER_BILL",
                        "document_language": "es",
                        "issuer": "Aguas del Norte",
                        "issue_date": "2026-04-10",
                        "expiration_date": null,
                        "poa_address": "AVDA. MONSEÑOR TAVELLA N° 1291, B° VILLA LAVALLE CP: 4400, CAPITAL - SALTA",
                        "poa_formatted_address": "Av. Monseñor Tavella 1291 b, A4400 Salta, Argentina",
                        "poa_parsed_address": {
                          "street_1": "Avenida Monseñor Tavella 1291",
                          "street_2": "b",
                          "city": "Salta",
                          "region": "Salta",
                          "country": "AR",
                          "postal_code": "A4400",
                          "document_location": {
                            "latitude": -24.8208682,
                            "longitude": -65.4130954
                          }
                        },
                        "expected_details_address": null,
                        "expected_details_formatted_address": null,
                        "expected_details_parsed_address": null,
                        "name_on_document": "OESTE EMBOTELLADORA S.A.",
                        "extra_fields": {
                          "bank_account_number": null,
                          "bank_iban": null,
                          "bank_sort_code": null,
                          "bank_routing_number": null,
                          "bank_swift_bic": null,
                          "bank_branch_name": null,
                          "bank_branch_address": null,
                          "document_phone_number": null,
                          "additional_names": [
                            "LA EMBOTELLADORA DEL NORTE SA"
                          ]
                        },
                        "detected_codes": [
                          {
                            "type": "QR_CODE",
                            "page_number": 1,
                            "position": [
                              [
                                820,
                                1120
                              ],
                              [
                                1002,
                                1120
                              ],
                              [
                                1002,
                                1302
                              ],
                              [
                                820,
                                1302
                              ]
                            ],
                            "x": 820,
                            "y": 1120,
                            "width": 182,
                            "height": 182,
                            "page_width": 1190,
                            "page_height": 1684,
                            "raw_payload": "aHR0cHM6Ly9hZ3Vhc2RlbG5vcnRlLmNvbS9mYWN0dXJhLzk5ODgxMQ==",
                            "parsed_payload": "https://aguasdelnorte.com/factura/998811"
                          },
                          {
                            "type": "CODE_128",
                            "page_number": 1,
                            "position": [
                              [
                                112,
                                1480
                              ],
                              [
                                560,
                                1480
                              ],
                              [
                                560,
                                1540
                              ],
                              [
                                112,
                                1540
                              ]
                            ],
                            "x": 112,
                            "y": 1480,
                            "width": 448,
                            "height": 60,
                            "page_width": 1190,
                            "page_height": 1684,
                            "raw_payload": "MDA5OTg4MTEwMDA0Mg==",
                            "parsed_payload": "0099881100042"
                          }
                        ],
                        "status": "Approved",
                        "warnings": []
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T02:29:02.439655+00:00"
                    }
                  },
                  "Declined - document too old": {
                    "summary": "Issue date older than the allowed `poa_document_age_months`",
                    "value": {
                      "request_id": "f61681b8-9422-4378-ac3e-04c6a247fb45",
                      "poa": {
                        "issuing_state": "ARG",
                        "document_type": "UTILITY_BILL",
                        "document_subtype": "WATER_BILL",
                        "document_language": "es",
                        "issuer": "Aguas del Norte",
                        "issue_date": "2021-02-10",
                        "expiration_date": null,
                        "poa_address": "AVDA. MONSEÑOR TAVELLA N° 1291, B° VILLA LAVALLE CP: 4400, CAPITAL - SALTA",
                        "poa_formatted_address": "Av. Monseñor Tavella 1291 b, A4400 Salta, Argentina",
                        "poa_parsed_address": {
                          "street_1": "Avenida Monseñor Tavella 1291",
                          "street_2": "b",
                          "city": "Salta",
                          "region": "Salta",
                          "country": "AR",
                          "postal_code": "A4400",
                          "document_location": {
                            "latitude": -24.8208682,
                            "longitude": -65.4130954
                          }
                        },
                        "expected_details_address": null,
                        "expected_details_formatted_address": null,
                        "expected_details_parsed_address": null,
                        "name_on_document": "OESTE EMBOTELLADORA S.A.",
                        "extra_fields": {
                          "bank_account_number": null,
                          "bank_iban": null,
                          "bank_sort_code": null,
                          "bank_routing_number": null,
                          "bank_swift_bic": null,
                          "bank_branch_name": null,
                          "bank_branch_address": null,
                          "document_phone_number": null,
                          "additional_names": [
                            "LA EMBOTELLADORA DEL NORTE SA"
                          ]
                        },
                        "status": "Declined",
                        "warnings": [
                          {
                            "risk": "POA_DOCUMENT_EXPIRED",
                            "feature": "PROOF_OF_ADDRESS",
                            "additional_data": {
                              "expiration_reason": "age_window",
                              "max_age_months": 3,
                              "document_subtype": "WATER_BILL",
                              "document_type": "UTILITY_BILL",
                              "issue_date": "2021-02-10"
                            },
                            "log_type": "error",
                            "short_description": "Document expired",
                            "long_description": "The submitted document is older than the maximum accepted age of 3 months from its issue date, which exceeds the acceptable time period for validity."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T02:23:02.165493+00:00"
                    }
                  },
                  "Declined - name mismatch": {
                    "summary": "`expected_first_name`/`expected_last_name` do not match `name_on_document`",
                    "value": {
                      "request_id": "0a7f2f9c-58f1-4b8e-b1e3-2f6f9d4f7a21",
                      "poa": {
                        "issuing_state": "ARG",
                        "document_type": "UTILITY_BILL",
                        "document_subtype": "WATER_BILL",
                        "document_language": "es",
                        "issuer": "Aguas del Norte",
                        "issue_date": "2021-02-10",
                        "expiration_date": null,
                        "poa_address": "AVDA. MONSEÑOR TAVELLA N° 1291, B° VILLA LAVALLE CP: 4400, CAPITAL - SALTA",
                        "poa_formatted_address": "Av. Monseñor Tavella 1291 b, A4400 Salta, Argentina",
                        "poa_parsed_address": {
                          "street_1": "Avenida Monseñor Tavella 1291",
                          "street_2": "b",
                          "city": "Salta",
                          "region": "Salta",
                          "country": "AR",
                          "postal_code": "A4400",
                          "document_location": {
                            "latitude": -24.8208682,
                            "longitude": -65.4130954
                          }
                        },
                        "expected_details_address": null,
                        "expected_details_formatted_address": null,
                        "expected_details_parsed_address": null,
                        "name_on_document": "OESTE EMBOTELLADORA S.A.",
                        "extra_fields": {
                          "bank_account_number": null,
                          "bank_iban": null,
                          "bank_sort_code": null,
                          "bank_routing_number": null,
                          "bank_swift_bic": null,
                          "bank_branch_name": null,
                          "bank_branch_address": null,
                          "document_phone_number": null,
                          "additional_names": [
                            "LA EMBOTELLADORA DEL NORTE SA"
                          ]
                        },
                        "status": "Declined",
                        "warnings": [
                          {
                            "risk": "NAME_MISMATCH_WITH_PROVIDED",
                            "feature": "PROOF_OF_ADDRESS",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Name mismatch with provided information",
                            "long_description": "The full name on the document does not match the name from the user's verified identity documents, or the full name sent by API."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T02:27:21.330172+00:00"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "poa": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined"
                          ],
                          "description": "`Approved` when no warning resolves to a decline; `Declined` otherwise — the `warnings` list explains why."
                        },
                        "issuing_state": {
                          "type": "string",
                          "nullable": true,
                          "description": "Country the document was issued in, as extracted from the document — usually ISO 3166-1 alpha-3 (e.g. `ARG`).",
                          "example": "ARG"
                        },
                        "document_type": {
                          "type": "string",
                          "enum": [
                            "UTILITY_BILL",
                            "BANK_STATEMENT",
                            "GOVERNMENT_ISSUED_DOCUMENT",
                            "OTHER_POA_DOCUMENT",
                            "UNKNOWN"
                          ],
                          "description": "Detected document category. `UNKNOWN` means the document could not be classified as an acceptable Proof of Address and auto-declines with `INVALID_DOCUMENT_TYPE`. Never null — classification failures fall back to `UNKNOWN`."
                        },
                        "document_subtype": {
                          "type": "string",
                          "description": "Finer-grained classification within `document_type` — e.g. `ELECTRICITY_BILL`, `WATER_BILL`, `GAS_BILL`, `INTERNET_BILL`, `PHONE_BILL` (utility bills); `ACCOUNT_STATEMENT`, `CREDIT_CARD_STATEMENT` (bank statements); `TAX_ASSESSMENT`, `RESIDENCY_CERTIFICATE` (government documents). `UNKNOWN` when no subtype could be determined. Never null — classification failures fall back to `UNKNOWN`.",
                          "example": "WATER_BILL"
                        },
                        "document_language": {
                          "type": "string",
                          "nullable": true,
                          "description": "Detected document language (ISO 639-1).",
                          "example": "es"
                        },
                        "issuer": {
                          "type": "string",
                          "nullable": true,
                          "description": "Company or organization that issued the document. `null` adds `ISSUER_NOT_IDENTIFIED`.",
                          "example": "Aguas del Norte"
                        },
                        "issue_date": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "description": "Document issue date (`YYYY-MM-DD`). `null` when it could not be extracted — that declines with `UNABLE_TO_EXTRACT_ISSUE_DATE` on this endpoint.",
                          "example": "2021-02-10"
                        },
                        "expiration_date": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "description": "Explicit expiry/validity date printed on the document, when present. Independent of the `poa_document_age_months` age check."
                        },
                        "poa_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Address exactly as printed on the document. `null` auto-declines with `MISSING_ADDRESS_INFORMATION`."
                        },
                        "poa_formatted_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Geocoded, normalized version of `poa_address`.",
                          "example": "Av. Monseñor Tavella 1291 b, A4400 Salta, Argentina"
                        },
                        "poa_parsed_address": {
                          "type": "object",
                          "nullable": true,
                          "description": "Structured, geocoded breakdown of the document address. `null` when the address could not be parsed.",
                          "properties": {
                            "street_1": {
                              "type": "string",
                              "nullable": true,
                              "example": "Avenida Monseñor Tavella 1291"
                            },
                            "street_2": {
                              "type": "string",
                              "nullable": true
                            },
                            "city": {
                              "type": "string",
                              "nullable": true,
                              "example": "Salta"
                            },
                            "region": {
                              "type": "string",
                              "nullable": true,
                              "example": "Salta"
                            },
                            "country": {
                              "type": "string",
                              "nullable": true,
                              "description": "ISO 3166-1 alpha-2 country code.",
                              "example": "AR"
                            },
                            "postal_code": {
                              "type": "string",
                              "nullable": true,
                              "example": "A4400"
                            },
                            "document_location": {
                              "type": "object",
                              "nullable": true,
                              "properties": {
                                "latitude": {
                                  "type": "number"
                                },
                                "longitude": {
                                  "type": "number"
                                }
                              },
                              "description": "Geocoded coordinates of the document address."
                            }
                          }
                        },
                        "expected_details_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Echo of the `expected_address` you sent, or `null`."
                        },
                        "expected_details_formatted_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Geocoded, normalized version of `expected_address`; `null` when not provided or not geocodable."
                        },
                        "expected_details_parsed_address": {
                          "type": "object",
                          "nullable": true,
                          "additionalProperties": true,
                          "description": "Full geocoding result for `expected_address` (street/city/region/country/postal code plus raw geocoder output and an `is_verified` flag). `null` when `expected_address` was not provided."
                        },
                        "name_on_document": {
                          "type": "string",
                          "nullable": true,
                          "description": "Primary holder name extracted from the document; compared against `expected_first_name`/`expected_last_name` when provided. `null` declines with `POA_NAME_NOT_DETECTED` on this endpoint.",
                          "example": "OESTE EMBOTELLADORA S.A."
                        },
                        "extra_fields": {
                          "type": "object",
                          "description": "Document-specific extras. Bank fields are populated for bank statements when printed on the document; `null` otherwise.",
                          "properties": {
                            "bank_account_number": {
                              "type": "string",
                              "nullable": true
                            },
                            "bank_iban": {
                              "type": "string",
                              "nullable": true
                            },
                            "bank_sort_code": {
                              "type": "string",
                              "nullable": true
                            },
                            "bank_routing_number": {
                              "type": "string",
                              "nullable": true
                            },
                            "bank_swift_bic": {
                              "type": "string",
                              "nullable": true
                            },
                            "bank_branch_name": {
                              "type": "string",
                              "nullable": true
                            },
                            "bank_branch_address": {
                              "type": "string",
                              "nullable": true
                            },
                            "document_phone_number": {
                              "type": "string",
                              "nullable": true,
                              "description": "Contact phone number printed on the document."
                            },
                            "additional_names": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "Other holder names found on the document (e.g. co-account holders, previous account names)."
                            }
                          }
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Empty on a clean approval. Every entry explains one detected risk; entries with `log_type: \"error\"` set `status` to `Declined`.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "description": "Machine-readable risk code. Always-decline: `MISSING_ADDRESS_INFORMATION`, `POA_DOCUMENT_EXPIRED`, `INVALID_DOCUMENT_TYPE`, `UNABLE_TO_VALIDATE_DOCUMENT_AGE`, plus `UNABLE_TO_EXTRACT_ISSUE_DATE` and `POA_NAME_NOT_DETECTED` (fixed to decline on this endpoint). Governed by request options: `NAME_MISMATCH_WITH_PROVIDED` / `ADDRESS_MISMATCH_WITH_PROVIDED` / `POA_COUNTRY_MISMATCH_WITH_PROVIDED` (`poa_address_mismatch_action`), `POOR_DOCUMENT_QUALITY` (never produced by this endpoint) / `DOCUMENT_METADATA_MISMATCH` (`poa_document_issues_action`), `SUSPECTED_DOCUMENT_MANIPULATION` (`poa_document_authenticity_action`), `UNSUPPORTED_DOCUMENT_LANGUAGE` (`poa_unsupported_language_action`), `ISSUER_NOT_IDENTIFIED` (`poa_issuer_not_identified_action`). Informational on this endpoint: `POA_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION`, `UNPARSABLE_OR_INVALID_ADDRESS`.",
                                "example": "POA_DOCUMENT_EXPIRED"
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "PROOF_OF_ADDRESS"
                                ],
                                "description": "Feature that raised the warning. Always `PROOF_OF_ADDRESS` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Extra context for some risks — e.g. `POA_DOCUMENT_EXPIRED` includes `expiration_reason` (`printed_expiration` or `age_window`), `document_type`, `document_subtype`, and `issue_date`, plus `expiration_date` on the `printed_expiration` path or `max_age_months` on the `age_window` path; `SUSPECTED_DOCUMENT_MANIPULATION` includes `reason` and `detection_method`. `null` for most risks."
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error",
                                  "information"
                                ],
                                "description": "Severity. `error` warnings drive `status` to `Declined`; `information` entries are advisory and never decline on their own. (`warning` is not produced by this endpoint — its options only accept `DECLINE` or `NO_ACTION`.)"
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-line summary of the risk."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation of the risk."
                              }
                            }
                          }
                        },
                        "detected_codes": {
                          "type": "array",
                          "description": "QR codes and barcodes detected across every processed page of the document. Empty when none are found. A located but undecodable QR code has `parsed_payload: null`.",
                          "items": {
                            "$ref": "#/components/schemas/DocumentAIDetectedCode"
                          }
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp (UTC) of when the response was generated."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or processing error. Field-level problems return DRF's standard envelope (one array of messages per offending field). Encrypted-PDF problems return `{\"detail\": ...}`. A document the extraction pipeline cannot process returns `{\"error\": [\"Error extracting POA information\"]}`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing document": {
                    "summary": "`document` not included in the form data",
                    "value": {
                      "document": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Unsupported file extension": {
                    "summary": "File extension outside tiff/jpg/jpeg/png/pdf/webp",
                    "value": {
                      "document": [
                        "File extension “txt” is not allowed. Allowed extensions are: tiff, jpg, jpeg, png, pdf, webp."
                      ]
                    }
                  },
                  "File too large": {
                    "summary": "Upload exceeds the 15 MB limit",
                    "value": {
                      "document": [
                        "File size should not exceed 15 MB"
                      ]
                    }
                  },
                  "Encrypted PDF": {
                    "summary": "PDF uploaded without the required password",
                    "value": {
                      "detail": "The PDF is encrypted. Please upload a decrypted PDF or a photo instead."
                    }
                  },
                  "Wrong PDF password": {
                    "summary": "`document_password` does not decrypt the PDF",
                    "value": {
                      "detail": "The PDF password is incorrect. Please provide the correct password."
                    }
                  },
                  "Invalid language code": {
                    "summary": "`poa_languages_allowed` contains an unsupported code",
                    "value": {
                      "poa_languages_allowed": [
                        "Invalid language code: 'xx'. Must be one of the supported languages: ['ar', 'bn', 'hy', 'bg', 'bs', 'ca', 'cnr', 'sq', 'zh', 'hr', 'cs', 'da', 'nl', 'en', 'et', 'fi', 'fr', 'ka', 'kk', 'de', 'el', 'he', 'hi', 'hu', 'id', 'it', 'ja', 'ko', 'ky', 'lv', 'lt', 'mk', 'mn', 'ms', 'no', 'fa', 'pl', 'pt', 'ro', 'ru', 'sr', 'sk', 'sl', 'so', 'es', 'sv', 'th', 'tr', 'uk', 'uz', 'vi']."
                      ]
                    }
                  },
                  "Invalid document age value": {
                    "summary": "`poa_document_age_months` value outside 1–120 / -1",
                    "value": {
                      "poa_document_age_months": [
                        "Invalid integer value for 'utility_bill': '999'. Must be -1 (unlimited) or a positive integer between 1 and 120."
                      ]
                    }
                  },
                  "Extraction failure": {
                    "summary": "The document could not be processed by the extraction pipeline",
                    "value": {
                      "error": [
                        "Error extracting POA information"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any document processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/poa/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'document=@./utility-bill.pdf' \\\n  -F 'expected_address=Av. Monseñor Tavella 1291, Salta, Argentina' \\\n  -F 'expected_country=ARG' \\\n  -F 'expected_first_name=Sophia' \\\n  -F 'expected_last_name=Martinez' \\\n  -F 'poa_languages_allowed=en,es' \\\n  -F 'vendor_data=user-123' \\\n  --max-time 45"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = 'https://verification.didit.me/v3/poa/'\nheaders = {'x-api-key': 'YOUR_API_KEY'}\n\nwith open('utility-bill.pdf', 'rb') as f:\n    files = {'document': ('utility-bill.pdf', f, 'application/pdf')}\n    data = {\n        'expected_address': 'Av. Monseñor Tavella 1291, Salta, Argentina',\n        'expected_country': 'ARG',\n        'expected_first_name': 'Sophia',\n        'expected_last_name': 'Martinez',\n        'poa_languages_allowed': 'en,es',\n        'vendor_data': 'user-123',\n    }\n    # LLM-based extraction takes 5-15s (multi-page PDFs up to ~30s) - allow headroom\n    resp = requests.post(url, headers=headers, files=files, data=data, timeout=45)\n\nresp.raise_for_status()\npoa = resp.json()['poa']\nprint('status:', poa['status'])\nprint('issuer:', poa['issuer'], '| issued:', poa['issue_date'])\nprint('address:', poa['poa_formatted_address'])\nfor w in poa['warnings']:\n    print('warning:', w['risk'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import fs from 'node:fs';\n\nconst form = new FormData();\nform.append('document', new Blob([fs.readFileSync('./utility-bill.pdf')]), 'utility-bill.pdf');\nform.append('expected_address', 'Av. Monseñor Tavella 1291, Salta, Argentina');\nform.append('expected_country', 'ARG');\nform.append('expected_first_name', 'Sophia');\nform.append('expected_last_name', 'Martinez');\nform.append('poa_languages_allowed', 'en,es');\nform.append('vendor_data', 'user-123');\n\n// LLM-based extraction takes 5-15s (multi-page PDFs up to ~30s) - allow >=45s\nconst response = await fetch('https://verification.didit.me/v3/poa/', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n  body: form,\n  signal: AbortSignal.timeout(45_000),\n});\n\nif (!response.ok) throw new Error(`POA verification failed: ${response.status}`);\nconst { poa } = await response.json();\nconsole.log('status:', poa.status);\nconsole.log('warnings:', poa.warnings.map((w) => w.risk));"
          }
        ]
      }
    },
    "/v3/document-ai/": {
      "post": {
        "summary": "Document AI (custom field extraction + tamper checks)",
        "description": "Extract the fields **you** define from any supporting document — payslips, proof of funds, source-of-wealth letters, tax statements, contracts, invoices — in one call. Send the file plus a `fields` definition (key, name, extraction instruction, type) and get back typed values (`text`, `number`, `date` as `YYYY-MM-DD`), an optional name-match score against the expected person or company, PDF/EXIF tamper signals, an `Approved`/`Declined`/`In Review` `status`, and a `warnings` list explaining every issue found. This is the server-to-server counterpart of the hosted Document AI workflow step (see `/core-technology/document-ai/overview`); it uses Didit's default extraction model and does not expose provider selection.\n\n**Latency.** Extraction is LLM-based: typical calls take **5–15 seconds**, multi-page PDFs up to **~30 seconds**. Configure a client timeout of **at least 45 seconds** and do not retry before the call completes.\n\n**Request format.** `multipart/form-data` only. `fields` is **one JSON-encoded array string** (1–30 items, at most 16 KB); bracket-style form arrays are rejected with `400`. Each item is `{key, name, instruction, type, required, is_full_name}` — `key` is the JSON key you get back (`^[a-z0-9_]{1,64}$`, unique), `instruction` tells the model what to read, `type` is `text` (default) | `number` | `date`, `required` raises `DOCUMENT_AI_MISSING_REQUIRED_FIELDS` when the value cannot be read, and at most one field may set `is_full_name: true` to mark the value compared against the expected name.\n\n**Name matching.** Pass `expected_first_name` + `expected_last_name` (person) **or** `expected_company_name` (+ optional `expected_company_country`) — not both. The value of the `is_full_name` field (or, when none is marked, the first text field whose key looks like a name) is compared fuzzily; `name_match_score` (0–100) and `name_on_document` are always returned when both sides exist, and a score below `document_ai_name_match_score_threshold` (default 80) adds `DOCUMENT_AI_NAME_MISMATCH`, governed by `document_ai_name_mismatch_action`.\n\n**Decision logic.** Each risk maps to a configurable action: `DECLINE` → `status: \"Declined\"`, `REVIEW` → `status: \"In Review\"`, `NO_ACTION` → informational only. Defaults mirror the workflow step: unreadable document `REVIEW`, missing required fields `REVIEW`, suspected manipulation `DECLINE`, name mismatch `NO_ACTION`, unsupported file `REVIEW`. A document that cannot be processed at all returns `400`; a readable but problematic document returns `200` with `Declined`/`In Review` — always inspect `document_ai.status` and `document_ai.warnings`, not just the HTTP code.\n\n**Billing.** Each `200` response consumes one Document AI API credit — **$0.20 per document, no free tier** (standalone APIs never have one). When the organization's balance cannot cover the call, the endpoint returns `403` before any processing. Sandbox API keys return a deterministic mock response and are not charged.\n\n**Persistence.** With `save_api_request=true` (default) the call is stored as an API-type session: the document, the extracted values, the field definitions and the name-match snapshot are kept, the session shows up in the Business Console, and `request_id` works with `GET /v3/session/{sessionId}/decision/`.",
        "operationId": "post_v3document-ai",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "document",
                  "fields"
                ],
                "properties": {
                  "document": {
                    "type": "string",
                    "format": "binary",
                    "description": "The document to read. Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `pdf`, `webp`, `zip`. Maximum upload size: **30 MB** (larger files are rejected with `400`). Multi-page PDFs are supported (expect higher latency); encrypted PDFs are rejected with `400`. Images are automatically compressed before processing."
                  },
                  "fields": {
                    "type": "string",
                    "description": "One JSON-encoded array string with **1–30** field definitions (maximum 16 KB). Each item: `key` (required, `^[a-z0-9_]{1,64}$`, unique — the key returned in `extracted_data`), `name` (≤100 chars, shown in messages), `instruction` (≤500 chars, what the model should read), `type` (`text` default | `number` | `date`), `required` (boolean, default `false`), `is_full_name` (boolean, default `false`, at most one per request). Bracket-style form arrays, invalid JSON, duplicate keys, or more than one `is_full_name` return `400` before any processing or billing.",
                    "example": "[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]"
                  },
                  "expected_first_name": {
                    "type": "string",
                    "description": "First name to verify against the document's name field (fuzzy match, transliteration-aware). Use together with `expected_last_name`; cannot be combined with `expected_company_name`.",
                    "example": "Sophia"
                  },
                  "expected_last_name": {
                    "type": "string",
                    "description": "Last name to verify against the document's name field, combined with `expected_first_name` for `name_match_score`.",
                    "example": "Martinez"
                  },
                  "expected_company_name": {
                    "type": "string",
                    "description": "Company name to verify against the document's name field (for business documents). Cannot be combined with `expected_first_name` / `expected_last_name` (no example value on purpose — the generated request sample uses the person fields; swap them for this one when verifying a business document)."
                  },
                  "expected_company_country": {
                    "type": "string",
                    "description": "Optional ISO 3166-1 alpha-2 country code (two ASCII letters, e.g. `FR`) that tunes company-name normalization for `expected_company_name`. Only used with `expected_company_name`."
                  },
                  "document_ai_name_match_score_threshold": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 80,
                    "description": "Minimum `name_match_score` (0–100) to consider the name matched. A lower score adds `DOCUMENT_AI_NAME_MISMATCH`, governed by `document_ai_name_mismatch_action`.",
                    "example": 80
                  },
                  "document_ai_unreadable_document_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "REVIEW",
                      "NO_ACTION"
                    ],
                    "default": "REVIEW",
                    "description": "What to do when no field could be read from the document (`DOCUMENT_AI_UNREADABLE_DOCUMENT`)."
                  },
                  "document_ai_missing_required_fields_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "REVIEW",
                      "NO_ACTION"
                    ],
                    "default": "REVIEW",
                    "description": "What to do when at least one `required` field could not be read (`DOCUMENT_AI_MISSING_REQUIRED_FIELDS`; `additional_data.missing_fields` lists them)."
                  },
                  "document_ai_document_tampering_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "REVIEW",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What to do when PDF/EXIF forensics suspect manipulation — modified after digital signing, known PDF editor, overlay-text manipulation, suspicious re-export, image anomalies (`DOCUMENT_AI_SUSPECTED_MANIPULATION`)."
                  },
                  "document_ai_name_mismatch_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "REVIEW",
                      "NO_ACTION"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when `name_match_score` is below the threshold (`DOCUMENT_AI_NAME_MISMATCH`)."
                  },
                  "document_ai_unsupported_file_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "REVIEW",
                      "NO_ACTION"
                    ],
                    "default": "REVIEW",
                    "description": "What to do when the upload is empty or not a processable file (`DOCUMENT_AI_UNSUPPORTED_FILE`)."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session — visible in the Business Console, retrievable via `GET /v3/session/{sessionId}/decision/` using the returned `request_id`, with the uploaded document, the extracted values, the field definitions and the name-match snapshot stored. When `false`, nothing is stored and `request_id` is a transient UUID for response correlation only; the call is still billed.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. `metadata={\"flow\":\"onboarding\"}`) — it is parsed into an object.",
                    "example": {
                      "flow": "onboarding"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document processed. `document_ai.status` is `Approved`, `Declined`, or `In Review`; every detected issue is itemized in `document_ai.warnings`. A problematic document still returns `200` — inspect the body, not just the HTTP code. When `save_api_request=true`, `request_id` is the persisted session id.",
            "content": {
              "application/json": {
                "examples": {
                  "Approved": {
                    "summary": "Payslip read cleanly, name matched",
                    "value": {
                      "request_id": "9d6a3b1e-2f0c-4a8e-9b7d-1c2e3f4a5b6c",
                      "document_ai": {
                        "status": "Approved",
                        "extracted_data": {
                          "employer_name": "Acme Payments Ltd",
                          "employee_name": "Sophia Martinez",
                          "net_pay": 3120.5,
                          "pay_date": "2026-07-31"
                        },
                        "detected_codes": [
                          {
                            "type": "CODE_128",
                            "page_number": 1,
                            "position": [
                              [
                                96,
                                456
                              ],
                              [
                                96,
                                616
                              ],
                              [
                                1012,
                                611
                              ],
                              [
                                1015,
                                456
                              ]
                            ],
                            "x": 96,
                            "y": 456,
                            "width": 919,
                            "height": 160,
                            "page_width": 1200,
                            "page_height": 1700,
                            "raw_payload": "SU5WLTIwMjYtMDA0Mg==",
                            "parsed_payload": "INV-2026-0042"
                          }
                        ],
                        "fields": [
                          {
                            "key": "employer_name",
                            "name": "Employer name",
                            "instruction": "The employer or company issuing the payslip.",
                            "type": "text",
                            "required": true,
                            "is_full_name": false
                          },
                          {
                            "key": "employee_name",
                            "name": "Employee name",
                            "instruction": "The full name of the employee as printed on the payslip.",
                            "type": "text",
                            "required": true,
                            "is_full_name": true
                          },
                          {
                            "key": "net_pay",
                            "name": "Net pay",
                            "instruction": "The net amount paid to the employee for the period.",
                            "type": "number",
                            "required": true,
                            "is_full_name": false
                          },
                          {
                            "key": "pay_date",
                            "name": "Pay date",
                            "instruction": "The payment date shown on the payslip.",
                            "type": "date",
                            "required": false,
                            "is_full_name": false
                          }
                        ],
                        "name_match_score": 100.0,
                        "name_on_document": "Sophia Martinez",
                        "warnings": []
                      },
                      "vendor_data": "user-123",
                      "metadata": {
                        "flow": "onboarding"
                      },
                      "created_at": "2026-08-19T16:40:12.318Z"
                    }
                  },
                  "In Review — missing required field": {
                    "summary": "`net_pay` could not be read; default action REVIEW",
                    "value": {
                      "request_id": "3f2a9c7b-5d4e-4b1a-8c6f-0e9d8c7b6a5f",
                      "document_ai": {
                        "status": "In Review",
                        "extracted_data": {
                          "employer_name": "Acme Payments Ltd",
                          "employee_name": "Sophia Martinez",
                          "net_pay": null,
                          "pay_date": "2026-07-31"
                        },
                        "detected_codes": [],
                        "fields": [
                          {
                            "key": "employer_name",
                            "name": "Employer name",
                            "instruction": "The employer or company issuing the payslip.",
                            "type": "text",
                            "required": true,
                            "is_full_name": false
                          },
                          {
                            "key": "employee_name",
                            "name": "Employee name",
                            "instruction": "The full name of the employee as printed on the payslip.",
                            "type": "text",
                            "required": true,
                            "is_full_name": true
                          },
                          {
                            "key": "net_pay",
                            "name": "Net pay",
                            "instruction": "The net amount paid to the employee for the period.",
                            "type": "number",
                            "required": true,
                            "is_full_name": false
                          },
                          {
                            "key": "pay_date",
                            "name": "Pay date",
                            "instruction": "The payment date shown on the payslip.",
                            "type": "date",
                            "required": false,
                            "is_full_name": false
                          }
                        ],
                        "name_match_score": 100.0,
                        "name_on_document": "Sophia Martinez",
                        "warnings": [
                          {
                            "risk": "DOCUMENT_AI_MISSING_REQUIRED_FIELDS",
                            "feature": "DOCUMENT_AI",
                            "additional_data": {
                              "missing_fields": [
                                "Net pay"
                              ]
                            },
                            "log_type": "warning",
                            "short_description": "Required fields could not be extracted",
                            "long_description": "One or more fields configured as required could not be extracted from the uploaded document."
                          }
                        ]
                      },
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-08-19T16:41:05.002Z"
                    }
                  },
                  "Declined — suspected manipulation": {
                    "summary": "PDF forensics flagged a known editor; default action DECLINE",
                    "value": {
                      "request_id": "7c1d2e3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
                      "document_ai": {
                        "status": "Declined",
                        "extracted_data": {
                          "employer_name": "Acme Payments Ltd",
                          "employee_name": "Sophia Martinez",
                          "net_pay": 3120.5,
                          "pay_date": "2026-07-31"
                        },
                        "detected_codes": [],
                        "fields": [
                          {
                            "key": "employer_name",
                            "name": "Employer name",
                            "instruction": "The employer or company issuing the payslip.",
                            "type": "text",
                            "required": true,
                            "is_full_name": false
                          },
                          {
                            "key": "employee_name",
                            "name": "Employee name",
                            "instruction": "The full name of the employee as printed on the payslip.",
                            "type": "text",
                            "required": true,
                            "is_full_name": true
                          },
                          {
                            "key": "net_pay",
                            "name": "Net pay",
                            "instruction": "The net amount paid to the employee for the period.",
                            "type": "number",
                            "required": true,
                            "is_full_name": false
                          },
                          {
                            "key": "pay_date",
                            "name": "Pay date",
                            "instruction": "The payment date shown on the payslip.",
                            "type": "date",
                            "required": false,
                            "is_full_name": false
                          }
                        ],
                        "name_match_score": null,
                        "name_on_document": "Sophia Martinez",
                        "warnings": [
                          {
                            "risk": "DOCUMENT_AI_SUSPECTED_MANIPULATION",
                            "feature": "DOCUMENT_AI",
                            "additional_data": {
                              "detection_method": "known_editor",
                              "processed_by_known_editor": "ilovepdf"
                            },
                            "log_type": "error",
                            "short_description": "Suspected document manipulation",
                            "long_description": "The system detected signs of potential manipulation or editing in the uploaded document."
                          }
                        ]
                      },
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-08-19T16:42:40.771Z"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "document_ai": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined",
                            "In Review"
                          ],
                          "description": "`Approved` when no warning resolves to a decline or review; `Declined` when at least one risk maps to `DECLINE`; otherwise `In Review` when at least one maps to `REVIEW`. The `warnings` list explains why."
                        },
                        "extracted_data": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "One entry per requested field key. Values are typed per the field `type` — strings for `text`, numbers for `number`, `YYYY-MM-DD` strings for `date` — or `null` when the value could not be read.",
                          "example": {
                            "employer_name": "Acme Payments Ltd",
                            "employee_name": "Sophia Martinez",
                            "net_pay": 3120.5,
                            "pay_date": "2026-07-31"
                          }
                        },
                        "detected_codes": {
                          "type": "array",
                          "description": "QR codes and barcodes detected across every processed page. Empty when none are found. A located but undecodable QR code has `parsed_payload: null`.",
                          "items": {
                            "$ref": "#/components/schemas/DocumentAIDetectedCode"
                          }
                        },
                        "fields": {
                          "type": "array",
                          "description": "The normalized field definitions that were used for this extraction, echoed back (also stored with the session when `save_api_request=true`).",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "instruction": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date"
                                ]
                              },
                              "required": {
                                "type": "boolean"
                              },
                              "is_full_name": {
                                "type": "boolean"
                              }
                            }
                          }
                        },
                        "name_match_score": {
                          "type": "number",
                          "nullable": true,
                          "minimum": 0,
                          "maximum": 100,
                          "description": "Fuzzy similarity (0–100) between `name_on_document` and the expected person/company name. Returned whenever both a name value and an expected name exist — on matches **and** mismatches; `null` otherwise.",
                          "example": 96.0
                        },
                        "name_on_document": {
                          "type": "string",
                          "nullable": true,
                          "description": "The name value taken from the document (the `is_full_name` field, or the first name-like text field) that was compared against the expected name. `null` when no name value was available.",
                          "example": "Sophia Martinez"
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Empty on a clean approval. Every entry explains one detected risk; entries with `log_type: \"error\"` set `status` to `Declined`, entries with `log_type: \"warning\"` set it to `In Review`.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "enum": [
                                  "DOCUMENT_AI_UNREADABLE_DOCUMENT",
                                  "DOCUMENT_AI_MISSING_REQUIRED_FIELDS",
                                  "DOCUMENT_AI_SUSPECTED_MANIPULATION",
                                  "DOCUMENT_AI_NAME_MISMATCH",
                                  "DOCUMENT_AI_UNSUPPORTED_FILE"
                                ],
                                "description": "Machine-readable risk code. Each one is governed by the matching `document_ai_*_action` request option.",
                                "example": "DOCUMENT_AI_MISSING_REQUIRED_FIELDS"
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "DOCUMENT_AI"
                                ],
                                "description": "Feature that raised the warning. Always `DOCUMENT_AI` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "Extra context for the risk: `{\"missing_fields\": [\"Net pay\"]}` for missing required fields, `{\"name_on_document\", \"score\", \"threshold\"}` for a name mismatch, and the forensic finding (`detection_method`, producer/editor details) for suspected manipulation. `null` when there is nothing to add.",
                                "example": {
                                  "missing_fields": [
                                    "Net pay"
                                  ]
                                }
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error",
                                  "warning",
                                  "information"
                                ],
                                "description": "Severity derived from the configured action: `error` (DECLINE), `warning` (REVIEW), `information` (NO_ACTION)."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-liner for the risk.",
                                "example": "Required fields could not be extracted"
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation, interpolated with `additional_data` where relevant."
                              }
                            }
                          }
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the request was processed (UTC, ISO 8601)."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation or processing error. Field-level problems return DRF's standard envelope (one array of messages per offending field). Encrypted or unreadable documents and extraction failures return `{\"error\": ...}`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing document": {
                    "summary": "`document` not included in the form data",
                    "value": {
                      "document": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Invalid fields payload": {
                    "summary": "`fields` is not one JSON-encoded array string",
                    "value": {
                      "fields": [
                        "fields must be a valid JSON array string."
                      ]
                    }
                  },
                  "Duplicate field keys": {
                    "summary": "Two items share the same `key`",
                    "value": {
                      "fields": [
                        "Every fields item must have a unique key."
                      ]
                    }
                  },
                  "Conflicting expectations": {
                    "summary": "Person and company expectations sent together",
                    "value": {
                      "non_field_errors": [
                        "Provide either person expected-name fields or expected_company_name, not both."
                      ]
                    }
                  },
                  "Invalid metadata": {
                    "summary": "`metadata` is not a JSON object (or contains a NUL character)",
                    "value": {
                      "metadata": [
                        "Metadata must be a JSON object."
                      ]
                    }
                  },
                  "Oversized vendor_data": {
                    "summary": "`vendor_data` over the 2,000-byte cap",
                    "value": {
                      "vendor_data": [
                        "vendor_data is too long (maximum 2000 bytes)."
                      ]
                    }
                  },
                  "Encrypted PDF": {
                    "summary": "Password-protected PDF",
                    "value": {
                      "error": "The PDF is encrypted. Please upload a decrypted PDF or a photo instead."
                    }
                  },
                  "Extraction failed": {
                    "summary": "The extraction pipeline could not process the document",
                    "value": {
                      "error": [
                        "Error extracting Document AI information"
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls — and contract-billed organizations whose rate card has no Document AI API entry — return `403` with `{\"error\": ...}` before any document processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  },
                  "Contract rate missing": {
                    "summary": "Contract-billed organization whose rate card has no Document AI API entry",
                    "value": {
                      "error": "Document AI API is not included in your contract rate card. Contact support@didit.me to enable it."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/aml/": {
      "post": {
        "summary": "AML screening (standalone)",
        "operationId": "post_v3aml",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional retry-safety key, up to 255 characters. Reusing the same key with the same request body returns the original response without running or billing a second screening. Reusing the key with a different body returns `409`.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "description": "Screen a person or company against PEP, sanctions, warning/watchlist, and adverse-media datasets in one call.\n\n**Two-score model.** Each hit carries a `match_score` (0–100, identity confidence) and a `risk_score` (0–100, entity risk). Hits whose `match_score` is below `aml_match_score_threshold` (default **93**) are tagged `review_status: \"False Positive\"` and ignored for risk purposes; the highest `risk_score` among the remaining hits becomes `aml.score`. The final `aml.status` follows your thresholds: `score` > `aml_score_review_threshold` (default **100**) → `Declined`; `score` > `aml_score_approve_threshold` (default **80**) → `In Review`; otherwise `Approved`. Whenever `score` is non-zero and ≥ the approve threshold a `POSSIBLE_MATCH_FOUND` warning is added (a score of exactly 0 never warns).\n\n**Match-score weights.** `aml_name_weight` + `aml_dob_weight` + `aml_country_weight` must sum to exactly 100 (defaults 60/25/15). Components missing from the request are re-normalized away; a matching `document_number` acts as a golden key that overrides `match_score` to 100.\n\n**Latency.** Plain screenings typically complete in a few seconds. With `include_adverse_media=true` the API waits for adverse-media enrichment (an initial ~5 s pause plus up to ~25 s of polling) — configure a client timeout of **at least 60 seconds**.\n\n**Persistence.** `save_api_request` defaults to **true**: the screening is stored as a session (`request_id` works with `GET /v3/session/{sessionId}/decision/`), it appears in the console, a `status.updated` webhook fires, and hit review statuses can be updated later. With `save_api_request=false` nothing is stored and `request_id` is a transient correlation id. `include_ongoing_monitoring=true` keeps re-screening the profile and requires `save_api_request=true` (enforced with a `400`).\n\n**Idempotency.** Send an `Idempotency-Key` header when retrying after a timeout or transient error. The key is scoped to your application and the exact request body. The first completed request stores its response; later identical retries return that same response and do not run or bill another AML screening. If the original request is still running, retry later with the same key. If the same key is reused with a different body, the API returns `409`.\n\n**Billing.** One AML API credit is charged after the first successful screening. Replayed idempotent responses are not charged again; an insufficient balance returns `403` before any new screening happens.\n\n**Sandbox.** Keys from sandbox applications skip screening and billing entirely and return a mocked result — `Approved` with zero hits unless you pass `sandbox_scenario`. `save_api_request` works the same as on live keys, so a saved sandbox screening is retrievable through `GET /v3/session/{sessionId}/decision/` and `GET /v3/session/{sessionId}/generate-pdf/`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "full_name"
                ],
                "properties": {
                  "full_name": {
                    "type": "string",
                    "minLength": 2,
                    "description": "Full name of the person or company to screen. Minimum **2 characters** - the screening provider's own floor. A shorter or blank name returns `400` on this field before any screening runs, so nothing is billed.",
                    "example": "Antonio Ejemplo Modelo"
                  },
                  "entity_type": {
                    "type": "string",
                    "enum": [
                      "person",
                      "company"
                    ],
                    "default": "person",
                    "description": "Type of entity to screen. Defaults to `person`."
                  },
                  "date_of_birth": {
                    "type": "string",
                    "format": "date",
                    "description": "Date of birth (persons) or incorporation date (companies), `YYYY-MM-DD`. Improves match precision via the DOB weight.",
                    "example": "1972-02-29"
                  },
                  "nationality": {
                    "type": "string",
                    "description": "ISO 3166-1 **alpha-2** country code (e.g. `ES`). Invalid codes return `400`. Improves match precision via the country weight.",
                    "example": "ES"
                  },
                  "document_number": {
                    "type": "string",
                    "description": "Identity document number. Not weighted — acts as a golden key: an exact match overrides the hit's `match_score` to 100, a hard mismatch penalizes it. Sent to the screening provider as a search filter only when it is **2-50 characters**; a value outside that range is accepted and stored, and the screening still runs and is billed, just not narrowed by document number."
                  },
                  "aml_score_approve_threshold": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 80,
                    "description": "Risk-score threshold at or below which the result is `Approved`. Must be ≤ `aml_score_review_threshold` (else `400`)."
                  },
                  "aml_score_review_threshold": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 100,
                    "description": "Risk-score threshold above which the result is `Declined`. Scores between the two thresholds produce `In Review`."
                  },
                  "aml_name_weight": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 60,
                    "description": "Weight of name similarity in the per-hit match score. The three weights must sum to exactly 100 (else `400`)."
                  },
                  "aml_dob_weight": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 25,
                    "description": "Weight of date of birth in the per-hit match score."
                  },
                  "aml_country_weight": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 15,
                    "description": "Weight of country/nationality in the per-hit match score."
                  },
                  "aml_match_score_threshold": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 100,
                    "default": 93,
                    "description": "Per-hit cutoff: hits with `match_score` below this are `False Positive` (excluded from risk assessment); at or above are `Unreviewed` possible matches."
                  },
                  "include_adverse_media": {
                    "type": "boolean",
                    "default": false,
                    "description": "Also search news media for negative coverage. Adds up to ~30 s of latency while results are gathered — use a ≥60 s client timeout."
                  },
                  "include_ongoing_monitoring": {
                    "type": "boolean",
                    "default": false,
                    "description": "Keep re-screening this profile and push changes via webhook. Requires `save_api_request=true` (else `400`)."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "Persist the screening as a session (console visibility, decision endpoint, webhooks, hit review). Set to `false` for a stateless check."
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for the screened user; echoed back and stored with the session."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON stored with the request and echoed back."
                  },
                  "sandbox_scenario": {
                    "type": "string",
                    "description": "Sandbox-only scenario slug. Only accepted when the API key belongs to a sandbox-mode application; rejected on live applications. A standalone screening has no session to arm, so the slug goes on the screening request itself: `decline_aml_hit` returns one production-shaped hit and settles the screening as `Declined`, `review_aml_possible_match` settles it `In Review`, and a scenario that arms no AML outcome leaves the screening clean. See the scenario catalog at GET /v1/sandbox/scenarios/ or [Sandbox & Test Data](/integration/sandbox-testing).",
                    "example": "decline_aml_hit"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/aml/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -H 'Idempotency-Key: aml-user-1234-2026-08-20' \\\n  -d '{\n    \"full_name\": \"Antonio Ejemplo Modelo\",\n    \"entity_type\": \"person\",\n    \"date_of_birth\": \"1972-02-29\",\n    \"nationality\": \"ES\",\n    \"include_adverse_media\": false,\n    \"vendor_data\": \"user-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/aml/\",\n    headers={\n        \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n        \"Idempotency-Key\": \"aml-user-1234-2026-08-20\",\n    },\n    json={\n        \"full_name\": \"Antonio Ejemplo Modelo\",\n        \"entity_type\": \"person\",\n        \"date_of_birth\": \"1972-02-29\",\n        \"nationality\": \"ES\",\n        \"include_adverse_media\": False,\n        \"vendor_data\": \"user-1234\",\n    },\n    timeout=60,  # adverse media enrichment can add ~30s\n)\nresp.raise_for_status()\nprint(resp.json()[\"aml\"][\"status\"])  # Approved / In Review / Declined"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/aml/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n    'Idempotency-Key': 'aml-user-1234-2026-08-20',\n  },\n  body: JSON.stringify({\n    full_name: 'Antonio Ejemplo Modelo',\n    entity_type: 'person',\n    date_of_birth: '1972-02-29',\n    nationality: 'ES',\n    include_adverse_media: false,\n    vendor_data: 'user-1234',\n  }),\n});\nconst data = await res.json();\nconsole.log(data.aml.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "Screening completed. `aml.status` reflects your thresholds; every hit at or above the internal inclusion floor is listed in `aml.hits` with its identity `match_score`, entity `risk_score`, and a `score_breakdown` explaining the match.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "aml": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "In Review",
                            "Declined"
                          ],
                          "description": "`Declined` when `score` > `aml_score_review_threshold`; `In Review` when `score` > `aml_score_approve_threshold`; `Approved` otherwise (including when no score is available)."
                        },
                        "total_hits": {
                          "type": "integer",
                          "description": "Number of entries in `hits`."
                        },
                        "entity_type": {
                          "type": "string",
                          "enum": [
                            "person",
                            "company"
                          ],
                          "description": "Echo of the screened entity type."
                        },
                        "hits": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "description": "One screening hit. `match_score` (0–100) measures identity confidence — hits below `aml_match_score_threshold` are tagged `review_status: \"False Positive\"` and excluded from the risk assessment; hits at or above it are `\"Unreviewed\"` possible matches. `risk_score` (0–100) measures how risky the matched entity is and drives the top-level `aml.score`.",
                            "properties": {
                              "id": {
                                "type": "string",
                                "nullable": true,
                                "description": "Stable identifier of the matched entity in the screening datasets."
                              },
                              "url": {
                                "type": "string",
                                "nullable": true,
                                "description": "Source URL for the matched entity, when available."
                              },
                              "match": {
                                "type": "boolean",
                                "nullable": true,
                                "description": "Legacy exact-match flag. Prefer `match_score` + `review_status`."
                              },
                              "score": {
                                "type": "number",
                                "nullable": true,
                                "description": "DEPRECATED weighted match score in the 0–1 range. Use `match_score` instead."
                              },
                              "match_score": {
                                "type": "number",
                                "nullable": true,
                                "description": "Identity confidence (0–100). Compared against `aml_match_score_threshold` to split False Positives from Possible Matches."
                              },
                              "risk_score": {
                                "type": "number",
                                "nullable": true,
                                "description": "Entity risk score (0–100). The highest `risk_score` among non-false-positive hits becomes the top-level `aml.score`."
                              },
                              "target": {
                                "type": "boolean",
                                "nullable": true
                              },
                              "caption": {
                                "type": "string",
                                "nullable": true,
                                "description": "Display name of the matched entity."
                              },
                              "datasets": {
                                "type": "array",
                                "nullable": true,
                                "items": {
                                  "type": "string"
                                },
                                "description": "Datasets the entity appears in (e.g. `PEP`, `PEP Level 1`, sanctions list names)."
                              },
                              "features": {
                                "type": "object",
                                "nullable": true
                              },
                              "properties": {
                                "type": "object",
                                "nullable": true,
                                "description": "Entity profile: `name`, `alias`, `notes`, `gender`, `birthDate`, `birthPlace`, `nationality`, `position`, and other biographical arrays (each nullable)."
                              },
                              "rca_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Name of the related close associate through which the entity was matched, when the hit is an RCA."
                              },
                              "pep_matches": {
                                "type": "array",
                                "description": "PEP list entries backing this hit.",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "list_name": {
                                      "type": "string"
                                    },
                                    "publisher": {
                                      "type": "string"
                                    },
                                    "source_url": {
                                      "type": "string"
                                    },
                                    "description": {
                                      "type": "string"
                                    },
                                    "matched_name": {
                                      "type": "string"
                                    },
                                    "pep_position": {
                                      "type": "string"
                                    },
                                    "date_of_birth": {
                                      "type": "string"
                                    },
                                    "place_of_birth": {
                                      "type": "string"
                                    },
                                    "aliases": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "education": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "other_sources": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "sanction_matches": {
                                "type": "array",
                                "items": {
                                  "type": "object"
                                },
                                "description": "Sanctions list entries backing this hit (same backing-list shape as `pep_matches`, plus sanction-specific fields)."
                              },
                              "warning_matches": {
                                "type": "array",
                                "items": {
                                  "type": "object"
                                },
                                "description": "Warning/watchlist entries backing this hit."
                              },
                              "adverse_media_matches": {
                                "type": "array",
                                "description": "Adverse-media articles. Populated only when `include_adverse_media=true`.",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "headline": {
                                      "type": "string"
                                    },
                                    "summary": {
                                      "type": "string"
                                    },
                                    "sentiment": {
                                      "type": "string"
                                    },
                                    "sentiment_score": {
                                      "type": "number"
                                    },
                                    "source_url": {
                                      "type": "string"
                                    },
                                    "thumbnail": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "country": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "author_name": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "publication_date": {
                                      "type": "string",
                                      "nullable": true
                                    },
                                    "adverse_keywords": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "other_sources": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "adverse_media_details": {
                                "type": "object",
                                "nullable": true,
                                "description": "Aggregated adverse-media sentiment for the entity (`sentiment`, `sentiment_score`, `adverse_keywords` frequency map). Populated only when `include_adverse_media=true`."
                              },
                              "first_seen": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "When the entity first appeared in the datasets."
                              },
                              "last_seen": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "Most recent dataset refresh that included the entity."
                              },
                              "linked_entities": {
                                "type": "array",
                                "description": "Known relationships of the matched entity (family, associates, companies).",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "name": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "relation": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "status": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "details": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    },
                                    "active": {
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              },
                              "risk_view": {
                                "type": "object",
                                "nullable": true,
                                "description": "Per-dimension risk breakdown (`crimes`, `countries`, `categories`, `custom_list`), each with `score`, `weightage`, `risk_level`, and a `risk_scores` map."
                              },
                              "additional_information": {
                                "type": "object",
                                "nullable": true,
                                "description": "Free-form extra context, e.g. a `flag_summary` array explaining why the entity is flagged."
                              },
                              "review_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "False Positive",
                                  "Unreviewed",
                                  "Confirmed Match",
                                  "Inconclusive"
                                ],
                                "description": "`False Positive` — `match_score` below `aml_match_score_threshold`, excluded from risk assessment. `Unreviewed` — possible match awaiting review. `Confirmed Match` / `Inconclusive` — set manually by a reviewer (via the Business Console) on saved sessions; that review capability is not part of this spec."
                              },
                              "score_breakdown": {
                                "type": "object",
                                "nullable": true,
                                "description": "How `match_score` was computed. Name, date of birth, and country each contribute `<component>_score` × `<component>_weight_normalized` points; weights are re-normalized when a component is missing from the screened data. The document number is not weighted — it acts as a 'golden key': `MATCH` overrides the score to 100, `NEUTRAL` leaves it unchanged, `HARD_MISMATCH` applies a penalty.",
                                "properties": {
                                  "name_score": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Raw name similarity (0–100)."
                                  },
                                  "name_weight": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Configured name weight (`aml_name_weight`)."
                                  },
                                  "name_weight_normalized": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Name weight after re-normalization (0–100)."
                                  },
                                  "name_contribution": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Points the name contributed to `total_score`."
                                  },
                                  "dob_score": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Date-of-birth score as a percentage of its weight (−100 to 100)."
                                  },
                                  "dob_weight": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Configured DOB weight (`aml_dob_weight`)."
                                  },
                                  "dob_weight_normalized": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "DOB weight after re-normalization (0–100)."
                                  },
                                  "dob_contribution": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Points the DOB contributed to `total_score`."
                                  },
                                  "country_score": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Country score as a percentage of its weight (−100 to 100)."
                                  },
                                  "country_weight": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Configured country weight (`aml_country_weight`)."
                                  },
                                  "country_weight_normalized": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Country weight after re-normalization (0–100)."
                                  },
                                  "country_contribution": {
                                    "type": "number",
                                    "nullable": true,
                                    "description": "Points the country contributed to `total_score`."
                                  },
                                  "document_number_match_type": {
                                    "type": "string",
                                    "nullable": true,
                                    "enum": [
                                      "MATCH",
                                      "NEUTRAL",
                                      "HARD_MISMATCH"
                                    ],
                                    "description": "Golden-key result for the document number comparison."
                                  },
                                  "document_number_effect": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Human-readable description of the document-number effect."
                                  },
                                  "total_score": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "Final weighted match score (0–100) — mirrors `match_score`."
                                  }
                                }
                              }
                            }
                          }
                        },
                        "score": {
                          "type": "number",
                          "nullable": true,
                          "description": "Overall AML risk score (0–100): the highest `risk_score` among hits that are not False Positives. Drives `status` via the two thresholds."
                        },
                        "screened_data": {
                          "type": "object",
                          "description": "Echo of what was screened: `full_name`, `date_of_birth`, `nationality`, `document_number` (absent fields are `null`).",
                          "properties": {
                            "full_name": {
                              "type": "string"
                            },
                            "date_of_birth": {
                              "type": "string",
                              "nullable": true
                            },
                            "nationality": {
                              "type": "string",
                              "nullable": true
                            },
                            "document_number": {
                              "type": "string",
                              "nullable": true
                            }
                          }
                        },
                        "warnings": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "feature": {
                                "type": "string",
                                "description": "Feature that raised the warning."
                              },
                              "risk": {
                                "type": "string",
                                "description": "Machine-readable risk identifier."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "description": "Extra context for the warning, when available."
                              },
                              "log_type": {
                                "type": "string",
                                "description": "`warning`, `information`, or `error` — how the risk affected the outcome."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "One-line human-readable summary."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Full human-readable explanation."
                              }
                            }
                          },
                          "description": "Contains a `POSSIBLE_MATCH_FOUND` warning whenever `score` is non-zero and ≥ `aml_score_approve_threshold` (a score of exactly 0 never warns); empty otherwise."
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "description": "Echo of the `metadata` you sent."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "examples": {
                  "No hits (Approved)": {
                    "summary": "Clean screening — zero hits",
                    "value": {
                      "request_id": "d27c5509-7a66-45a9-b05e-d69d9f4c336a",
                      "aml": {
                        "status": "Approved",
                        "total_hits": 0,
                        "entity_type": "person",
                        "hits": [],
                        "score": 0,
                        "screened_data": {
                          "full_name": "Maximilian Mustermann-Doe",
                          "date_of_birth": "1992-03-14",
                          "nationality": "DE",
                          "document_number": null
                        },
                        "warnings": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": {
                        "internal_ref": "abc-123"
                      },
                      "created_at": "2026-06-11T10:21:07.013938+00:00"
                    }
                  },
                  "PEP hit (Approved — risk below approve threshold)": {
                    "summary": "One PEP possible match; risk score 73 stays under the default approve threshold of 80",
                    "value": {
                      "request_id": "0b7e7a3e-65a1-4f3d-9c7a-1de2f9a40111",
                      "aml": {
                        "status": "Approved",
                        "total_hits": 1,
                        "entity_type": "person",
                        "hits": [
                          {
                            "id": "kDpfszrbkDdaxpMVZw3NLg",
                            "url": "https://news.example.org/articles/sample",
                            "match": false,
                            "score": 0.93,
                            "match_score": 93.0,
                            "risk_score": 73.0,
                            "target": null,
                            "caption": "Antonio Ejemplo Modelo",
                            "datasets": [
                              "PEP Level 1",
                              "PEP"
                            ],
                            "features": null,
                            "rca_name": "",
                            "first_seen": "2026-01-07T00:00:00",
                            "last_seen": "2026-01-07T00:00:00",
                            "review_status": "Unreviewed",
                            "properties": {
                              "name": [
                                "Antonio Ejemplo Modelo",
                                "Antonio Ejemplo"
                              ],
                              "alias": [
                                "Antonio Ejemplo Modelo",
                                "Ejemplo Modelo, Pedro"
                              ],
                              "notes": [
                                "Prime Minister of Spain"
                              ],
                              "gender": [
                                "male"
                              ],
                              "birthDate": [
                                "1972-02-29"
                              ],
                              "birthPlace": [
                                "Madrid, Spain"
                              ],
                              "nationality": null,
                              "position": null
                            },
                            "risk_view": {
                              "crimes": {
                                "score": 0.0,
                                "weightage": 20,
                                "risk_level": "Low",
                                "risk_scores": {}
                              },
                              "countries": {
                                "score": 9.64,
                                "weightage": 30,
                                "risk_level": "Low",
                                "risk_scores": {
                                  "Spain": 25.71
                                }
                              },
                              "categories": {
                                "score": 62.5,
                                "weightage": 50,
                                "risk_level": "High",
                                "risk_scores": {
                                  "PEP": 100.0,
                                  "PEP Level 1": 100.0
                                }
                              },
                              "custom_list": {}
                            },
                            "score_breakdown": {
                              "name_score": 89,
                              "name_weight": 60,
                              "name_weight_normalized": 60.0,
                              "name_contribution": 53.4,
                              "dob_score": 100,
                              "dob_weight": 25,
                              "dob_weight_normalized": 25.0,
                              "dob_contribution": 25.0,
                              "country_score": 100,
                              "country_weight": 15,
                              "country_weight_normalized": 15.0,
                              "country_contribution": 15.0,
                              "document_number_match_type": "NEUTRAL",
                              "document_number_effect": "No document number provided for screening",
                              "total_score": 93
                            },
                            "pep_matches": [
                              {
                                "aliases": [],
                                "education": [],
                                "list_name": "Presidency of the Government of Spain",
                                "publisher": "Presidency of the Government of Spain",
                                "source_url": "https://news.example.org/articles/sample",
                                "description": "The Presidency of the Government is the central institutional body in Spain that supports the Prime Minister and coordinates the general action of the central government.",
                                "matched_name": "Antonio Ejemplo Modelo",
                                "pep_position": "",
                                "date_of_birth": "1972-02-29",
                                "other_sources": [],
                                "place_of_birth": "Madrid, Spain"
                              }
                            ],
                            "sanction_matches": [],
                            "warning_matches": [],
                            "adverse_media_matches": [],
                            "adverse_media_details": null,
                            "linked_entities": [
                              {
                                "name": [
                                  "Maria Begona Gomez Fernandez"
                                ],
                                "active": [],
                                "status": [],
                                "details": [],
                                "relation": [
                                  "spouse"
                                ]
                              }
                            ],
                            "additional_information": {
                              "flag_summary": [
                                "Antonio Ejemplo Modelo has been flagged as a Level 1 Politically Exposed Person (PEP) from Spain, serving as the President of the Government of Spain."
                              ]
                            }
                          }
                        ],
                        "score": 73.0,
                        "screened_data": {
                          "full_name": "Pedro Sanchez Perez-Castejon",
                          "date_of_birth": "1972-02-29",
                          "nationality": "ES",
                          "document_number": null
                        },
                        "warnings": []
                      },
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-06-11T10:23:44.812000+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field-level problems return DRF's standard envelope (one array of messages per offending field); cross-field rules (weight sum, threshold ordering, monitoring-without-save) return `{\"error\": [...]}`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing full_name": {
                    "summary": "`full_name` is the only required field",
                    "value": {
                      "full_name": [
                        "This field is required."
                      ]
                    }
                  },
                  "Short full_name": {
                    "summary": "`full_name` must be at least 2 characters",
                    "value": {
                      "full_name": [
                        "Ensure this field has at least 2 characters."
                      ]
                    }
                  },
                  "Invalid nationality": {
                    "summary": "`nationality` must be ISO 3166-1 alpha-2",
                    "value": {
                      "nationality": [
                        "Invalid ISO 3166-1 alpha-2 country code."
                      ]
                    }
                  },
                  "Weights do not sum to 100": {
                    "summary": "`aml_name_weight` + `aml_dob_weight` + `aml_country_weight` ≠ 100",
                    "value": {
                      "error": [
                        "AML weights must sum to 100. Current sum: 90 (name: 50, dob: 25, country: 15)"
                      ]
                    }
                  },
                  "Thresholds out of order": {
                    "summary": "Approve threshold above review threshold",
                    "value": {
                      "error": [
                        "Approve threshold (90.0) cannot be greater than review threshold (80.0)"
                      ]
                    }
                  },
                  "Monitoring without saving": {
                    "summary": "`include_ongoing_monitoring=true` with `save_api_request=false`",
                    "value": {
                      "error": [
                        "Ongoing monitoring can only be enabled when the API request is saved."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any screening or provider call happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/face-search/": {
      "post": {
        "summary": "Face Search",
        "description": "Search a face image (1:N) against your application's face search index — faces enrolled from verification sessions, saved standalone API calls, direct user-profile face uploads, and your block/allow lists — and get back ranked similarity matches plus blocklist and duplicate warnings.\n\n**How it works.** The largest detected face in `user_image` is embedded and searched against the index, scoped to your application. Up to **5 matches** above the similarity floor are returned in `matches`, each with `similarity_percentage`, the originating session (`session_id`, `session_number`, `status`, `vendor_data`), `user_details` extracted during that session's document verification, `is_blocklisted` / `is_allowlisted` flags, and a `source` discriminator (`session`, `imported`, or `list_entry`).\n\n- `search_type=most_similar` (default) ranks every enrolled face by similarity — use it for deduplication and fraud-ring investigation.\n- `search_type=blocklisted_or_approved` restricts candidates to blocklisted faces, allowlisted faces, faces from approved sessions, and imported user-profile faces, ranking blocklisted entries first — use it when the primary goal is blocklist screening.\n\n`status` is `Declined` only when a `FACE_IN_BLOCKLIST` or `POSSIBLE_FACE_IN_BLOCKLIST` warning fires; `DUPLICATED_FACE` / `POSSIBLE_DUPLICATED_FACE` (`information`) and `MULTIPLE_FACES_DETECTED` (`warning`) never decline. Unlike Passive Liveness, this endpoint does **not** exclude prior sessions with the same `vendor_data` from matching. A passive-liveness analysis also runs internally and is stored with the persisted session, but its result is not part of this response.\n\n**Billing.** Each `200` response consumes one Face Search API credit (standalone APIs have no free tier). Insufficient balance returns `403` before any image processing.\n\n**Session persistence and face enrollment (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session (Business Console, `GET /v3/session/{sessionId}/decision/` via the returned `request_id`, `status.updated` webhook) and the searched face is enrolled into your face search index. Faces enrolled by Face Search calls are excluded from future Face Search results, so repeated searches never match each other. When `false`, the call is one-shot: nothing is stored, the face is not enrolled, and `match_image_url` values are internal storage paths rather than downloadable URLs.\n\n**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload, no session is persisted, and no credits are consumed.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.",
        "operationId": "post_v3face-search",
        "tags": [
          "Standalone APIs"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "user_image"
                ],
                "properties": {
                  "user_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Front-facing face image to search with. Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `webp`. Maximum upload size: **5 MB** (larger files are rejected with `400`). Images are automatically compressed to ~0.5 MB before processing, so very high resolutions do not improve accuracy. The image must contain at least one detectable face — otherwise the endpoint returns `400`. When several faces are present, the largest one is searched and a `MULTIPLE_FACES_DETECTED` warning is added."
                  },
                  "search_type": {
                    "type": "string",
                    "default": "most_similar",
                    "enum": [
                      "most_similar",
                      "blocklisted_or_approved"
                    ],
                    "description": "Search policy. `most_similar` (default) ranks every enrolled face in your application by similarity. `blocklisted_or_approved` restricts candidates to blocklisted faces, allowlisted faces, faces from approved sessions, and imported user-profile faces — with blocklisted entries ranked first.",
                    "example": "most_similar"
                  },
                  "rotate_image": {
                    "type": "boolean",
                    "default": false,
                    "description": "When `true`, the service tries 90-degree rotations of the input and uses the orientation that yields the best face detection. Useful when EXIF orientation is missing. Adds latency.",
                    "example": false
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session, emits a `status.updated` webhook, presigns `match_image_url` values, and enrolls the searched face into your face search index (Face Search enrollments are excluded from future searches). When `false`, the search is one-shot — no session is stored and the face is not enrolled.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque identifier (your user id, email, UUID…) stored on the persisted session and echoed back. It does not exclude same-user faces from the search results.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back. In multipart requests, send it as a JSON-encoded string field — it is parsed into an object.",
                    "example": {
                      "flow": "dedup_check"
                    }
                  }
                }
              },
              "example": {
                "user_image": "(binary JPEG/PNG selfie)",
                "search_type": "most_similar",
                "rotate_image": false,
                "save_api_request": true,
                "vendor_data": "user-123",
                "metadata": {
                  "flow": "dedup_check"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Face search completed. `face_search.matches` holds up to 5 similar faces ordered by similarity; an empty array means no enrolled face exceeded the similarity floor. `status` is `Declined` only on blocklist hits — duplicate matches alone return `Approved`, so inspect `matches` and `warnings`, not just `status`. When `save_api_request=true`, `request_id` is the persisted session id. Each match carries `source` (`session`, `imported`, `list_entry`, or `retained_template`), `vendor_user_id`, and `biometric_template_id`; a `retained_template` match comes from an image-free biometric template kept after the source session was deleted and has `null` session fields, `match_image_url`, and `user_details`.",
            "content": {
              "application/json": {
                "examples": {
                  "Blocklist hit (Declined)": {
                    "summary": "The face matches a blocklisted face",
                    "value": {
                      "request_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                      "face_search": {
                        "status": "Declined",
                        "total_matches": 1,
                        "matches": [
                          {
                            "session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
                            "session_number": 323442,
                            "similarity_percentage": 99.99,
                            "source": "session",
                            "vendor_data": "user-1",
                            "verification_date": "2025-01-01T00:00:00Z",
                            "user_details": {
                              "full_name": "Jane Marie Doe",
                              "document_type": "ID",
                              "document_number": "X1234567"
                            },
                            "match_image_url": "https://<media-host>/face/3f6a1c2e/reference.jpg",
                            "status": "Approved",
                            "is_blocklisted": true,
                            "is_allowlisted": false,
                            "api_service": null,
                            "vendor_user_id": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f",
                            "biometric_template_id": null
                          }
                        ],
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                40,
                                40,
                                120,
                                120
                              ],
                              "confidence": 0.732973
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": [
                          {
                            "risk": "FACE_IN_BLOCKLIST",
                            "feature": "LIVENESS",
                            "additional_data": {
                              "blocklisted_session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
                              "blocklisted_session_number": 323442,
                              "api_service": null
                            },
                            "log_type": "error",
                            "short_description": "Face in blocklist",
                            "long_description": "The system identified a face in the blocklist, which means the face is not allowed to be verified."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  },
                  "Duplicate found (Approved)": {
                    "summary": "The face already appeared in another approved session — informational, no decline",
                    "value": {
                      "request_id": "5e0c3a1f-7b2d-4c8e-9f10-2a3b4c5d6e7f",
                      "face_search": {
                        "status": "Approved",
                        "total_matches": 1,
                        "matches": [
                          {
                            "session_id": "1f2e3d4c-5b6a-7980-1122-334455667788",
                            "session_number": 1024,
                            "similarity_percentage": 87.42,
                            "source": "session",
                            "vendor_data": "user-9",
                            "verification_date": "2025-11-20T09:15:00Z",
                            "user_details": null,
                            "match_image_url": "https://<media-host>/face/9c8b7a6d/reference.jpg",
                            "status": "Approved",
                            "is_blocklisted": false,
                            "is_allowlisted": false,
                            "api_service": "PASSIVE_LIVENESS",
                            "vendor_user_id": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f",
                            "biometric_template_id": null
                          }
                        ],
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                40,
                                40,
                                120,
                                120
                              ],
                              "confidence": 0.732973
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": [
                          {
                            "risk": "DUPLICATED_FACE",
                            "feature": "LIVENESS",
                            "additional_data": {
                              "duplicated_session_id": "1f2e3d4c-5b6a-7980-1122-334455667788",
                              "duplicated_session_number": 1024,
                              "api_service": "PASSIVE_LIVENESS"
                            },
                            "log_type": "information",
                            "short_description": "Duplicated face from other approved session",
                            "long_description": "The system identified a duplicated face from another approved session, requiring further investigation."
                          }
                        ]
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  },
                  "No matches (Approved)": {
                    "summary": "No enrolled face exceeded the similarity floor",
                    "value": {
                      "request_id": "9d8c7b6a-5f4e-3d2c-1b0a-998877665544",
                      "face_search": {
                        "status": "Approved",
                        "total_matches": 0,
                        "matches": [],
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                40,
                                40,
                                120,
                                120
                              ],
                              "confidence": 0.732973
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": []
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "face_search": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined"
                          ],
                          "description": "`Declined` only when a `FACE_IN_BLOCKLIST` or `POSSIBLE_FACE_IN_BLOCKLIST` warning fired. Duplicate matches and multiple-face warnings never decline."
                        },
                        "total_matches": {
                          "type": "integer",
                          "description": "Number of entries in `matches` (0–5).",
                          "example": 1
                        },
                        "matches": {
                          "type": "array",
                          "maxItems": 5,
                          "description": "Up to 5 faces from your face search index that exceed the similarity floor, ordered by similarity (with blocklisted entries ranked first when `search_type=blocklisted_or_approved`). Empty when no enrolled face is similar enough.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "session_id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true,
                                "description": "Id of the verification session the matched face belongs to. `null` when `source` is `imported`, `list_entry`, or `retained_template`.",
                                "example": "882c42d5-8a4d-4d20-8080-a22f57822c86"
                              },
                              "session_number": {
                                "type": "integer",
                                "nullable": true,
                                "description": "Human-friendly session number shown in the Business Console. `null` for non-session matches.",
                                "example": 323442
                              },
                              "similarity_percentage": {
                                "type": "number",
                                "format": "float",
                                "minimum": 0,
                                "maximum": 100,
                                "description": "Similarity between the submitted face and the matched face (0–100).",
                                "example": 99.99
                              },
                              "source": {
                                "type": "string",
                                "enum": [
                                  "session",
                                  "imported",
                                  "list_entry",
                                  "retained_template"
                                ],
                                "description": "Where the matched face was enrolled from: `session` — a verification session or a saved standalone API call; `imported` — a face uploaded directly to a User profile; `list_entry` — a face attached to one of your lists; `retained_template` — an image-free biometric template stored on a User, listed under `/v3/biometric-templates/`."
                              },
                              "vendor_data": {
                                "type": "string",
                                "nullable": true,
                                "description": "`vendor_data` of the matched session or linked User for imported and retained-template faces.",
                                "example": "user-1"
                              },
                              "vendor_user_id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true,
                                "description": "Linked User id. `null` for list entries and session matches without a User.",
                                "example": "2f7c1a9e-4b28-4a6d-97f1-83576f80e1b4"
                              },
                              "biometric_template_id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true,
                                "description": "Id of the retained biometric template. Set only when `source` is `retained_template`; `null` otherwise.",
                                "example": null
                              },
                              "verification_date": {
                                "type": "string",
                                "format": "date-time",
                                "nullable": true,
                                "description": "When the matched face was originally captured, or when a retained template was created (`YYYY-MM-DDThh:mm:ssZ`). `null` for `list_entry` matches.",
                                "example": "2025-01-01T00:00:00Z"
                              },
                              "user_details": {
                                "type": "object",
                                "nullable": true,
                                "description": "Identity data extracted during the matched session's document verification. `null` when the matched session has no document data (e.g. liveness-only sessions) and always `null` for `retained_template` matches. For `source: imported` matches it is populated from the User profile instead: `full_name` set, `document_type`/`document_number` null.",
                                "properties": {
                                  "full_name": {
                                    "type": "string",
                                    "nullable": true,
                                    "example": "Jane Marie Doe"
                                  },
                                  "document_type": {
                                    "type": "string",
                                    "nullable": true,
                                    "example": "ID"
                                  },
                                  "document_number": {
                                    "type": "string",
                                    "nullable": true,
                                    "example": "X1234567"
                                  }
                                }
                              },
                              "match_image_url": {
                                "type": "string",
                                "nullable": true,
                                "description": "Time-limited URL (`https://<media-host>/...`) of the matched face's reference image when `save_api_request=true`. With `save_api_request=false` this is an internal storage path that is not directly downloadable. Always `null` for `retained_template` matches because retained templates contain no image.",
                                "example": "https://<media-host>/face/3f6a1c2e/reference.jpg"
                              },
                              "status": {
                                "type": "string",
                                "nullable": true,
                                "description": "Status of the matched session (`Approved`, `Declined`, `In Review`, …). `null` for `imported`/`list_entry` matches.",
                                "example": "Approved"
                              },
                              "is_blocklisted": {
                                "type": "boolean",
                                "description": "`true` when the matched face is on your face blocklist. Any sufficiently similar blocklisted match declines the search."
                              },
                              "is_allowlisted": {
                                "type": "boolean",
                                "description": "`true` when the matched face is on one of your allowlists. Allowlisted matches suppress duplicate warnings."
                              },
                              "api_service": {
                                "type": "string",
                                "nullable": true,
                                "description": "Set when the matched face was enrolled by a standalone API call (e.g. `PASSIVE_LIVENESS`); `null` for regular verification sessions and imported faces.",
                                "example": null
                              }
                            }
                          }
                        },
                        "user_image": {
                          "type": "object",
                          "description": "Face-detection results for the submitted image. Entries here carry only `bbox` and `confidence`.",
                          "properties": {
                            "entities": {
                              "type": "array",
                              "description": "One entry per detected face. The largest face is the one searched.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "bbox": {
                                    "type": "array",
                                    "items": {
                                      "type": "integer"
                                    },
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "description": "Bounding box `[x_min, y_min, x_max, y_max]` in pixels.",
                                    "example": [
                                      40,
                                      40,
                                      120,
                                      120
                                    ]
                                  },
                                  "confidence": {
                                    "type": "number",
                                    "format": "float",
                                    "minimum": 0,
                                    "maximum": 1,
                                    "description": "Face-detection confidence (0–1).",
                                    "example": 0.732973
                                  }
                                }
                              }
                            },
                            "best_angle": {
                              "type": "integer",
                              "description": "Rotation (degrees) that produced the best face detection; non-zero only when `rotate_image=true` corrected the orientation. Never null on this endpoint (defaults to 0 when the model omits it).",
                              "example": 0
                            }
                          }
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Risk signals. `FACE_IN_BLOCKLIST` / `POSSIBLE_FACE_IN_BLOCKLIST` (`error`) decline the search; `MULTIPLE_FACES_DETECTED` (`warning`) and `DUPLICATED_FACE` / `POSSIBLE_DUPLICATED_FACE` (`information`) are advisory.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "enum": [
                                  "MULTIPLE_FACES_DETECTED",
                                  "FACE_IN_BLOCKLIST",
                                  "POSSIBLE_FACE_IN_BLOCKLIST",
                                  "DUPLICATED_FACE",
                                  "POSSIBLE_DUPLICATED_FACE"
                                ],
                                "description": "Machine-readable risk code."
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "LIVENESS"
                                ],
                                "description": "Feature that raised the warning. Always `LIVENESS` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "`null` for `MULTIPLE_FACES_DETECTED`. Blocklist hits carry `{blocklisted_session_id, blocklisted_session_number, api_service}`; duplicate hits carry `{duplicated_session_id, duplicated_session_number, api_service}` pointing at the first matching session."
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error",
                                  "warning",
                                  "information"
                                ],
                                "description": "Severity. `error` warnings drive `status` to `Declined`; `warning` and `information` entries are advisory and never decline on their own."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-line summary of the risk."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation of the risk."
                              }
                            }
                          }
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp (UTC) of when the response was generated, e.g. `2026-06-12T01:04:42.763237+00:00`."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Returned when `user_image` is missing, exceeds 5 MB, has an unsupported extension, or when **no face is detected** in the submitted image. Field errors use DRF's `{field: [messages]}` envelope; face-detection failures use `{\"error\": ...}`.",
            "content": {
              "application/json": {
                "examples": {
                  "No face detected": {
                    "summary": "The image decodes fine but contains no detectable face",
                    "value": {
                      "error": "No face detected in the image"
                    }
                  },
                  "Missing image": {
                    "summary": "`user_image` not included in the form data",
                    "value": {
                      "user_image": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Unsupported file extension": {
                    "summary": "File extension outside tiff/jpg/jpeg/png/webp",
                    "value": {
                      "user_image": [
                        "File extension “txt” is not allowed. Allowed extensions are: tiff, jpg, jpeg, png, webp."
                      ]
                    }
                  },
                  "File too large": {
                    "summary": "Upload exceeds the 5 MB limit",
                    "value": {
                      "user_image": [
                        "File size should not exceed 5 MB"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any image processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/face-search/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'user_image=@./selfie.jpg' \\\n  -F 'search_type=most_similar' \\\n  -F 'save_api_request=true' \\\n  -F 'vendor_data=user-123'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = 'https://verification.didit.me/v3/face-search/'\nheaders = {'x-api-key': 'YOUR_API_KEY'}\n\nwith open('selfie.jpg', 'rb') as f:\n    files = {'user_image': ('selfie.jpg', f, 'image/jpeg')}\n    data = {\n        'search_type': 'most_similar',\n        'save_api_request': 'true',\n        'vendor_data': 'user-123',\n    }\n    resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)\n\nresp.raise_for_status()\nbody = resp.json()\nprint('status:', body['face_search']['status'])\nprint('matches:', body['face_search']['total_matches'])\nfor m in body['face_search']['matches']:\n    print(f\"  session={m['session_id']} similarity={m['similarity_percentage']} blocklisted={m['is_blocklisted']}\")"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import fs from 'node:fs';\n\nconst form = new FormData();\nform.append('user_image', new Blob([fs.readFileSync('./selfie.jpg')]), 'selfie.jpg');\nform.append('search_type', 'most_similar');\nform.append('save_api_request', 'true');\nform.append('vendor_data', 'user-123');\n\nconst response = await fetch('https://verification.didit.me/v3/face-search/', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n  body: form,\n});\n\nif (!response.ok) throw new Error(`Face search failed: ${response.status}`);\nconst body = await response.json();\nconsole.log('status:', body.face_search.status, 'matches:', body.face_search.total_matches);\nbody.face_search.matches.forEach(m =>\n  console.log(`  session=${m.session_id} similarity=${m.similarity_percentage} blocklisted=${m.is_blocklisted}`)\n);"
          }
        ]
      }
    },
    "/v3/sessions/": {
      "get": {
        "summary": "List verification sessions (KYC and/or KYB) with filters and pagination",
        "description": "Returns a paginated list of verification sessions for the application identified by your API key, newest first (descending `session_number`).\n\n**Canonical URL:** the route is `/v3/sessions/` (trailing slash). Requests to `/v3/sessions` without the slash receive a `301` redirect to the slashed URL with the query string preserved; most HTTP clients follow it transparently on GET.\n\n**When to use this endpoint vs webhooks.** Use this endpoint for dashboards, back-office search, reconciliation, and batch exports. Do not poll it to track the progress of individual verifications - configure [webhooks](/integration/webhooks) instead, which push `status.updated` events the moment a session changes. For one session's full result, call `GET /v3/session/{sessionId}/decision/`.\n\n**KYC and KYB sessions.** `session_kind` selects which kinds are listed:\n- `user` (default) - User Verification (KYC) sessions only. Backward-compatible behavior.\n- `business` - Business Verification (KYB) sessions only. Rows have a different, smaller shape (see the response schema).\n- `all` - both kinds in one response: the KYC page and the KYB page for the same `limit`/`offset` are concatenated in `results` (KYC rows first), so a page can contain up to `2 x limit` rows. `count` is the sum of both kinds and `next`/`previous` reflect the KYC-side pagination. For strict pagination of mixed data, call `user` and `business` separately.\n\nEvery row carries a `session_kind` discriminator (`\"user\"` or `\"business\"`).\n\n**Pagination.** Standard limit/offset: `limit` (default 50) and `offset` (default 0), with `next`/`previous` ready-made page URLs. For KYC rows `count` is exact. For KYB rows `count` is computed with a bounded scan and is capped at 100 - when there are more than 100 matches it stays at 100, so iterate using `next` (or by checking whether a full page came back) rather than computing total pages from `count`.\n\n**Filter semantics.** All filters combine with AND and apply to KYC rows. When `session_kind` is `business` or `all`, the KYB side honors the shared parameters `vendor_data`, `status`, `workflow_id`, `country` (registry-company country code), `date_from`, `date_to`, `search` (company name, registration number — type registration numbers without separators, e.g. `DPC001` not `DPC-001` — vendor_data, session number, or session UUID), `warning`, and `organization_name`; the remaining KYC-only filters are ignored for KYB rows. Comma-separated parameters (`status`, `country`, `document_type`, `region`, `workflow_id`, `document_name`, `warning`, `organization_name`, `session_type`) match any of the listed values (OR within the parameter). `vendor_data` is an exact match - use `search` for partial matching. Unknown values in list filters simply return no rows (no error); malformed typed values (`date_from`, `date_to`, `didit_internal_id`, `api_service`, `session_kind`) return `400` with a per-field error object.\n\n**Search.** `search` adapts to the input: a full UUID looks up `session_id`; digits (with optional `+ - . space`) match session-number prefix, document/personal numbers, phone-number prefix, or `vendor_data`; values containing `@` match email prefixes; any other text matches names (accent-insensitive) and `vendor_data`.\n\nNo fixed per-endpoint rate limit is enforced, but keep list polling infrequent and rely on webhooks for real-time updates.",
        "operationId": "get_v3_sessions",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "session_kind",
            "in": "query",
            "required": false,
            "description": "Which kind of sessions to list: `user` (KYC only, default), `business` (KYB only), or `all` (both, concatenated - see the description for merged-pagination semantics). Matching is case-insensitive (`BUSINESS` works); any value other than a case variant of `user`/`business`/`all` returns `400`.",
            "schema": {
              "type": "string",
              "enum": [
                "user",
                "business",
                "all"
              ],
              "default": "user"
            },
            "example": "all"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of rows per page (per kind when `session_kind=all`). Defaults to 50.",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "example": 20
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of rows to skip before the first returned row. Defaults to 0. Prefer following the `next`/`previous` URLs from the response.",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "example": 20
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of session statuses to include, e.g. `Approved,In Review`. Values are case-sensitive; see [Verification Statuses](/integration/verification-statuses). Unknown values match nothing.",
            "schema": {
              "type": "string"
            },
            "example": "Approved,In Review"
          },
          {
            "name": "vendor_data",
            "in": "query",
            "required": false,
            "description": "Exact-match filter on the `vendor_data` you sent at session creation (your own user/business identifier). For partial matches use `search` instead.",
            "schema": {
              "type": "string"
            },
            "example": "your-user-id-123"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Smart free-text search. A full UUID matches `session_id`; numeric input matches session-number prefix, document/personal numbers, phone prefix, or `vendor_data`; input containing `@` matches email prefixes; other text matches names (accent-insensitive) and `vendor_data`. Free text containing digits additionally matches document/personal-number search fields and session-number prefixes.",
            "schema": {
              "type": "string"
            },
            "example": "jane doe"
          },
          {
            "name": "workflow_id",
            "in": "query",
            "required": false,
            "description": "Comma-separated workflow UUIDs (find them on the Workflows page in the Console). Malformed UUIDs in the list are ignored; if none are valid the result is empty.",
            "schema": {
              "type": "string"
            },
            "example": "9f9b1234-aaaa-bbbb-cccc-1234567890ab"
          },
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "description": "Only sessions created on or after this date (UTC), format `YYYY-MM-DD`. Malformed dates return `400`.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-06-01"
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "description": "Only sessions created up to this date (UTC), format `YYYY-MM-DD`. For KYC rows the entire day is included; for KYB rows the comparison is `created_at <= date_to` (midnight), so use the next day's date to include a full day of KYB sessions.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-06-30"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Comma-separated country filter. For KYC rows: ISO 3166-1 alpha-3 codes of the ID document's issuing state (e.g. `ESP,USA`), which may differ from nationality. For KYB rows: the registry company's country code.",
            "schema": {
              "type": "string"
            },
            "example": "ESP,USA"
          },
          {
            "name": "document_type",
            "in": "query",
            "required": false,
            "description": "Comma-separated ID-document type codes verified in the session (KYC rows only): `P` (Passport), `ID` (Identity Card), `DL` (Driver's License), `RP` (Residence Permit), `SSC` (Social Security Card), `HIC` (Health Insurance Card), `WP` (Work Permit), `TC` (Tax Card), `VISA`, `PSC` (Public Service Card), `BC` (Birth Certificate), `OTHER`. Note the response field `document_type` contains the display name, not the code.",
            "schema": {
              "type": "string"
            },
            "example": "P,ID"
          },
          {
            "name": "document_name",
            "in": "query",
            "required": false,
            "description": "Exact document names; multiple names can be passed comma-separated, but the value is only split on commas when it contains more than one ` - ` separator (a lone name with an embedded comma is matched whole). Names are as recognized by document verification (front or back side), e.g. `Spain - Id Card (2021)`. KYC rows only.",
            "schema": {
              "type": "string"
            },
            "example": "Spain - Id Card (2021)"
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Comma-separated document region/state values (for documents issued per region, such as US driver's licenses). KYC rows only.",
            "schema": {
              "type": "string"
            },
            "example": "CA,TX"
          },
          {
            "name": "didit_internal_id",
            "in": "query",
            "required": false,
            "description": "Filter by Didit's internal user identifier (the `didit_internal_id` response field) to list all sessions of one verified user. Must be a valid UUID; malformed values return `400`. KYC rows only.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "d9e78474-6c8d-4f2a-bb90-6f5c2f3a1147"
          },
          {
            "name": "session_type",
            "in": "query",
            "required": false,
            "description": "Comma-separated session creation channels: `API`, `HOSTED`, `MIGRATED`. The special value `ALL` (or omitting the parameter) disables the filter. KYC rows only.",
            "schema": {
              "type": "string"
            },
            "example": "HOSTED"
          },
          {
            "name": "api_service",
            "in": "query",
            "required": false,
            "description": "Filter standalone API sessions by service. Invalid values return `400`. KYC rows only.",
            "schema": {
              "type": "string",
              "enum": [
                "ID_VERIFICATION",
                "FACE_MATCH",
                "AGE_ESTIMATION",
                "FACE_SEARCH",
                "POA",
                "AML",
                "KYB_REGISTRY",
                "PASSIVE_LIVENESS",
                "DATABASE_VALIDATION",
                "PHONE_VERIFICATION",
                "EMAIL_VERIFICATION"
              ]
            },
            "example": "AML"
          },
          {
            "name": "screened_full_name",
            "in": "query",
            "required": false,
            "description": "Accent-insensitive name search inside AML and database-validation screened data. When combined with `api_service=AML` or `api_service=DATABASE_VALIDATION`, the search is restricted to that feature's screened data. KYC rows only.",
            "schema": {
              "type": "string"
            },
            "example": "Jane Doe"
          },
          {
            "name": "warning",
            "in": "query",
            "required": false,
            "description": "Comma-separated warning risk codes; returns sessions that raised any of them (e.g. `POSSIBLE_FRAUD`). Risk codes are listed per feature in the [warnings documentation](/integration/webhooks). Applies to KYC rows and, with business warning codes, to KYB rows.",
            "schema": {
              "type": "string"
            },
            "example": "POSSIBLE_FRAUD"
          },
          {
            "name": "status_initialized_as_in_review",
            "in": "query",
            "required": false,
            "description": "When `true`, only sessions whose decision initially landed in `In Review` (useful to audit manual-review volume). KYC rows only.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          },
          {
            "name": "is_kyc_to_be_reviewed",
            "in": "query",
            "required": false,
            "description": "`true` returns sessions whose document verification is flagged for manual review; `false` returns sessions with document verification explicitly not flagged. Omit to disable. KYC rows only.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          },
          {
            "name": "euuid",
            "in": "query",
            "required": false,
            "description": "Filter by the end user's euuid (UUID assigned to the verifying user, used by Console deep links). Must be a valid UUID; malformed values return a 400 field error. KYC rows only.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "0f8fad5b-d9cb-469f-a165-70867728950e"
          },
          {
            "name": "organization_name",
            "in": "query",
            "required": false,
            "description": "Comma-separated organization names. Console-oriented; with an API key (already scoped to one application) it only matches your own organization's name.",
            "schema": {
              "type": "string"
            },
            "example": "Acme Inc"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated session list. `results` items are KYC rows, KYB rows, or both depending on `session_kind`; discriminate with each row's `session_kind` field.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "count",
                    "next",
                    "previous",
                    "results"
                  ],
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of sessions matching the filters. Exact for KYC rows; for KYB rows it is capped at 100 (use `next` to know whether more pages exist). For `session_kind=all` it is the sum of both kinds.",
                      "example": 2
                    },
                    "next": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or `null` on the last page.",
                      "example": "https://verification.didit.me/v3/sessions/?limit=20&offset=20"
                    },
                    "previous": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or `null` on the first page.",
                      "example": null
                    },
                    "results": {
                      "type": "array",
                      "description": "Session rows, newest first. With `session_kind=all`, KYC rows come first, then KYB rows.",
                      "items": {
                        "oneOf": [
                          {
                            "title": "KYC session row (session_kind: user)",
                            "type": "object",
                            "description": "Summary row for a User Verification (KYC) session. Identity fields (`full_name`, `country`, `document_type`, `portrait_image`, contact fields) are populated progressively as the user completes verification steps, and are `null` until the relevant step finishes. Fields restricted by the workflow's response-attributes configuration are also returned as `null`.",
                            "required": [
                              "session_id",
                              "session_kind",
                              "session_number",
                              "session_url",
                              "portrait_image",
                              "document_type",
                              "full_name",
                              "country",
                              "status",
                              "vendor_data",
                              "didit_internal_id",
                              "created_at",
                              "features",
                              "phone_number",
                              "email_address",
                              "additional_details"
                            ],
                            "properties": {
                              "session_id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Unique identifier of the verification session. Use it with `GET /v3/session/{sessionId}/decision/` to fetch the full decision payload.",
                                "example": "5b3720ed-d429-42ef-b67f-37ea805f48ee"
                              },
                              "session_kind": {
                                "type": "string",
                                "enum": [
                                  "user"
                                ],
                                "description": "Row discriminator. Always `\"user\"` for KYC rows; Business Verification (KYB) rows have `\"business\"` and a different shape.",
                                "example": "user"
                              },
                              "session_number": {
                                "type": "integer",
                                "description": "Human-friendly sequential number of the session within your application. Also matched by the `search` parameter.",
                                "example": 720
                              },
                              "session_url": {
                                "type": "string",
                                "nullable": true,
                                "description": "Hosted verification URL the end user opens to complete the flow. `null` when the session has no hosted URL.",
                                "example": "https://verify.didit.me/session/CuXoBYCYVO5Y"
                              },
                              "portrait_image": {
                                "type": "string",
                                "nullable": true,
                                "description": "Expiring (presigned) URL of the best available portrait: the NFC chip photo when available, otherwise the ID document portrait, otherwise the liveness reference image. `null` until one of those exists. Download promptly; the link expires.",
                                "example": "https://<media-host>/portraits/5b3720ed.jpg?X-Amz-Expires=3600&X-Amz-Signature=..."
                              },
                              "document_type": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Passport",
                                  "Identity Card",
                                  "Driver's License",
                                  "Residence Permit",
                                  "Health Insurance Card",
                                  "Tax Card"
                                ],
                                "description": "Human-readable type of the verified ID document. `null` before document verification completes, and also `null` after completion when the verified code has no display mapping (`SSC`, `WP`, `VISA`, `PSC`, `BC`, `OTHER`). Note: the `document_type` query parameter filters by short codes (`P`, `ID`, `DL`, `RP`, ...), not by these display values.",
                                "example": "Passport"
                              },
                              "full_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Best available full name for the session, resolved in order: ID document OCR, AML screened data, database-validation screened data, proof-of-address document, then the expected details provided at session creation. `null` when none is available yet.",
                                "example": "Jane Marie Doe"
                              },
                              "country": {
                                "type": "string",
                                "nullable": true,
                                "description": "ISO 3166-1 alpha-3 country associated with the session, resolved in order: ID document issuing state, database-validation issuing state, proof-of-address issuing state, expected details, then the verified phone's country. May differ from nationality.",
                                "example": "ESP"
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "Not Started",
                                  "In Progress",
                                  "Approved",
                                  "Declined",
                                  "In Review",
                                  "Expired",
                                  "Abandoned",
                                  "Kyc Expired",
                                  "Resubmitted",
                                  "Awaiting User"
                                ],
                                "description": "Overall session status. See the [Verification Statuses](/integration/verification-statuses) page for the lifecycle.",
                                "example": "Approved"
                              },
                              "vendor_data": {
                                "type": "string",
                                "nullable": true,
                                "description": "Your own identifier for the end user, echoed back exactly as sent at session creation.",
                                "example": "your-user-id-123"
                              },
                              "didit_internal_id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true,
                                "description": "Didit's internal identifier for the verified user profile behind this session. Stable across multiple sessions of the same user; filterable via the `didit_internal_id` query parameter.",
                                "example": "d9e78474-6c8d-4f2a-bb90-6f5c2f3a1147"
                              },
                              "created_at": {
                                "type": "string",
                                "format": "date-time",
                                "description": "UTC timestamp when the session was created.",
                                "example": "2026-06-09T12:26:54.328364Z"
                              },
                              "features": {
                                "type": "array",
                                "description": "Per-feature status for every verification step configured in the session's workflow, in workflow order.",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "feature",
                                    "status"
                                  ],
                                  "properties": {
                                    "feature": {
                                      "type": "string",
                                      "enum": [
                                        "ID_VERIFICATION",
                                        "NFC",
                                        "LIVENESS",
                                        "FACE_MATCH",
                                        "POA",
                                        "QUESTIONNAIRE",
                                        "EMAIL_VERIFICATION",
                                        "PHONE",
                                        "AML",
                                        "IP_ANALYSIS",
                                        "AGE_ESTIMATION",
                                        "DATABASE_VALIDATION"
                                      ],
                                      "description": "Verification feature identifier.",
                                      "example": "ID_VERIFICATION"
                                    },
                                    "status": {
                                      "type": "string",
                                      "enum": [
                                        "Not Finished",
                                        "Approved",
                                        "Declined",
                                        "In Review",
                                        "Resub Requested"
                                      ],
                                      "description": "Status of this feature. `Not Finished` until the step completes.",
                                      "example": "Approved"
                                    }
                                  }
                                }
                              },
                              "phone_number": {
                                "type": "object",
                                "nullable": true,
                                "description": "Phone associated with the session: the verified phone when phone verification ran, otherwise the contact phone provided at session creation. `null` when neither exists.",
                                "required": [
                                  "number",
                                  "is_verified"
                                ],
                                "properties": {
                                  "number": {
                                    "type": "string",
                                    "description": "Phone number in E.164 format.",
                                    "example": "+14155552671"
                                  },
                                  "is_verified": {
                                    "type": "boolean",
                                    "description": "`true` only when the phone-verification feature approved this number.",
                                    "example": true
                                  }
                                }
                              },
                              "email_address": {
                                "type": "object",
                                "nullable": true,
                                "description": "Email associated with the session: the verified email when email verification ran, otherwise the contact email provided at session creation. `null` when neither exists.",
                                "required": [
                                  "email",
                                  "is_verified"
                                ],
                                "properties": {
                                  "email": {
                                    "type": "string",
                                    "format": "email",
                                    "example": "jane@example.com"
                                  },
                                  "is_verified": {
                                    "type": "boolean",
                                    "description": "`true` only when the email-verification feature approved this address.",
                                    "example": true
                                  }
                                }
                              },
                              "additional_details": {
                                "type": "object",
                                "nullable": true,
                                "description": "Compact per-feature extras. Only features that produced data appear as keys; `null` when no feature produced extras. Fields excluded by the workflow's response-attributes configuration are omitted.",
                                "properties": {
                                  "aml": {
                                    "type": "object",
                                    "description": "Present when AML screening ran.",
                                    "properties": {
                                      "total_hits": {
                                        "type": "integer",
                                        "description": "Number of AML screening hits.",
                                        "example": 0
                                      },
                                      "entity_type": {
                                        "type": "string",
                                        "description": "Screened entity type.",
                                        "example": "person"
                                      },
                                      "is_adverse_media_fetched": {
                                        "type": "boolean",
                                        "example": false
                                      },
                                      "screened_data": {
                                        "type": "object",
                                        "description": "Subset of the data that was screened. Only non-empty keys are included.",
                                        "properties": {
                                          "nationality": {
                                            "type": "string",
                                            "example": "ESP"
                                          },
                                          "document_number": {
                                            "type": "string",
                                            "example": "XX1234567"
                                          },
                                          "date_of_birth": {
                                            "type": "string",
                                            "example": "1990-05-21"
                                          }
                                        }
                                      }
                                    }
                                  },
                                  "database_validation": {
                                    "type": "object",
                                    "description": "Present when database validation ran.",
                                    "properties": {
                                      "validation_type": {
                                        "type": "string",
                                        "example": "DOCUMENT_VALIDATION"
                                      },
                                      "match_type": {
                                        "type": "string",
                                        "example": "FULL_MATCH"
                                      },
                                      "identification_number": {
                                        "type": "string",
                                        "description": "Tax, personal, or document number that was validated (first available).",
                                        "example": "12345678Z"
                                      }
                                    }
                                  },
                                  "poa": {
                                    "type": "object",
                                    "description": "Present when proof of address ran.",
                                    "properties": {
                                      "document_type": {
                                        "type": "string",
                                        "example": "UTILITY_BILL"
                                      },
                                      "issuer": {
                                        "type": "string",
                                        "example": "Energy Co"
                                      },
                                      "address": {
                                        "type": "string",
                                        "example": "Calle Mayor 1, 28013 Madrid"
                                      },
                                      "name_on_document": {
                                        "type": "string",
                                        "example": "Jane Marie Doe"
                                      }
                                    }
                                  },
                                  "liveness": {
                                    "type": "object",
                                    "description": "Present when a liveness check ran.",
                                    "properties": {
                                      "method": {
                                        "type": "string",
                                        "example": "PASSIVE"
                                      },
                                      "score": {
                                        "type": "number",
                                        "description": "Liveness confidence score, rounded to 2 decimals.",
                                        "example": 0.98
                                      }
                                    }
                                  },
                                  "face_match": {
                                    "type": "object",
                                    "description": "Present when face match ran.",
                                    "properties": {
                                      "score": {
                                        "type": "number",
                                        "description": "Face-match similarity score, rounded to 2 decimals.",
                                        "example": 0.95
                                      },
                                      "source_image": {
                                        "type": "string",
                                        "description": "Expiring (presigned) URL of the source face image.",
                                        "example": "https://<media-host>/faces/source.jpg?X-Amz-Expires=3600&..."
                                      },
                                      "target_image": {
                                        "type": "string",
                                        "description": "Expiring (presigned) URL of the target face image.",
                                        "example": "https://<media-host>/faces/target.jpg?X-Amz-Expires=3600&..."
                                      }
                                    }
                                  },
                                  "phone_verification": {
                                    "type": "object",
                                    "description": "Present when phone verification ran.",
                                    "properties": {
                                      "country_code": {
                                        "type": "string",
                                        "description": "ISO 3166-1 alpha-2 country of the phone number.",
                                        "example": "US"
                                      },
                                      "is_temporary": {
                                        "type": "boolean",
                                        "example": false
                                      },
                                      "is_ported": {
                                        "type": "boolean",
                                        "example": false
                                      },
                                      "is_blocked": {
                                        "type": "boolean",
                                        "example": false
                                      }
                                    }
                                  },
                                  "email_verification": {
                                    "type": "object",
                                    "description": "Present when email verification ran.",
                                    "properties": {
                                      "is_breached": {
                                        "type": "boolean",
                                        "example": false
                                      },
                                      "is_disposable": {
                                        "type": "boolean",
                                        "example": false
                                      },
                                      "is_undeliverable": {
                                        "type": "boolean",
                                        "example": false
                                      },
                                      "is_blocklisted": {
                                        "type": "boolean",
                                        "example": false
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          },
                          {
                            "title": "KYB session row (session_kind: business)",
                            "type": "object",
                            "description": "Summary row for a Business Verification (KYB) session. Returned only when `session_kind` is `business` or `all`.",
                            "required": [
                              "session_id",
                              "session_kind",
                              "session_number",
                              "status",
                              "vendor_data",
                              "created_at",
                              "workflow_id",
                              "workflow_type",
                              "workflow_label",
                              "company_name",
                              "registration_number",
                              "country"
                            ],
                            "properties": {
                              "session_id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Unique identifier of the business verification session.",
                                "example": "8a1f63c2-1b9e-4f3a-9c41-2f6a1f0b7d52"
                              },
                              "session_kind": {
                                "type": "string",
                                "enum": [
                                  "business"
                                ],
                                "description": "Row discriminator. Always `\"business\"` for KYB rows.",
                                "example": "business"
                              },
                              "session_number": {
                                "type": "integer",
                                "description": "Human-friendly sequential number of the business session within your application. Numbered independently from KYC sessions.",
                                "example": 42
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "Not Started",
                                  "In Progress",
                                  "Approved",
                                  "Declined",
                                  "In Review",
                                  "Expired",
                                  "Abandoned",
                                  "Kyc Expired",
                                  "Resubmitted",
                                  "Awaiting User"
                                ],
                                "description": "Overall session status. See the [Verification Statuses](/integration/verification-statuses) page.",
                                "example": "Approved"
                              },
                              "vendor_data": {
                                "type": "string",
                                "nullable": true,
                                "description": "Your own identifier for the business, echoed back exactly as sent at session creation.",
                                "example": "your-company-id-77"
                              },
                              "created_at": {
                                "type": "string",
                                "format": "date-time",
                                "description": "UTC timestamp when the session was created.",
                                "example": "2026-06-08T09:14:02.118450Z"
                              },
                              "workflow_id": {
                                "type": "string",
                                "format": "uuid",
                                "nullable": true,
                                "description": "Identifier of the workflow this session was created with.",
                                "example": "9f9b1234-aaaa-bbbb-cccc-1234567890ab"
                              },
                              "workflow_type": {
                                "type": "string",
                                "nullable": true,
                                "description": "Workflow type. `kyb` for business workflows.",
                                "example": "kyb"
                              },
                              "workflow_label": {
                                "type": "string",
                                "nullable": true,
                                "description": "Display name of the workflow.",
                                "example": "Standard KYB"
                              },
                              "company_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Name of the company being verified, from the registry company linked to the session. `null` until a company is selected.",
                                "example": "Acme Holdings S.L."
                              },
                              "registration_number": {
                                "type": "string",
                                "nullable": true,
                                "description": "Company registration number from the registry company linked to the session.",
                                "example": "B12345678"
                              },
                              "country": {
                                "type": "string",
                                "nullable": true,
                                "description": "Country code of the registry company linked to the session.",
                                "example": "ES"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                },
                "examples": {
                  "KYC sessions (default)": {
                    "summary": "session_kind=user - one completed and one not-started session",
                    "value": {
                      "count": 2,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "session_id": "5b3720ed-d429-42ef-b67f-37ea805f48ee",
                          "session_kind": "user",
                          "session_number": 720,
                          "session_url": "https://verify.didit.me/session/CuXoBYCYVO5Y",
                          "portrait_image": "https://<media-host>/portraits/5b3720ed.jpg?X-Amz-Expires=3600&X-Amz-Signature=...",
                          "document_type": "Passport",
                          "full_name": "Jane Marie Doe",
                          "country": "ESP",
                          "status": "Approved",
                          "vendor_data": "your-user-id-123",
                          "didit_internal_id": "d9e78474-6c8d-4f2a-bb90-6f5c2f3a1147",
                          "created_at": "2026-06-09T12:26:54.328364Z",
                          "features": [
                            {
                              "feature": "ID_VERIFICATION",
                              "status": "Approved"
                            },
                            {
                              "feature": "LIVENESS",
                              "status": "Approved"
                            },
                            {
                              "feature": "FACE_MATCH",
                              "status": "Approved"
                            },
                            {
                              "feature": "AML",
                              "status": "Approved"
                            },
                            {
                              "feature": "IP_ANALYSIS",
                              "status": "Approved"
                            }
                          ],
                          "phone_number": {
                            "number": "+14155552671",
                            "is_verified": true
                          },
                          "email_address": {
                            "email": "jane@example.com",
                            "is_verified": true
                          },
                          "additional_details": {
                            "aml": {
                              "total_hits": 0,
                              "entity_type": "person",
                              "is_adverse_media_fetched": false
                            },
                            "liveness": {
                              "method": "PASSIVE",
                              "score": 0.98
                            },
                            "face_match": {
                              "score": 0.95
                            }
                          }
                        },
                        {
                          "session_id": "038ad62f-5ebd-46c2-afe9-4b2956bf687f",
                          "session_kind": "user",
                          "session_number": 719,
                          "session_url": "https://verify.didit.me/session/7RGKiO6ioGH6",
                          "portrait_image": null,
                          "document_type": null,
                          "full_name": null,
                          "country": null,
                          "status": "Not Started",
                          "vendor_data": "your-user-id-124",
                          "didit_internal_id": "eb4e679d-ca4b-461f-9685-687bac29ebdb",
                          "created_at": "2026-06-09T08:02:23.343053Z",
                          "features": [
                            {
                              "feature": "ID_VERIFICATION",
                              "status": "Not Finished"
                            },
                            {
                              "feature": "LIVENESS",
                              "status": "Not Finished"
                            },
                            {
                              "feature": "FACE_MATCH",
                              "status": "Not Finished"
                            },
                            {
                              "feature": "AML",
                              "status": "Not Finished"
                            },
                            {
                              "feature": "IP_ANALYSIS",
                              "status": "Not Finished"
                            }
                          ],
                          "phone_number": null,
                          "email_address": null,
                          "additional_details": null
                        }
                      ]
                    }
                  },
                  "Mixed KYC + KYB (session_kind=all)": {
                    "summary": "session_kind=all - KYC row followed by a KYB row",
                    "value": {
                      "count": 2,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "session_id": "5b3720ed-d429-42ef-b67f-37ea805f48ee",
                          "session_kind": "user",
                          "session_number": 720,
                          "session_url": "https://verify.didit.me/session/CuXoBYCYVO5Y",
                          "portrait_image": null,
                          "document_type": "Identity Card",
                          "full_name": "Jane Marie Doe",
                          "country": "ESP",
                          "status": "In Review",
                          "vendor_data": "your-user-id-123",
                          "didit_internal_id": "d9e78474-6c8d-4f2a-bb90-6f5c2f3a1147",
                          "created_at": "2026-06-09T12:26:54.328364Z",
                          "features": [
                            {
                              "feature": "ID_VERIFICATION",
                              "status": "In Review"
                            },
                            {
                              "feature": "LIVENESS",
                              "status": "Approved"
                            }
                          ],
                          "phone_number": null,
                          "email_address": null,
                          "additional_details": {
                            "liveness": {
                              "method": "PASSIVE",
                              "score": 0.98
                            }
                          }
                        },
                        {
                          "session_id": "8a1f63c2-1b9e-4f3a-9c41-2f6a1f0b7d52",
                          "session_kind": "business",
                          "session_number": 42,
                          "status": "Approved",
                          "vendor_data": "your-company-id-77",
                          "created_at": "2026-06-08T09:14:02.118450Z",
                          "workflow_id": "9f9b1234-aaaa-bbbb-cccc-1234567890ab",
                          "workflow_type": "kyb",
                          "workflow_label": "Standard KYB",
                          "company_name": "Acme Holdings S.L.",
                          "registration_number": "B12345678",
                          "country": "ES"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "301": {
            "description": "Redirect to the canonical trailing-slash URL. Returned when the request path is `/v3/sessions` (no trailing slash); the `Location` header points to `/v3/sessions/` with the query string preserved. GET clients typically follow it automatically."
          },
          "400": {
            "description": "Invalid query parameter. The body is an object keyed by the offending parameter.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid session_kind": {
                    "summary": "session_kind not one of user/business/all",
                    "value": {
                      "session_kind": "Must be \"user\", \"business\", or \"all\"."
                    }
                  },
                  "Invalid date": {
                    "summary": "Malformed date_from/date_to",
                    "value": {
                      "date_from": [
                        "Enter a valid date."
                      ]
                    }
                  },
                  "Invalid didit_internal_id": {
                    "summary": "didit_internal_id is not a UUID",
                    "value": {
                      "didit_internal_id": [
                        "Enter a valid UUID."
                      ]
                    }
                  },
                  "Invalid api_service": {
                    "summary": "api_service not in the allowed choices",
                    "value": {
                      "api_service": [
                        "Select a valid choice. FOO is not one of the available choices."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, malformed, or revoked API key. This API never returns `401`; all authentication failures are `403`.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -s 'https://verification.didit.me/v3/sessions/?status=Approved,In%20Review&date_from=2026-06-01&limit=20' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://verification.didit.me/v3/sessions/\"\nheaders = {\"x-api-key\": \"YOUR_API_KEY\"}\nparams = {\n    \"session_kind\": \"user\",          # \"user\" (default) | \"business\" | \"all\"\n    \"status\": \"Approved,In Review\",  # comma-separated, OR within the list\n    \"date_from\": \"2026-06-01\",\n    \"limit\": 20,\n}\n\nwhile url:\n    response = requests.get(url, headers=headers, params=params)\n    response.raise_for_status()\n    page = response.json()\n    for session in page[\"results\"]:\n        print(session[\"session_kind\"], session[\"session_id\"], session[\"status\"])\n    url, params = page[\"next\"], None  # \"next\" already carries the query string"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const params = new URLSearchParams({\n  session_kind: 'all',\n  status: 'Approved,In Review',\n  date_from: '2026-06-01',\n  limit: '20',\n});\n\nconst response = await fetch(\n  `https://verification.didit.me/v3/sessions/?${params}`,\n  { headers: { 'x-api-key': process.env.DIDIT_API_KEY } },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\n\nconst { count, next, results } = await response.json();\nfor (const session of results) {\n  // session.session_kind is \"user\" (KYC) or \"business\" (KYB)\n  console.log(session.session_kind, session.session_id, session.status);\n}"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/share/": {
      "post": {
        "summary": "Mint a share token for a finished verification session",
        "description": "Mint a short-lived JWT that lets a specific Didit application import this finished session. Pair with `POST /v3/session/import-shared/`.",
        "operationId": "post_v3_session_share",
        "tags": [
          "Sessions"
        ],
        "responses": {
          "200": {
            "description": "Share token minted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "share_token": {
                      "type": "string",
                      "description": "HS256-signed JWT. Pass this verbatim as `share_token` to [`POST /v3/session/import-shared/`](/sessions-api/import-shared-session) on the target application.",
                      "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
                    },
                    "for_application_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Echoes the target application UUID that the token is bound to.",
                      "example": "a5f3bca2-46e2-411e-90ef-a580900a57ee"
                    },
                    "session_kind": {
                      "type": "string",
                      "enum": [
                        "user",
                        "business"
                      ],
                      "description": "Whether the source session is a User Verification (KYC) or Business Verification (KYB) session."
                    }
                  }
                },
                "examples": {
                  "User session": {
                    "summary": "Share a KYC session",
                    "value": {
                      "share_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uX2lkIjoiMjBiYjNjM2ItNjE0Ni00MzlmLTg0YTQtYmQzMGQwMGFjNmEyIiwiZnJvbV9hcHBsaWNhdGlvbl9pZCI6ImRiZDIwZTM0LTQyZTktNGYyYy1iYTkxLWNmMDc2MjAxNmY2NCIsImZvcl9hcHBsaWNhdGlvbl9pZCI6ImE1ZjNiY2EyLTQ2ZTItNDExZS05MGVmLWE1ODA5MDBhNTdlZSIsImlhdCI6MTc1MzYzMDY2NiwiZXhwIjoxNzUzNjM0MjY2fQ.JJ9pNE_hqZsOtbR0XYZIWw4JzidjdEl279iUrsIkhGE",
                      "for_application_id": "a5f3bca2-46e2-411e-90ef-a580900a57ee",
                      "session_kind": "user"
                    }
                  },
                  "Business session": {
                    "summary": "Share a KYB session",
                    "value": {
                      "share_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                      "for_application_id": "a5f3bca2-46e2-411e-90ef-a580900a57ee",
                      "session_kind": "business"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid credentials. Unlike most v3 endpoints, this endpoint authenticates through the permission decorator and returns `401` when no valid token/key is presented.",
            "content": {
              "application/json": {
                "examples": {
                  "Unauthorized": {
                    "summary": "Unauthorized",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No session with the given `session_id` exists in your application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not Found": {
                    "summary": "Session not found",
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field errors are keyed by field name; the not-finished error arrives under a `detail` key (as an array).",
            "content": {
              "application/json": {
                "examples": {
                  "Wrong status": {
                    "summary": "Source session is not finished",
                    "value": {
                      "detail": [
                        "Only finished sessions (\"Approved\", \"Declined\", \"In Review\") can be shared."
                      ]
                    }
                  },
                  "Target missing": {
                    "summary": "Target application does not exist",
                    "value": {
                      "for_application_id": [
                        "Target application does not exist."
                      ]
                    }
                  },
                  "Self-share": {
                    "summary": "Target is the calling application",
                    "value": {
                      "for_application_id": [
                        "Cannot share a session with the same application."
                      ]
                    }
                  },
                  "TTL bounds": {
                    "summary": "ttl_in_seconds outside bounds",
                    "value": {
                      "ttl_in_seconds": [
                        "Ensure this value is greater than or equal to 60."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The credentials are valid but lack the `write:sessions` permission for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "No Permission": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    },
                    "summary": "No Permission"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the source verification session to mint a token for.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          }
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "for_application_id"
                ],
                "properties": {
                  "for_application_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "UUID of the Didit application that will redeem the token. Must exist, must not be deleted, and must differ from the calling application. Find it in the Business Console under **Settings → Application**.",
                    "example": "a5f3bca2-46e2-411e-90ef-a580900a57ee"
                  },
                  "ttl_in_seconds": {
                    "type": "integer",
                    "description": "Token lifetime, in seconds. Minimum `60`, maximum `86400` (24 h). Defaults to `3600` (1 h).",
                    "minimum": 60,
                    "maximum": 86400,
                    "default": 3600,
                    "example": 3600
                  }
                }
              },
              "example": {
                "for_application_id": "a5f3bca2-46e2-411e-90ef-a580900a57ee",
                "ttl_in_seconds": 7200
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/share/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"for_application_id\": \"a5f3bca2-46e2-411e-90ef-a580900a57ee\",\n    \"ttl_in_seconds\": 7200\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/share/\",\n    headers={\n        'x-api-key': 'YOUR_API_KEY',\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"for_application_id\": \"a5f3bca2-46e2-411e-90ef-a580900a57ee\",\n        \"ttl_in_seconds\": 7200,\n    },\n)\nresponse.raise_for_status()\nshare_token = response.json()[\"share_token\"]"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/share/',\n  {\n    method: 'POST',\n    headers: {\n      'x-api-key': 'YOUR_API_KEY',\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      for_application_id: 'a5f3bca2-46e2-411e-90ef-a580900a57ee',\n      ttl_in_seconds: 7200,\n    }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst { share_token } = await response.json();"
          }
        ]
      }
    },
    "/v3/session/import-shared/": {
      "post": {
        "summary": "Redeem a share token to clone a verification session into your application",
        "description": "Redeem a share token to clone a KYC or KYB session into the calling application with a fresh `session_id`. Not idempotent — a token redeems once per receiver.",
        "operationId": "post_v3_session_import_shared",
        "tags": [
          "Sessions"
        ],
        "responses": {
          "201": {
            "description": "Session cloned. The body is the V3 decision payload for both kinds, discriminated by `session_kind`: `\"user\"` (KYC) with list-based feature blocks such as `id_verifications`, `liveness_checks`, `aml_screenings`; `\"business\"` (KYB) with blocks like `registry_checks` and `key_people_checks`. Both include `shared_from_session` — the `session_id` of the original session in the source application. With `trust_review: false` the cloned session's `status` is forced to `In Review`.",
            "content": {
              "application/json": {
                "examples": {
                  "User session imported": {
                    "summary": "Cloned KYC session (truncated — full V3 decision payload in reality)",
                    "value": {
                      "session_id": "11111111-2222-3333-4444-555555555555",
                      "session_kind": "user",
                      "shared_from_session": "99999999-8888-7777-6666-555555555555",
                      "session_number": 43762,
                      "session_url": null,
                      "status": "In Review",
                      "workflow_id": "9f9b1234-aaaa-bbbb-cccc-1234567890ab",
                      "vendor_data": "user-1",
                      "created_at": "2026-05-17T08:42:11Z",
                      "expires_at": "2026-05-24T08:42:11Z"
                    }
                  },
                  "Business session imported": {
                    "summary": "Cloned KYB session (truncated — full V3 KYB decision payload in reality)",
                    "value": {
                      "session_id": "22222222-3333-4444-5555-666666666666",
                      "session_kind": "business",
                      "shared_from_session": "88888888-7777-6666-5555-444444444444",
                      "session_number": 982,
                      "session_url": null,
                      "status": "Approved",
                      "workflow_id": "9f9b1234-aaaa-bbbb-cccc-1234567890ab",
                      "vendor_data": "company-1"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error (token invalid, expired, wrong target, or references a session that no longer exists).",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Share Token": {
                    "summary": "Invalid JWT",
                    "value": {
                      "share_token": [
                        "Invalid share token."
                      ]
                    }
                  },
                  "Expired Share Token": {
                    "summary": "Token past `exp`",
                    "value": {
                      "share_token": [
                        "Share token has expired."
                      ]
                    }
                  },
                  "Wrong audience": {
                    "summary": "Token not bound to this application",
                    "value": {
                      "share_token": [
                        "This token is not valid for this application."
                      ]
                    }
                  },
                  "Original missing": {
                    "summary": "Source session was deleted",
                    "value": {
                      "share_token": [
                        "Original session does not exist."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid API key (this endpoint returns `403`, never `401`, for authentication failures), or this source session has already been imported into the calling application (one redeem per receiver).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "summary": "Forbidden",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Already imported": {
                    "summary": "Source already imported once",
                    "value": {
                      "detail": "This session has already been shared with your application."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`workflow_id` does not belong to the calling application.",
            "content": {
              "application/json": {
                "examples": {
                  "Workflow not found": {
                    "summary": "Workflow unknown",
                    "value": {
                      "detail": "Workflow does not exist for this application."
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "share_token",
                  "trust_review",
                  "workflow_id"
                ],
                "properties": {
                  "share_token": {
                    "type": "string",
                    "description": "JWT share token issued by [`POST /v3/session/{sessionId}/share/`](/sessions-api/share-session).",
                    "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
                  },
                  "trust_review": {
                    "type": "boolean",
                    "description": "If `true`, the cloned session keeps the source's final `status`. If `false`, it is forced into `In Review`.",
                    "example": false
                  },
                  "workflow_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "UUID of a workflow in the calling application. Cross-application IDs are rejected with `404`.",
                    "example": "9f9b1234-aaaa-bbbb-cccc-1234567890ab"
                  },
                  "vendor_data": {
                    "type": "string",
                    "nullable": true,
                    "description": "Optional override for the cloned session's `vendor_data`.",
                    "example": "user-1"
                  }
                }
              },
              "example": {
                "share_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                "trust_review": false,
                "workflow_id": "9f9b1234-aaaa-bbbb-cccc-1234567890ab",
                "vendor_data": "user-1"
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST \\\n  https://verification.didit.me/v3/session/import-shared/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"share_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n    \"trust_review\": false,\n    \"workflow_id\": \"9f9b1234-aaaa-bbbb-cccc-1234567890ab\",\n    \"vendor_data\": \"user-1\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/session/import-shared/\",\n    headers={\n        'x-api-key': 'YOUR_API_KEY',\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"share_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",\n        \"trust_review\": False,\n        \"workflow_id\": \"9f9b1234-aaaa-bbbb-cccc-1234567890ab\",\n        \"vendor_data\": \"user-1\",\n    },\n)\nresponse.raise_for_status()\nimported = response.json()"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/import-shared/',\n  {\n    method: 'POST',\n    headers: {\n      'x-api-key': 'YOUR_API_KEY',\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      share_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',\n      trust_review: false,\n      workflow_id: '9f9b1234-aaaa-bbbb-cccc-1234567890ab',\n      vendor_data: 'user-1',\n    }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst imported = await response.json();"
          }
        ]
      }
    },
    "/v3/kyb/search/": {
      "post": {
        "summary": "KYB registry company search (standalone)",
        "operationId": "post_v3_kyb_search",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [],
        "description": "Search official company registries for candidate companies by name and/or registration number. This is step 1 of the two-step registry flow: **search** returns lightweight candidates, then `POST /v3/kyb/select/` retrieves the full profile of one candidate.\n\n**Search billing.** Successful searches using a paid company-data source cost USD 0.50 per request, regardless of candidate count. Empty results, failures and results served only by other sources are not charged. The applicable price is reserved before searching; insufficient balance returns 403 with code `insufficient_credits`. Contract rates apply where agreed, and an unconfigured contract search rate returns 403. Sandbox searches are free. Repeating a successful search can incur another charge; callback delivery does not add a charge. Profile retrieval is billed separately. This search fee also applies to v2. Candidates always come back with `fetch_status: \"pending\"`: the full company data is only fetched (and billed) on select.\n\n**`kyb_response_id` is ephemeral.** It is a per-search handle, not a stable company id. Select promptly after searching and re-search to get a fresh handle instead of storing it.\n\n**Two modes.**\n- *Synchronous (default):* the API polls the registry until the search resolves and returns the final candidate list (`search_resolved: true`).\n- *Asynchronous:* pass `webhook_url` and the API returns immediately — usually with `search_status: \"pending\"` and an empty candidate list — then POSTs a `kyb.registry_search.resolved` callback to your URL when the registry finishes. The callback body is `{\"event_id\", \"event_type\": \"kyb.registry_search.resolved\", \"request_id\", \"vendor_data\", \"metadata\", \"search_status\", \"search_resolved\", \"kyb_registry\", \"timestamp\", \"created_at\"}` — note `timestamp` and `created_at` in the callback are epoch integers, unlike this endpoint's ISO `created_at` — and is sent **unsigned** (header `X-Didit-Unsigned-Callback: true`, no `X-Signature`).\n\n**Country codes.** ISO 3166-1 alpha-2 (`GB`, `DE`), plus `XX-YY` subdivision codes where registries are regional — e.g. `US-CA` for California.\n\n**Sandbox.** Keys from sandbox applications return one static candidate without contacting any registry.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "country_code"
                ],
                "properties": {
                  "country_code": {
                    "type": "string",
                    "maxLength": 10,
                    "description": "ISO 3166-1 alpha-2 code of the country whose company registry to search. For example, `GB`. Where company registries operate at state or province level, append the ISO 3166-2 subdivision code as `XX-YY`: `US-CA` searches the California registry. United States searches always require the subdivision — a bare `US` is rejected. Case-insensitive; normalized to upper case.",
                    "example": "GB"
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Company name to search for. Either `name` or `registration_number` is required.",
                    "example": "Tesco"
                  },
                  "registration_number": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Registry registration number to search for. Either `name` or `registration_number` is required."
                  },
                  "search_type": {
                    "type": "string",
                    "enum": [
                      "contains",
                      "start_with",
                      "fuzzy"
                    ],
                    "default": "contains",
                    "description": "Name-matching strategy applied by the registry search."
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for this lookup; echoed back and included in the webhook callback."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON; echoed back and included in the webhook callback."
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 500,
                    "description": "Switches the search to asynchronous mode: the API returns immediately and POSTs an unsigned `kyb.registry_search.resolved` callback to this URL when the candidate list is ready."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/kyb/search/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"country_code\": \"GB\",\n    \"name\": \"Tesco\",\n    \"search_type\": \"contains\",\n    \"vendor_data\": \"company-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/kyb/search/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"country_code\": \"GB\", \"name\": \"Tesco\"},\n    timeout=60,  # synchronous mode waits for the registry to resolve\n)\nresp.raise_for_status()\ncandidates = resp.json()[\"kyb_registry\"][\"companies\"]\nkyb_response_id = candidates[0][\"kyb_response_id\"]  # pass to /v3/kyb/select/"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/kyb/search/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ country_code: 'GB', name: 'Tesco' }),\n});\nconst data = await res.json();\nconst kybResponseId = data.kyb_registry.companies[0].kyb_response_id;"
          }
        ],
        "responses": {
          "200": {
            "description": "Search accepted. Synchronous mode returns the resolved candidate list; webhook mode returns immediately (often `search_status: \"pending\"`) and delivers the final list via the `kyb.registry_search.resolved` callback.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "With `webhook_url`: the persisted search-request id, echoed as `request_id` in the `kyb.registry_search.resolved` callback. Without `webhook_url`: a transient correlation UUID (the search is not stored)."
                    },
                    "kyb_registry": {
                      "type": "object",
                      "properties": {
                        "companies": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "kyb_response_id": {
                                "type": "string",
                                "nullable": true,
                                "description": "Handle for this candidate — pass it to `POST /v3/kyb/select/` to retrieve the full profile. Ephemeral and scoped to this search: do not store it long-term; re-search to get a fresh one.",
                                "example": "69aeeb95febb0f1704042259"
                              },
                              "name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Registered company name.",
                                "example": "Tesco PLC"
                              },
                              "registration_number": {
                                "type": "string",
                                "nullable": true,
                                "description": "Registry registration number.",
                                "example": "00445790"
                              },
                              "status": {
                                "type": "string",
                                "nullable": true,
                                "description": "Normalized registry status of the company (e.g. `active`, `dissolved`, `inactive`, `struck off`).",
                                "example": "active"
                              },
                              "type": {
                                "type": "string",
                                "nullable": true,
                                "description": "Legal form as reported by the registry.",
                                "example": "Public Limited Company"
                              },
                              "risk_level": {
                                "type": "string",
                                "nullable": true,
                                "description": "Registry-reported risk level, when available. Usually `null` at search time."
                              },
                              "fetch_status": {
                                "type": "string",
                                "nullable": true,
                                "description": "Always `pending` for search candidates — the full company profile is only fetched (and billed) when you select the candidate.",
                                "example": "pending"
                              }
                            }
                          },
                          "description": "Deduplicated candidate list. Empty while `search_resolved=false` (webhook mode) or when nothing matched."
                        },
                        "pagination": {
                          "type": "object",
                          "properties": {
                            "total": {
                              "type": "integer",
                              "description": "Number of candidates returned."
                            },
                            "page": {
                              "type": "integer"
                            },
                            "per_page": {
                              "type": "integer",
                              "example": 25
                            }
                          }
                        },
                        "search_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "pending",
                            "resolved"
                          ],
                          "description": "Registry search lifecycle status."
                        },
                        "search_resolved": {
                          "type": "boolean",
                          "description": "`true` once the candidate list is final."
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "description": "Echo of the `metadata` you sent."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "examples": {
                  "Resolved search": {
                    "summary": "Synchronous mode — final candidate list",
                    "value": {
                      "request_id": "0c7e9a40-3a13-4f7e-8a44-9d2e2f1c5b6a",
                      "kyb_registry": {
                        "companies": [
                          {
                            "kyb_response_id": "69aeeb95febb0f1704042259",
                            "name": "Tesco PLC",
                            "registration_number": "00445790",
                            "status": "active",
                            "type": "Public Limited Company",
                            "risk_level": null,
                            "fetch_status": "pending"
                          },
                          {
                            "kyb_response_id": "69aeeb95febb0f170404225a",
                            "name": "E-TESCO LTD",
                            "registration_number": "15168476",
                            "status": "active",
                            "type": "Private Limited Company",
                            "risk_level": null,
                            "fetch_status": "pending"
                          }
                        ],
                        "pagination": {
                          "total": 2,
                          "page": 1,
                          "per_page": 25
                        },
                        "search_status": "resolved",
                        "search_resolved": true
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:40:00.000000+00:00"
                    }
                  },
                  "Pending search (webhook mode)": {
                    "summary": "`webhook_url` provided — candidates arrive via the kyb.registry_search.resolved callback",
                    "value": {
                      "request_id": "5f2d8c1b-7e4a-4b9c-9f0d-3a6e8c2b1d4f",
                      "kyb_registry": {
                        "companies": [],
                        "pagination": {
                          "total": 0,
                          "page": 1,
                          "per_page": 25
                        },
                        "search_status": "pending",
                        "search_resolved": false
                      },
                      "vendor_data": "company-1234",
                      "metadata": {
                        "source": "onboarding"
                      },
                      "created_at": "2026-06-11T10:41:00.000000+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field-level problems use DRF's standard envelope; the name/registration-number rule reports under `non_field_errors`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing search criteria": {
                    "summary": "Neither `name` nor `registration_number` provided",
                    "value": {
                      "non_field_errors": [
                        "Either 'name' or 'registration_number' is required."
                      ]
                    }
                  },
                  "Invalid country_code": {
                    "summary": "Must be `XX` (alpha-2) or `XX-YY` subdivision",
                    "value": {
                      "country_code": [
                        "country_code must be a 2-letter ISO code."
                      ]
                    }
                  },
                  "Invalid search_type": {
                    "summary": "Only contains / start_with / fuzzy",
                    "value": {
                      "search_type": [
                        "\"exact\" is not a valid choice."
                      ]
                    }
                  },
                  "Invalid webhook_url": {
                    "summary": "`webhook_url` must be a valid URL",
                    "value": {
                      "webhook_url": [
                        "Enter a valid URL."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Also returned before searching when the applicable search fee cannot be covered (`code: \"insufficient_credits\"`), or when a contract search rate is missing.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "The KYB registry provider is temporarily unavailable - a 5xx response, timeout, or connection failure from the upstream registry. The search is not billed. Retry later, or, in Didit's hosted verification flow, the user is automatically offered manual company entry instead of a retry-only error.",
            "content": {
              "application/json": {
                "examples": {
                  "Registry provider outage": {
                    "summary": "The registry provider did not answer the search",
                    "value": {
                      "detail": "The KYB registry provider is temporarily unavailable. Please try again shortly.",
                      "code": "kyb_registry_provider_unavailable"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/kyb/select/": {
      "post": {
        "summary": "KYB registry company select — Lite tier (standalone)",
        "operationId": "post_v3_kyb_select",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [],
        "description": "Retrieve the **Lite** registry profile of one candidate returned by `POST /v3/kyb/search/` — company details, registered address, identifiers, status, activity and the officers, plus the raw registry payload. Shareholders and ultimate beneficial owners are sold by `POST /v3/kyb/shareholders/` and `POST /v3/kyb/ubo/`.\n\n**Pairing with search.** Pass the candidate's `kyb_response_id` exactly as returned by a search of the same application. The handle is ephemeral and scoped to that search — select promptly, and re-search for a fresh handle rather than storing it.\n\n**Billing.** Each select is billed at the country's Lite price (any search fee is separate); see [KYB registry pricing](/getting-started/kyb-registry-pricing). The balance is checked before any registry call (`403` when short) and the charge is recorded against the created business session.\n\n**Persistence is mandatory.** Every select creates a business session (its id is the `request_id`) so billing and retrieval can be tracked; it appears in the console. `save_api_request` is accepted for symmetry but must be `true` (the default) — sending `false` returns `400`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kyb_response_id"
                ],
                "properties": {
                  "kyb_response_id": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Candidate handle from `POST /v3/kyb/search/` (`kyb_registry.companies[].kyb_response_id`). Ephemeral — use it shortly after the search that produced it.",
                    "example": "69aeeb95febb0f1704042259"
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for this company; echoed back and stored with the business session."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON stored with the business session and echoed back."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "Must be `true` (the default). KYB registry selects are always persisted so billing and retrieval can be tracked; `false` returns `400`."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/kyb/select/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n    \"vendor_data\": \"company-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nsearch = requests.post(\n    \"https://verification.didit.me/v3/kyb/search/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"country_code\": \"GB\", \"name\": \"Tesco\"},\n    timeout=60,\n).json()\nkyb_response_id = search[\"kyb_registry\"][\"companies\"][0][\"kyb_response_id\"]\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/kyb/select/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"kyb_response_id\": kyb_response_id, \"vendor_data\": \"company-1234\"},\n    timeout=90,  # waits for the registry to resolve the full profile\n)\nresp.raise_for_status()\ncompany = resp.json()[\"kyb_registry\"]\nprint(company[\"company_name\"], company[\"registry_status\"], company[\"status\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/kyb/select/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    kyb_response_id: '69aeeb95febb0f1704042259',\n    vendor_data: 'company-1234',\n  }),\n});\nconst data = await res.json();\nconsole.log(data.kyb_registry.company_name, data.kyb_registry.registry_status);"
          }
        ],
        "responses": {
          "200": {
            "description": "Company retrieved and billed. `kyb_registry` carries the full profile; check `data_resolved` — when `false` the registry was still processing and the stored record completes automatically once it resolves.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Id of the business session created for this retrieval. The stored record (visible in the console) keeps updating if the registry resolves after the response."
                    },
                    "registry_tier_requested": {
                      "type": "string",
                      "enum": [
                        "basic",
                        "shareholders",
                        "ubo"
                      ],
                      "description": "The tier this endpoint sells: `basic` (Lite) for select, `shareholders`, `ubo`."
                    },
                    "registry_tier_delivered": {
                      "type": "string",
                      "enum": [
                        "basic",
                        "shareholders",
                        "ubo"
                      ],
                      "description": "The tier actually delivered and billed. Lower than requested when the country's registries hold no ownership data, or the registry has no ownership record for this company."
                    },
                    "kyb_registry": {
                      "type": "object",
                      "description": "Full registry company profile.",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Didit's id for this company record."
                        },
                        "node_id": {
                          "type": "string",
                          "example": "feature_kyb_registry"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "Not Finished",
                            "Approved",
                            "Declined",
                            "In Review"
                          ],
                          "description": "Didit's assessment of the registry check (e.g. `In Review` when the company is not active in the registry or ownership data could not be derived)."
                        },
                        "registry_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "active",
                            "dissolved",
                            "deregistered",
                            "see full details",
                            "authorised",
                            "appointed representative",
                            "unauthorised",
                            "inactive",
                            "no longer authorised",
                            "closed",
                            "struck off"
                          ],
                          "description": "Normalized company status as reported by the registry."
                        },
                        "data_resolved": {
                          "type": "boolean",
                          "description": "`true` once the registry returned the full profile. `false` when the registry was still processing after polling — the stored record completes automatically once the registry resolves."
                        },
                        "company_name": {
                          "type": "string",
                          "example": "Tesco PLC"
                        },
                        "registration_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "00445790"
                        },
                        "country_code": {
                          "type": "string",
                          "description": "ISO 3166-1 alpha-2.",
                          "example": "GB"
                        },
                        "region": {
                          "type": "string",
                          "nullable": true,
                          "description": "Subdivision code when the registry is regional (e.g. `CA` for `US-CA`); empty otherwise."
                        },
                        "company_type": {
                          "type": "string",
                          "nullable": true,
                          "example": "Public Limited Company"
                        },
                        "incorporation_date": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "example": "1947-11-27"
                        },
                        "registered_address": {
                          "type": "string",
                          "nullable": true,
                          "example": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA"
                        },
                        "tax_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "GB412 8925 93"
                        },
                        "risk_level": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry-reported risk level, when available."
                        },
                        "verification_status": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry verification status, when available."
                        },
                        "is_from_registry": {
                          "type": "boolean",
                          "description": "Always `true` for this endpoint — the profile was retrieved from an official registry."
                        },
                        "fetch_status": {
                          "type": "string",
                          "enum": [
                            "pending",
                            "resolved"
                          ],
                          "description": "Registry fetch lifecycle. Mirrored by `data_resolved`."
                        },
                        "alternative_names": {
                          "type": "string",
                          "nullable": true,
                          "description": "Alternative, trading, former or original-language company names as text, when reported."
                        },
                        "nature_of_business": {
                          "type": "string",
                          "nullable": true,
                          "description": "Activity description or classification code, when reported."
                        },
                        "registered_capital": {
                          "type": "string",
                          "nullable": true
                        },
                        "registered_capital_amount": {
                          "type": "string",
                          "nullable": true,
                          "description": "Decimal amount as a string, when reported."
                        },
                        "registered_capital_currency": {
                          "type": "string",
                          "nullable": true,
                          "description": "ISO 4217 code, when reported."
                        },
                        "website": {
                          "type": "string",
                          "nullable": true,
                          "example": "https://www.tesco.com/"
                        },
                        "email": {
                          "type": "string",
                          "nullable": true,
                          "example": "customer.service@tesco.co.uk"
                        },
                        "phone": {
                          "type": "string",
                          "nullable": true,
                          "example": "03301231688"
                        },
                        "legal_entity_identifier": {
                          "type": "string",
                          "nullable": true,
                          "description": "LEI, when reported."
                        },
                        "location_of_registration": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry/jurisdiction the company is registered with, when reported."
                        },
                        "vat_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "EU VAT number, when collected during the hosted registry step or edited afterwards. At select time this is typically not yet set — VAT and tax ID validation runs when the end user submits the registry step in the hosted flow."
                        },
                        "vat_validation_status": {
                          "type": "string",
                          "enum": [
                            "valid",
                            "invalid",
                            "format_valid",
                            "invalid_format",
                            "could_not_validate",
                            "not_applicable"
                          ],
                          "description": "Result of validating the VAT number or, when there is none, the `tax_number`, at registry submit. `valid` / `invalid`: decided by the official registry of the country (EU VIES, Norway, Switzerland, Brazil, Colombia, Costa Rica, Ecuador, Paraguay; Poland also by its domestic VAT register). `format_valid` / `invalid_format`: decided by the country's format and check-digit rules where no registry can be queried. `could_not_validate`: the registry was unavailable. `not_applicable`: no number, a country without registry or rules, or a sandbox session."
                        },
                        "vat_validated_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "The number that was checked, as the source knows it (for example the VAT number derived from a French SIREN or a Dutch RSIN). `null` when no check ran."
                        },
                        "vat_validation_source": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "eu_vies",
                            "pl_vat_white_list",
                            "no_brreg",
                            "ch_uid_register",
                            "br_receita_federal",
                            "co_rues",
                            "cr_hacienda",
                            "ec_sri",
                            "py_dnit",
                            "format_rules",
                            null
                          ],
                          "description": "The source that decided `vat_validation_status`: an official registry, or `format_rules`. `null` when no check ran."
                        },
                        "vat_validated_name": {
                          "type": "string",
                          "nullable": true,
                          "description": "Name registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                        },
                        "vat_validated_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Address registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                        },
                        "vat_checked_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Timestamp of the check. `null` when no check ran."
                        },
                        "financial_summary": {
                          "type": "object",
                          "nullable": true,
                          "description": "Registry-reported share/capital details (currency, total shares, share classes), when available."
                        },
                        "officers": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string",
                                "example": "MELISSA BETHELL"
                              },
                              "designation": {
                                "type": "string",
                                "nullable": true,
                                "description": "Raw registry designation (e.g. `Director`, `Secretary`)."
                              },
                              "role": {
                                "type": "string",
                                "description": "Normalized role derived from the designation. Full 17-value model set; registry parsing on this endpoint typically emits director, non_executive_director, secretary, chairman, or company_officer.",
                                "enum": [
                                  "director",
                                  "non_executive_director",
                                  "secretary",
                                  "chairman",
                                  "ubo",
                                  "shareholder",
                                  "representative",
                                  "founder",
                                  "legal_advisor",
                                  "authorized_signatory",
                                  "trustee",
                                  "beneficiary",
                                  "company_officer",
                                  "settlor",
                                  "protector",
                                  "investor",
                                  "other"
                                ]
                              },
                              "nationality": {
                                "type": "string",
                                "nullable": true
                              },
                              "is_active": {
                                "type": "boolean",
                                "description": "`false` when the registry marks the appointment as resigned."
                              },
                              "kyc_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Approved",
                                  "Declined",
                                  "Pending"
                                ],
                                "description": "Status of an associated KYC session, when one was started for this officer. `null` otherwise."
                              },
                              "kyc_session_url": {
                                "type": "string",
                                "nullable": true,
                                "description": "Verification URL of the associated KYC session, when one exists."
                              },
                              "first_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Given name when explicitly reported by the registry; not inferred from the full name."
                              },
                              "last_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Family name when explicitly reported by the registry."
                              },
                              "address": {
                                "type": "string",
                                "nullable": true,
                                "description": "Officer address reported by the registry."
                              },
                              "appointment_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Date the officer was appointed.",
                                "format": "date"
                              },
                              "termination_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Date the appointment ended, when reported.",
                                "format": "date"
                              },
                              "date_of_birth": {
                                "type": "string",
                                "nullable": true,
                                "description": "Complete registry-reported birth date. Null when only a birth year or month is known.",
                                "format": "date"
                              },
                              "date_of_birth_year": {
                                "type": "integer",
                                "nullable": true,
                                "minimum": 1,
                                "maximum": 9999,
                                "description": "Registry-reported birth year, including when the full date is unavailable."
                              },
                              "date_of_birth_month": {
                                "type": "integer",
                                "nullable": true,
                                "minimum": 1,
                                "maximum": 12,
                                "description": "Registry-reported birth month. Null when only the year is known."
                              }
                            }
                          },
                          "description": "Directors, secretaries, and other officers extracted from the registry."
                        },
                        "beneficial_owners": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string"
                              },
                              "first_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "last_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "entity_type": {
                                "type": "string",
                                "enum": [
                                  "person",
                                  "company"
                                ],
                                "description": "Whether the owner is a natural person or a corporate entity."
                              },
                              "roles": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Normalized roles (e.g. `ubo`, `shareholder`)."
                              },
                              "ownership_min_shares": {
                                "type": "string",
                                "nullable": true,
                                "description": "Lower bound of the ownership band reported by the registry (e.g. `25%`)."
                              },
                              "ownership_max_shares": {
                                "type": "string",
                                "nullable": true,
                                "description": "Upper bound of the ownership band reported by the registry."
                              },
                              "is_active": {
                                "type": "boolean"
                              },
                              "kyc_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Approved",
                                  "Declined",
                                  "Pending"
                                ]
                              },
                              "kyc_session_url": {
                                "type": "string",
                                "nullable": true
                              },
                              "effective_ownership_percent": {
                                "type": "number",
                                "nullable": true,
                                "description": "Parsed ownership percentage (max bound, falling back to min bound)."
                              },
                              "company_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "registration_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "country_of_birth": {
                                "type": "string",
                                "nullable": true
                              },
                              "email": {
                                "type": "string",
                                "nullable": true
                              },
                              "nationality": {
                                "type": "string",
                                "nullable": true
                              },
                              "designation": {
                                "type": "string",
                                "nullable": true
                              },
                              "voting_min_shares": {
                                "type": "string",
                                "nullable": true
                              },
                              "voting_max_shares": {
                                "type": "string",
                                "nullable": true
                              },
                              "date_of_birth": {
                                "type": "string",
                                "nullable": true,
                                "description": "Complete birth date when reported.",
                                "format": "date"
                              },
                              "appointment_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Appointment date when reported.",
                                "format": "date"
                              },
                              "shareholding": {
                                "$ref": "#/components/schemas/KYBRegistryShareholding"
                              }
                            }
                          },
                          "description": "Beneficial owners / persons with significant control extracted from the registry. Can be empty when the registry does not expose ownership."
                        },
                        "addresses": {
                          "type": "array",
                          "nullable": true,
                          "description": "Every address the registry states, one canonical shape. Null when it states none.",
                          "items": {
                            "$ref": "#/components/schemas/KYBRegistryAddress"
                          }
                        },
                        "industries": {
                          "type": "array",
                          "nullable": true,
                          "description": "The activities the registry classifies the company under, one canonical shape. Null when it states none.",
                          "items": {
                            "$ref": "#/components/schemas/KYBRegistryIndustry"
                          }
                        },
                        "accounts": {
                          "type": "object",
                          "nullable": true,
                          "additionalProperties": true,
                          "description": "Registry filing dates, when available. Annual returns and general meetings use last_annual_return_date and last_agm_date; they are distinct from financial accounts."
                        },
                        "registry_data": {
                          "type": "object",
                          "description": "Raw record returned by the registry source, kept for reviewers. Its shape differs by country and source and is not a stable contract: read the canonical fields (`addresses`, `industries`, `ownership`, `beneficial_owners[].shareholding`) instead."
                        },
                        "user_provided_data": {
                          "type": "object",
                          "nullable": true,
                          "description": "Always `null` on this endpoint (used by the hosted KYB flow when end users edit registry data)."
                        },
                        "confirmed_by_user_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Always `null` on this endpoint."
                        },
                        "last_console_edit_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Set when a console reviewer edits the record later."
                        },
                        "is_editable": {
                          "type": "boolean",
                          "description": "Whether the registry-sourced data can still be edited in the hosted flow/console."
                        },
                        "registry_tier_delivered": {
                          "type": "string",
                          "enum": [
                            "basic",
                            "shareholders",
                            "ubo"
                          ],
                          "description": "Same as the top-level `registry_tier_delivered`."
                        },
                        "registry_ownership_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "not_requested",
                            "delivered",
                            "unavailable"
                          ],
                          "description": "`delivered` when the ownership data came back, `unavailable` when an ownership tier was requested but the registry had none for this company (see `registry_data.ownership_error`), `not_requested` on the Lite tier."
                        },
                        "ownership": {
                          "$ref": "#/components/schemas/KYBRegistryOwnership"
                        },
                        "registry_tier": {
                          "type": "string",
                          "nullable": true,
                          "description": "The registry tier the workflow ordered: `basic`, `shareholders` or `ubo`. Also in `ownership.tier_requested`."
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "description": "Echo of the `metadata` you sent."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "examples": {
                  "Resolved company": {
                    "summary": "Full registry profile (officer list truncated for brevity)",
                    "value": {
                      "request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
                      "kyb_registry": {
                        "uuid": "f1e2d3c4-b5a6-4789-9c0d-1e2f3a4b5c6d",
                        "node_id": "feature_kyb_registry",
                        "status": "In Review",
                        "registry_status": "active",
                        "data_resolved": true,
                        "company_name": "Tesco PLC",
                        "registration_number": "00445790",
                        "country_code": "GB",
                        "region": "",
                        "company_type": "Public Limited Company",
                        "incorporation_date": "1947-11-27",
                        "registered_address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
                        "tax_number": "GB412 8925 93",
                        "risk_level": "low risk",
                        "verification_status": "verified",
                        "is_from_registry": true,
                        "fetch_status": "resolved",
                        "alternative_names": "TESCO STORES (HOLDINGS) PUBLIC LIMITED COMPANY",
                        "nature_of_business": null,
                        "registered_capital": null,
                        "registered_capital_amount": null,
                        "registered_capital_currency": null,
                        "website": "https://www.tesco.com/",
                        "email": "customer.service@tesco.co.uk",
                        "phone": "03301231688",
                        "legal_entity_identifier": null,
                        "location_of_registration": null,
                        "financial_summary": {
                          "currency": "Pound (£)",
                          "total_number_of_shares": "8174378721",
                          "meta_detail": {
                            "Class_Of_Share": "Ordinary"
                          }
                        },
                        "officers": [
                          {
                            "uuid": "a1b2c3d4-e5f6-4789-9a0b-1c2d3e4f5a6b",
                            "name": "CHRISTOPHER JON TAYLOR",
                            "designation": "Secretary",
                            "role": "secretary",
                            "nationality": null,
                            "is_active": true,
                            "kyc_status": null,
                            "kyc_session_url": null
                          },
                          {
                            "uuid": "b2c3d4e5-f6a7-4890-8b1c-2d3e4f5a6b7c",
                            "name": "MELISSA BETHELL",
                            "designation": "Director",
                            "role": "director",
                            "nationality": "British",
                            "is_active": true,
                            "kyc_status": null,
                            "kyc_session_url": null
                          }
                        ],
                        "beneficial_owners": [],
                        "addresses": [
                          {
                            "address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
                            "type": "legal_entity_registry_address",
                            "description": "registered office address"
                          }
                        ],
                        "industries": null,
                        "accounts": {
                          "last_account": "26 February 2025",
                          "next_account": "26 February 2026",
                          "due_by_date": "26 August 2026"
                        },
                        "registry_data": {
                          "name": "Tesco PLC",
                          "registration_number": "00445790",
                          "status": "active",
                          "type": "Public Limited Company",
                          "incorporation_date": "1947-11-27",
                          "tax_number": "GB412 8925 93",
                          "country_code": "GB",
                          "fetch_status": "resolved",
                          "industries_detail": [
                            {
                              "code": "47110",
                              "name": "Retail Sale In Non-specialised Stores With Food, Beverages Or Tobacco Predominating",
                              "description": null,
                              "meta_detail": []
                            }
                          ]
                        },
                        "user_provided_data": null,
                        "confirmed_by_user_at": null,
                        "last_console_edit_at": null,
                        "is_editable": true
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:45:00.000000+00:00"
                    }
                  },
                  "Pending (registry still resolving)": {
                    "summary": "Select stayed pending after polling — sparse fields, auto-completes server-side",
                    "value": {
                      "request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
                      "kyb_registry": {
                        "uuid": "7c0a4f7e-2b1d-4f6a-9c3e-8d5b2a1f0e9d",
                        "node_id": "feature_kyb_registry",
                        "status": "Not Finished",
                        "registry_status": null,
                        "data_resolved": false,
                        "company_name": "Tesco PLC",
                        "registration_number": "00445790",
                        "country_code": "GB",
                        "region": null,
                        "company_type": null,
                        "incorporation_date": null,
                        "registered_address": null,
                        "tax_number": null,
                        "risk_level": null,
                        "verification_status": null,
                        "is_from_registry": true,
                        "fetch_status": "pending",
                        "alternative_names": null,
                        "nature_of_business": null,
                        "registered_capital": null,
                        "registered_capital_amount": null,
                        "registered_capital_currency": null,
                        "website": null,
                        "email": null,
                        "phone": null,
                        "legal_entity_identifier": null,
                        "location_of_registration": null,
                        "financial_summary": {},
                        "officers": [],
                        "beneficial_owners": [],
                        "addresses": null,
                        "industries": null,
                        "accounts": null,
                        "registry_data": {},
                        "user_provided_data": null,
                        "confirmed_by_user_at": null,
                        "last_console_edit_at": null,
                        "is_editable": true
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:45:00.000000+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field-level problems use DRF's standard envelope.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing kyb_response_id": {
                    "summary": "`kyb_response_id` is required",
                    "value": {
                      "kyb_response_id": [
                        "This field is required."
                      ]
                    }
                  },
                  "save_api_request=false rejected": {
                    "summary": "Selects are always persisted",
                    "value": {
                      "save_api_request": [
                        "KYB registry select must be saved so billing and retrieval can be tracked."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any screening or provider call happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/passive-liveness/": {
      "post": {
        "summary": "Passive Liveness",
        "description": "Detect presentation attacks — printed photos, screen replays, masks, deepfakes — from a single face image. No video, motion, or user interaction required.\n\n**How it works.** The image is analyzed by a biometric model; the largest detected face is evaluated and a liveness `score` (0–100) is computed. `status` is `Declined` when any `error`-severity warning fires:\n- `NO_FACE_DETECTED` — the liveness model found no face,\n- `LOW_LIVENESS_SCORE` — score at or below `face_liveness_score_decline_threshold` (default `30`),\n- `LIVENESS_FACE_ATTACK` — the model detected a presentation attack,\n- `FACE_IN_BLOCKLIST` / `POSSIBLE_FACE_IN_BLOCKLIST` — the face matches an entry on your face blocklist.\n\n`MULTIPLE_FACES_DETECTED` is a `warning`-severity signal (does not decline), and `DUPLICATED_FACE` / `POSSIBLE_DUPLICATED_FACE` are `information`-severity signals that the same face already appeared in another approved session (they never decline). `face_quality` and `face_luminance` (0–100, nullable) describe capture quality.\n\n**Blocklist and duplicate screening.** Runs on **every** call — with or without `save_api_request` — by matching the detected face against your application's face search index. Prior faces with the same `vendor_data` are excluded from the entire index search — so re-running liveness for the same user does not trigger `DUPLICATED_FACE`, and a blocklisted face originating from a session with the caller's own `vendor_data` is also NOT flagged (`FACE_IN_BLOCKLIST` screening is bypassed for same-`vendor_data` faces).\n\n**Billing.** Each `200` response consumes one Passive Liveness API credit (standalone APIs have no free tier). Insufficient balance returns `403` before any image processing.\n\n**Session persistence and face enrollment (`save_api_request`, default `true`).** When `true`, the call is persisted as an API-type session (Business Console, `GET /v3/session/{sessionId}/decision/` via the returned `request_id`, `status.updated` webhook), the reference image and face crop are stored, and the detected face is **enrolled into your face search index** so later Face Search calls and duplicate checks can match it. When `false`, the call is one-shot: nothing is stored and the face is not enrolled (blocklist/duplicate screening still runs).\n\n**Sandbox.** Sandbox API keys skip all processing and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Approved` mock payload, no session is persisted, and no credits are consumed.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.",
        "operationId": "post_v3passive-liveness",
        "tags": [
          "Standalone APIs"
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "user_image"
                ],
                "properties": {
                  "user_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Front-facing face image (e.g. a selfie). Allowed extensions: `tiff`, `jpg`, `jpeg`, `png`, `webp`. Maximum upload size: **5 MB** (larger files are rejected with `400`). Images are automatically compressed to ~0.5 MB before processing, so very high resolutions do not improve accuracy. The image should contain a single subject — when several faces are present, the largest one is evaluated and a `MULTIPLE_FACES_DETECTED` warning is added."
                  },
                  "face_liveness_score_decline_threshold": {
                    "type": "number",
                    "format": "float",
                    "default": 30,
                    "minimum": 0,
                    "maximum": 100,
                    "description": "Liveness score threshold (0–100). A computed score **at or below** this value emits a `LOW_LIVENESS_SCORE` warning and sets `status` to `Declined`. Default `30`; raise it for a stricter anti-spoofing posture. Values outside 0–100 return `400`.",
                    "example": 30
                  },
                  "rotate_image": {
                    "type": "boolean",
                    "default": false,
                    "description": "When `true`, the service tries 90-degree rotations of the input and uses the orientation that yields the best face detection. Useful when EXIF orientation is missing. Adds latency.",
                    "example": false
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `true` (default), persists the call as an API-type session, stores the face images, emits a `status.updated` webhook, and enrolls the detected face into your face search index. When `false`, the call is one-shot — nothing is stored and the face is not enrolled. Blocklist and duplicate screening run either way.",
                    "example": true
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional opaque identifier (your user id, email, UUID…) stored on the persisted session and echoed back. Also used to exclude prior sessions with the same `vendor_data` from the duplicate-face check, so re-verifying the same user does not raise `DUPLICATED_FACE`.",
                    "example": "user-123"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional JSON object stored with the session (when `save_api_request=true`) and echoed back. In multipart requests, send it as a JSON-encoded string field — it is parsed into an object.",
                    "example": {
                      "flow": "withdrawal"
                    }
                  }
                }
              },
              "example": {
                "user_image": "(binary JPEG/PNG selfie)",
                "face_liveness_score_decline_threshold": 30,
                "rotate_image": false,
                "save_api_request": true,
                "vendor_data": "user-123",
                "metadata": {
                  "flow": "withdrawal"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Passive liveness completed. `liveness.score` is the model's 0–100 confidence that the image shows a live person; `status` is `Approved` unless an `error`-severity warning fired. A spoofed or blocklisted face still returns `200` — inspect `liveness.status` and `liveness.warnings`, not just the HTTP code. When `save_api_request=true`, `request_id` is the persisted session id.",
            "content": {
              "application/json": {
                "examples": {
                  "Approved": {
                    "summary": "Live face — no warnings",
                    "value": {
                      "request_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                      "liveness": {
                        "status": "Approved",
                        "method": "PASSIVE",
                        "score": 95.0,
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                661,
                                728,
                                1688,
                                2188
                              ],
                              "confidence": 0.732973,
                              "age": 26.91,
                              "gender": "male",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": [],
                        "face_quality": 84.21,
                        "face_luminance": 50.33
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  },
                  "Declined - presentation attack": {
                    "summary": "The model flagged a spoof (print, replay, mask…)",
                    "value": {
                      "request_id": "f1c8c9b2-d3e4-4f5a-9b8c-7d6e5f4a3b2c",
                      "liveness": {
                        "status": "Declined",
                        "method": "PASSIVE",
                        "score": 12.5,
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                100,
                                120,
                                420,
                                540
                              ],
                              "confidence": 0.81,
                              "age": 30.1,
                              "gender": "female",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": [
                          {
                            "risk": "LOW_LIVENESS_SCORE",
                            "feature": "LIVENESS",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Low liveness score",
                            "long_description": "The liveness check resulted in a low score, indicating potential use of non-live facial representations or poor-quality biometric data."
                          },
                          {
                            "risk": "LIVENESS_FACE_ATTACK",
                            "feature": "LIVENESS",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Liveness Face Attack",
                            "long_description": "The system detected a potential attempt to bypass the liveness check."
                          }
                        ],
                        "face_quality": 72.4,
                        "face_luminance": 48.2
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  },
                  "Declined - face on blocklist": {
                    "summary": "Live face, but it matches a blocklist entry",
                    "value": {
                      "request_id": "0b54a1de-22aa-4e0f-9c84-5a2b1f3c4d5e",
                      "liveness": {
                        "status": "Declined",
                        "method": "PASSIVE",
                        "score": 93.75,
                        "user_image": {
                          "entities": [
                            {
                              "bbox": [
                                40,
                                40,
                                100,
                                100
                              ],
                              "confidence": 0.722082,
                              "age": 27.0,
                              "gender": "male",
                              "race": null
                            }
                          ],
                          "best_angle": 0
                        },
                        "warnings": [
                          {
                            "risk": "FACE_IN_BLOCKLIST",
                            "feature": "LIVENESS",
                            "additional_data": {
                              "blocklisted_session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
                              "blocklisted_session_number": 3242,
                              "api_service": null
                            },
                            "log_type": "error",
                            "short_description": "Face in blocklist",
                            "long_description": "The system identified a face in the blocklist, which means the face is not allowed to be verified."
                          }
                        ],
                        "face_quality": null,
                        "face_luminance": null
                      },
                      "vendor_data": "user-123",
                      "metadata": null,
                      "created_at": "2026-06-12T01:04:42.763237+00:00"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "liveness": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined"
                          ],
                          "description": "`Declined` when at least one `error`-severity warning fired (no face, low score, presentation attack, or a blocklist hit); `Approved` otherwise. `warning`/`information` entries (multiple faces, duplicates) never decline on their own."
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "PASSIVE"
                          ],
                          "description": "Always `PASSIVE` for this endpoint."
                        },
                        "score": {
                          "type": "number",
                          "format": "float",
                          "nullable": true,
                          "minimum": 0,
                          "maximum": 100,
                          "description": "Liveness confidence (0–100, two decimals) that the image depicts a live person rather than a spoof. `null` when the model returned no confidence.",
                          "example": 95.0
                        },
                        "user_image": {
                          "type": "object",
                          "description": "Face-detection results for the submitted image.",
                          "properties": {
                            "entities": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "bbox": {
                                    "type": "array",
                                    "items": {
                                      "type": "integer"
                                    },
                                    "minItems": 4,
                                    "maxItems": 4,
                                    "description": "Bounding box of the detected face as `[x_min, y_min, x_max, y_max]` pixel coordinates in the processed image.",
                                    "example": [
                                      661,
                                      728,
                                      1688,
                                      2188
                                    ]
                                  },
                                  "confidence": {
                                    "type": "number",
                                    "format": "float",
                                    "minimum": 0,
                                    "maximum": 1,
                                    "description": "Face-detection confidence (0–1).",
                                    "example": 0.732973
                                  },
                                  "age": {
                                    "type": "number",
                                    "format": "float",
                                    "description": "Model-estimated age of the detected face, in years. Informational only — it does not affect the liveness decision.",
                                    "example": 26.91
                                  },
                                  "gender": {
                                    "type": "string",
                                    "description": "Model-predicted gender of the detected face (`male` or `female`). Informational only.",
                                    "example": "male"
                                  },
                                  "race": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Reserved field — always `null` in responses from this endpoint.",
                                    "example": null
                                  }
                                }
                              },
                              "description": "One entry per detected face. The largest face is the one evaluated."
                            },
                            "best_angle": {
                              "type": "integer",
                              "nullable": true,
                              "description": "Rotation (degrees) that produced the best face detection; non-zero only when `rotate_image=true` corrected the orientation.",
                              "example": 0
                            }
                          }
                        },
                        "warnings": {
                          "type": "array",
                          "description": "Risk signals. `error` severity (declines): `NO_FACE_DETECTED`, `LOW_LIVENESS_SCORE` (score at or below the threshold), `LIVENESS_FACE_ATTACK`, `FACE_IN_BLOCKLIST`, `POSSIBLE_FACE_IN_BLOCKLIST`. `warning` severity (review, no decline): `MULTIPLE_FACES_DETECTED`. `information` severity (no decline): `DUPLICATED_FACE`, `POSSIBLE_DUPLICATED_FACE` — the same face already appeared in another approved session.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "risk": {
                                "type": "string",
                                "enum": [
                                  "NO_FACE_DETECTED",
                                  "LOW_LIVENESS_SCORE",
                                  "LIVENESS_FACE_ATTACK",
                                  "MULTIPLE_FACES_DETECTED",
                                  "FACE_IN_BLOCKLIST",
                                  "POSSIBLE_FACE_IN_BLOCKLIST",
                                  "DUPLICATED_FACE",
                                  "POSSIBLE_DUPLICATED_FACE"
                                ],
                                "description": "Machine-readable risk code."
                              },
                              "feature": {
                                "type": "string",
                                "enum": [
                                  "LIVENESS"
                                ],
                                "description": "Feature that raised the warning. Always `LIVENESS` on this endpoint."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "additionalProperties": true,
                                "description": "`null` for most warnings. Blocklist hits carry `{blocklisted_session_id, blocklisted_session_number, api_service}`; duplicate hits carry `{duplicated_session_id, duplicated_session_number, api_service}` pointing at the matching session."
                              },
                              "log_type": {
                                "type": "string",
                                "enum": [
                                  "error",
                                  "warning",
                                  "information"
                                ],
                                "description": "Severity. `error` warnings drive `status` to `Declined`; `warning` and `information` entries are advisory and never decline on their own."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "Human-readable one-line summary of the risk."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Human-readable explanation of the risk."
                              }
                            }
                          }
                        },
                        "face_quality": {
                          "type": "number",
                          "format": "float",
                          "nullable": true,
                          "minimum": 0,
                          "maximum": 100,
                          "description": "Capture-quality score of the detected face, normalized to 0–100. `null` when the model could not produce a reliable value.",
                          "example": 84.21
                        },
                        "face_luminance": {
                          "type": "number",
                          "format": "float",
                          "nullable": true,
                          "minimum": 0,
                          "maximum": 100,
                          "description": "Brightness of the detected face, normalized to 0–100. `null` when unavailable.",
                          "example": 50.33
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent, or `null`."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Echo of the `metadata` object you sent, or `null`."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp (UTC) of when the response was generated, e.g. `2026-06-12T01:04:42.763237+00:00`."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Returned when `user_image` is missing, exceeds 5 MB, has an unsupported extension, fails server-side image decoding, or when an option is out of range. Field errors use DRF's `{field: [messages]}` envelope; image-decoding failures use `{\"error\": ...}`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing image": {
                    "summary": "`user_image` not included in the form data",
                    "value": {
                      "user_image": [
                        "No file was submitted."
                      ]
                    }
                  },
                  "Invalid image format": {
                    "summary": "Allowed extension but undecodable image content",
                    "value": {
                      "error": "Invalid user image format."
                    }
                  },
                  "Unsupported file extension": {
                    "summary": "File extension outside tiff/jpg/jpeg/png/webp",
                    "value": {
                      "user_image": [
                        "File extension “txt” is not allowed. Allowed extensions are: tiff, jpg, jpeg, png, webp."
                      ]
                    }
                  },
                  "File too large": {
                    "summary": "Upload exceeds the 5 MB limit",
                    "value": {
                      "user_image": [
                        "File size should not exceed 5 MB"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any image processing happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/passive-liveness/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'user_image=@./selfie.jpg' \\\n  -F 'face_liveness_score_decline_threshold=30' \\\n  -F 'save_api_request=true' \\\n  -F 'vendor_data=user-123'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = 'https://verification.didit.me/v3/passive-liveness/'\nheaders = {'x-api-key': 'YOUR_API_KEY'}\n\nwith open('selfie.jpg', 'rb') as f:\n    files = {'user_image': ('selfie.jpg', f, 'image/jpeg')}\n    data = {\n        'face_liveness_score_decline_threshold': 30,\n        'save_api_request': 'true',\n        'vendor_data': 'user-123',\n    }\n    resp = requests.post(url, headers=headers, files=files, data=data, timeout=60)\n\nresp.raise_for_status()\nbody = resp.json()\nprint('status:', body['liveness']['status'])\nprint('score:', body['liveness']['score'])\nfor w in body['liveness']['warnings']:\n    print('warning:', w['risk'], '-', w['log_type'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import fs from 'node:fs';\n\nconst form = new FormData();\nform.append('user_image', new Blob([fs.readFileSync('./selfie.jpg')]), 'selfie.jpg');\nform.append('face_liveness_score_decline_threshold', '30');\nform.append('save_api_request', 'true');\nform.append('vendor_data', 'user-123');\n\nconst response = await fetch('https://verification.didit.me/v3/passive-liveness/', {\n  method: 'POST',\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n  body: form,\n});\n\nif (!response.ok) throw new Error(`Passive liveness failed: ${response.status}`);\nconst body = await response.json();\nconsole.log('status:', body.liveness.status, 'score:', body.liveness.score);\nbody.liveness.warnings.forEach(w => console.log('warning:', w.risk, '-', w.log_type));"
          }
        ]
      }
    },
    "/v3/database-validation/": {
      "post": {
        "summary": "Database Validation (standalone)",
        "operationId": "post_v3database-validation",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [],
        "description": "Validate a person's identity data against official government and registry sources — CPF in Brazil, RENAPER in Argentina, DNI registries in Spain and Peru, INE in Mexico, and 100+ more services across 60+ countries.\n\n**Service selection.** Each country exposes one or more catalog services identified by a `service_id` (e.g. `bra_cpf`, `arg_renaper`, `pan_cedula_sib`). Pin the services you want with the `services` array — if you omit it, exactly **one** default service runs (the longest-established live service for the country). Sending `services` also switches the response to the extended shape with `services_used` and `match_score`. Discover services, their required fields, and prices via `GET /v1/organization/database-validation-countries/` (a catalog endpoint not documented in this spec) or the Business Console workflow editor. Some services are flagged `requires_consent=true` in the catalog and demand `consent=true`; others require onboarding for your organization before they can be called.\n\n**Input fields.** `identification_number` is a universal field that maps to the right country-specific field automatically (see its description). Country format rules are enforced before any provider is called (e.g. BRA CPF must be exactly 11 digits) and format failures are never billed. Biometric services need a `selfie` upload (multipart only); Argentina RENAPER additionally requires `gender`.\n\n**Results.** Each service returns a field-by-field `validation` map plus a vendor-neutral `outcome_code` (`MATCH`, `PARTIAL_MATCH`, `NO_MATCH`, `DOCUMENT_NOT_FOUND`, `INVALID_DOCUMENT_FORMAT`, `INVALID_INPUT`, `MINOR_BLOCKED`, `DECEASED`, `BIOMETRIC_NO_MATCH`, `BIOMETRIC_IMAGE_UNUSABLE`, `INCONCLUSIVE`, `DOCUMENT_SUPERSEDED`, `REGISTRY_UNAVAILABLE`, `REGISTRY_ERROR`). Note the distinctions: `NO_MATCH` is a definitive mismatch, `INCONCLUSIVE` means the registry could not confirm either way (review, not decline), and `BIOMETRIC_IMAGE_UNUSABLE` is a technical selfie problem (retake), unlike the definitive `BIOMETRIC_NO_MATCH`. The overall `match_type` aggregates across services (any full → `full_match`, else any partial → `partial_match`, else `no_match`) and `no_match_action`/`partial_match_action` translate it into the final `status`. `validation_type` is derived: `two_by_two` when two or more distinct services produced a full match (on the identification number, on full name + date of birth together, or on the address without contradictions), else `one_by_one`.\n\n**Persistence.** `save_api_request` defaults to **true**: the result is stored as a session (`request_id` works with `GET /v3/session/{sessionId}/decision/`), appears in the console, and fires a `status.updated` webhook. It also controls the `validations` shape — per-service objects when saved, a merged `{field: match}` map when not.\n\n**Billing.** Per-service: each service that returns a billable result is charged its own catalog price. Failed or skipped services are not billed, and requests rejected with `400` cost nothing. The pre-flight balance check covers the sum of the selected services' prices (`403` when short).\n\n**Failures.** When no selected service returns a usable result, the API returns `400` with `validation_errors` if every unanswered attempt explicitly refused the input (`provider_rejected_input`, `retryable: false`). Correct the input before trying again. Otherwise it returns `502` with `validation_errors` (`empty_provider_response`, `retryable: true`), including mixed input rejection and unavailable fallback attempts; nothing is billed (a session is still recorded with status `Not Finished` when `save_api_request=true`). When only some services fail, the `200` response carries their failures in `database_validation.errors`.\n\n**Sandbox.** Keys from sandbox applications skip the registry calls and billing and return a static `full_match` response — the sandbox payload always includes `services_used` and `match_score: 100` regardless of how `services` was sent, so don't validate the live extended-shape gating or the 0.0–1.0 `match_score` fraction against sandbox responses.\n\nSend the request as `application/json`, or as `multipart/form-data` when uploading a `selfie`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "issuing_state"
                ],
                "properties": {
                  "issuing_state": {
                    "type": "string",
                    "description": "ISO 3166-1 **alpha-3** country code of the registry to validate against (e.g. `BRA`, `ESP`, `COL`). Determines which services are available. Unsupported codes return `400` with the full list of valid options.",
                    "example": "BRA"
                  },
                  "services": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Catalog `service_id`s to run for this country (e.g. `[\"bra_cpf\"]`). Also accepts a single string or a comma-separated/JSON-encoded string. **If omitted or empty, exactly one default service runs** — the longest-established live service for the country; newer, biometric, and pay-as-you-go services must be named explicitly. Sending `services` switches the response to the extended shape (adds `services_used` and `match_score`). Every id must exist and be live for the `issuing_state`; services that require onboarding return `400` until activated for your organization. Discover available services per country via `GET /v1/organization/database-validation-countries/` (a catalog endpoint not documented in this spec) or the Business Console workflow editor.",
                    "example": [
                      "bra_cpf"
                    ]
                  },
                  "validation_type": {
                    "type": "string",
                    "deprecated": true,
                    "description": "DEPRECATED. Accepted for backward compatibility but ignored — the response `validation_type` is now derived from how many services full-matched. Use `services` to pin specific services."
                  },
                  "consent": {
                    "type": "boolean",
                    "default": false,
                    "description": "Set to `true` when the end user has explicitly consented to the selected validation services. Required for services flagged `requires_consent=true` in the catalog — without it those services return `400` with `services_requiring_consent`."
                  },
                  "identification_number": {
                    "type": "string",
                    "description": "Universal identification number — automatically mapped to the correct country-specific field, so you can use it instead of `personal_number`/`tax_number`/`document_number`: ARG→document_number (DNI), BOL→document_number (CI), BRA→tax_number (CPF, 11 digits), CHL→personal_number (RUT), COL→personal_number (Cédula), CRI→personal_number (Cédula), DOM→personal_number (Cédula, 11 digits), ECU→personal_number (Cédula, 10 digits), ESP→personal_number (DNI/NIE), GTM→document_number (DPI), HND→document_number (DNI), MEX→personal_number (CURP, 18 chars), PAN→personal_number (Cédula), PER→personal_number (DNI, 8 digits), PRY→document_number (CI), SLV→document_number (DUI), URY→personal_number (CI), VEN→document_number (Cédula). It never overrides an explicitly provided country-specific field."
                  },
                  "first_name": {
                    "type": "string",
                    "description": "The individual's first name. Required by some services/countries.",
                    "example": "John"
                  },
                  "last_name": {
                    "type": "string",
                    "description": "The individual's last name. Required by some services/countries.",
                    "example": "Doe"
                  },
                  "middle_name": {
                    "type": "string",
                    "description": "Middle name, used by some country services (AUS, NZL, …)."
                  },
                  "full_name": {
                    "type": "string",
                    "description": "Full name — some services accept this in lieu of first/last name (e.g. CHN services, which match the native-script name)."
                  },
                  "date_of_birth": {
                    "type": "string",
                    "format": "date",
                    "description": "Date of birth, `YYYY-MM-DD`. Required by many services.",
                    "example": "1980-01-01"
                  },
                  "personal_number": {
                    "type": "string",
                    "description": "Government-issued unique personal identifier. Used by: CHL (RUT), COL (Cédula), CRI, DOM, ECU, ESP (DNI/NIE), MEX (CURP), PAN (Cédula), PER (DNI), URY. Consider `identification_number` instead."
                  },
                  "tax_number": {
                    "type": "string",
                    "description": "Tax identification number. Used by: BRA (CPF, 11 digits). Consider `identification_number` instead."
                  },
                  "document_number": {
                    "type": "string",
                    "description": "Document number. Used by: ARG (DNI), BOL (CI), GTM (DPI), HND (DNI), PRY (CI), SLV (DUI), VEN (Cédula). Consider `identification_number` instead."
                  },
                  "document_type": {
                    "type": "string",
                    "enum": [
                      "P",
                      "DL",
                      "ID",
                      "RP",
                      "SSC",
                      "HIC",
                      "WP",
                      "TC",
                      "VISA",
                      "PSC",
                      "BC",
                      "OTHER"
                    ],
                    "description": "Type of document being validated: `P` passport, `DL` driver license, `ID` national ID, `RP` residence permit (plus `SSC`, `HIC`, `WP`, `TC`, `VISA`, `PSC`, `BC`, `OTHER`). Required by some services (e.g. ESP)."
                  },
                  "expiration_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Document expiration date, `YYYY-MM-DD`. Required for ESP (Spain) validation.",
                    "example": "2030-01-15"
                  },
                  "date_of_issue": {
                    "type": "string",
                    "format": "date",
                    "description": "Document issue date, `YYYY-MM-DD` (fecha de expedición). Required for COL (Colombia) cédula validation.",
                    "example": "2015-06-20"
                  },
                  "nationality": {
                    "type": "string",
                    "description": "Nationality as ISO 3166-1 alpha-3. Required by some services."
                  },
                  "gender": {
                    "type": "string",
                    "enum": [
                      "M",
                      "F",
                      "X"
                    ],
                    "description": "Gender: `M`, `F`, or `X` (other/unknown). Required for Argentina's RENAPER validation (`arg_renaper`)."
                  },
                  "address": {
                    "description": "Residential address. Prefer the structured object `{\"street_1\":\"123 Main St\",\"street_2\":\"Apt 4B\",\"city\":\"Springfield\",\"region\":\"IL\",\"postal_code\":\"62701\",\"country\":\"US\"}`; a complete single-line string is still accepted. Required by address-verification services; when a service defines address requirements, missing parts return `400` with `address_fields_required_by`.",
                    "oneOf": [
                      {
                        "type": "object",
                        "properties": {
                          "street_1": {
                            "type": "string"
                          },
                          "street_2": {
                            "type": "string"
                          },
                          "city": {
                            "type": "string"
                          },
                          "region": {
                            "type": "string"
                          },
                          "postal_code": {
                            "type": "string"
                          },
                          "country": {
                            "type": "string"
                          }
                        }
                      },
                      {
                        "type": "string",
                        "description": "Complete single-line address (legacy)."
                      }
                    ]
                  },
                  "address_element_1": {
                    "type": "string",
                    "description": "Street address including street number and type. If omitted, derived from `address`."
                  },
                  "address_element_2": {
                    "type": "string",
                    "description": "Apartment, unit, building, floor, or extra address line. Only send when you have it explicitly."
                  },
                  "address_element_3": {
                    "type": "string",
                    "description": "City, suburb, district, locality, or neighborhood. If omitted, derived from `address`."
                  },
                  "address_element_4": {
                    "type": "string",
                    "description": "State, province, region, or town. If omitted, derived from `address`."
                  },
                  "address_element_5": {
                    "type": "string",
                    "description": "Postcode or postal code. `postal_code` is accepted as an alias."
                  },
                  "postal_code": {
                    "type": "string",
                    "description": "Postal code for address-based services (alias of `address_element_5`)."
                  },
                  "driver_license_number": {
                    "type": "string",
                    "description": "Driver licence number for government document-verification services (AUS, NZL, IND)."
                  },
                  "driver_license_card_number": {
                    "type": "string",
                    "description": "Physical driver licence card number, where required separately from the licence number (AUS)."
                  },
                  "driver_license_state": {
                    "type": "string",
                    "description": "Driver licence state or territory of issue (AUS)."
                  },
                  "driver_license_version": {
                    "type": "string",
                    "description": "Driver licence version code (NZL)."
                  },
                  "passport_number": {
                    "type": "string",
                    "description": "Passport number for government passport-verification services (AUS, NZL, IND, CHN)."
                  },
                  "passport_expiration_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Passport expiry date, `YYYY-MM-DD`, for passport-verification services."
                  },
                  "passport_file_number": {
                    "type": "string",
                    "description": "Passport file number (IND)."
                  },
                  "passport_issue_country": {
                    "type": "string",
                    "description": "Issuing country of the passport (ISO 3166-1 alpha-3) for passport-verification services."
                  },
                  "medicare_card_number": {
                    "type": "string",
                    "description": "Medicare card number (AUS)."
                  },
                  "immi_card_number": {
                    "type": "string",
                    "description": "Australian ImmiCard number."
                  },
                  "immi_card_expiry_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Australian ImmiCard expiry date."
                  },
                  "citizenship_certificate_number": {
                    "type": "string",
                    "description": "Citizenship certificate number (AUS)."
                  },
                  "birth_registration_number": {
                    "type": "string",
                    "description": "Birth-certificate registration number (AUS)."
                  },
                  "birth_registration_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Birth-certificate registration date (AUS)."
                  },
                  "birth_registration_state": {
                    "type": "string",
                    "description": "Birth-certificate registration state (AUS)."
                  },
                  "marriage_certificate_number": {
                    "type": "string",
                    "description": "Marriage certificate number (AUS)."
                  },
                  "change_of_name_certificate_number": {
                    "type": "string",
                    "description": "Change-of-name certificate number (AUS)."
                  },
                  "first_partner_name": {
                    "type": "string",
                    "description": "First name of the partner on a marriage certificate (AUS)."
                  },
                  "last_partner_name": {
                    "type": "string",
                    "description": "Last name of the partner on a marriage certificate (AUS)."
                  },
                  "voter_id": {
                    "type": "string",
                    "description": "Voter registration number (IND EPIC, IRL)."
                  },
                  "epic_card": {
                    "type": "string",
                    "description": "India EPIC voter card number."
                  },
                  "pan": {
                    "type": "string",
                    "description": "India PAN (Permanent Account Number)."
                  },
                  "national_id": {
                    "type": "string",
                    "description": "National ID number (CHN, MYS, KEN, KHM, NGA, ZAF, …)."
                  },
                  "cic": {
                    "type": "string",
                    "description": "Mexican INE/IFE Código de Identificación de Credencial (CIC), 9 digits. Used by the MEX INE credential-validity service (`mex_ine_vigencia`)."
                  },
                  "identificador_ciudadano": {
                    "type": "string",
                    "description": "Mexican INE Identificador del Ciudadano (9 digits). Used with `cic` for modern INE models (E/F/G/H) in `mex_ine_vigencia`."
                  },
                  "ocr": {
                    "type": "string",
                    "description": "Mexican INE OCR number (13 digits, back of card). Used with `cic` for Model D in `mex_ine_vigencia`."
                  },
                  "voter_number": {
                    "type": "string",
                    "description": "Mexican INE Clave de Elector (18 chars). Used with `emission_number` for legacy IFE models (A/B/C) in `mex_ine_vigencia`."
                  },
                  "emission_number": {
                    "type": "string",
                    "description": "Mexican INE Número de Emisión. Used with `voter_number` for legacy IFE models (A/B/C) in `mex_ine_vigencia`."
                  },
                  "bvn": {
                    "type": "string",
                    "description": "Nigerian Bank Verification Number."
                  },
                  "bank_card_number": {
                    "type": "string",
                    "description": "Bank card number (CHN bank-card verification)."
                  },
                  "ssn": {
                    "type": "string",
                    "description": "Social Security Number (USA)."
                  },
                  "phone": {
                    "type": "string",
                    "description": "Phone number for phone-verification services."
                  },
                  "landline": {
                    "type": "string",
                    "description": "Landline number for phone-verification services."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Email address for identity-verification services."
                  },
                  "country_of_residence": {
                    "type": "string",
                    "description": "ISO 3166-1 alpha-2 country of residence. Used by global identity-enrichment services (e.g. `glb_identity_enrichment`) to focus the lookup.",
                    "example": "US"
                  },
                  "partial_match_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "NO_ACTION",
                    "description": "What a `partial_match` does to `database_validation.status`. Defaults to `NO_ACTION` (status stays `Approved`, with a warning)."
                  },
                  "no_match_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What a `no_match` does to `database_validation.status`. Defaults to `DECLINE`."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "Persist the validation as a session (console visibility, decision endpoint, `status.updated` webhook). Also changes the `validations` response shape: per-service objects when `true` (default), a merged field map when `false`."
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for the validated user; echoed back and stored with the session."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON stored with the request and echoed back."
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "issuing_state"
                ],
                "properties": {
                  "issuing_state": {
                    "type": "string",
                    "description": "ISO 3166-1 **alpha-3** country code of the registry to validate against (e.g. `BRA`, `ESP`, `COL`). Determines which services are available. Unsupported codes return `400` with the full list of valid options.",
                    "example": "BRA"
                  },
                  "services": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Catalog `service_id`s to run for this country (e.g. `[\"bra_cpf\"]`). Also accepts a single string or a comma-separated/JSON-encoded string. **If omitted or empty, exactly one default service runs** — the longest-established live service for the country; newer, biometric, and pay-as-you-go services must be named explicitly. Sending `services` switches the response to the extended shape (adds `services_used` and `match_score`). Every id must exist and be live for the `issuing_state`; services that require onboarding return `400` until activated for your organization. Discover available services per country via `GET /v1/organization/database-validation-countries/` (a catalog endpoint not documented in this spec) or the Business Console workflow editor.",
                    "example": [
                      "bra_cpf"
                    ]
                  },
                  "validation_type": {
                    "type": "string",
                    "deprecated": true,
                    "description": "DEPRECATED. Accepted for backward compatibility but ignored — the response `validation_type` is now derived from how many services full-matched. Use `services` to pin specific services."
                  },
                  "consent": {
                    "type": "boolean",
                    "default": false,
                    "description": "Set to `true` when the end user has explicitly consented to the selected validation services. Required for services flagged `requires_consent=true` in the catalog — without it those services return `400` with `services_requiring_consent`."
                  },
                  "identification_number": {
                    "type": "string",
                    "description": "Universal identification number — automatically mapped to the correct country-specific field, so you can use it instead of `personal_number`/`tax_number`/`document_number`: ARG→document_number (DNI), BOL→document_number (CI), BRA→tax_number (CPF, 11 digits), CHL→personal_number (RUT), COL→personal_number (Cédula), CRI→personal_number (Cédula), DOM→personal_number (Cédula, 11 digits), ECU→personal_number (Cédula, 10 digits), ESP→personal_number (DNI/NIE), GTM→document_number (DPI), HND→document_number (DNI), MEX→personal_number (CURP, 18 chars), PAN→personal_number (Cédula), PER→personal_number (DNI, 8 digits), PRY→document_number (CI), SLV→document_number (DUI), URY→personal_number (CI), VEN→document_number (Cédula). It never overrides an explicitly provided country-specific field."
                  },
                  "first_name": {
                    "type": "string",
                    "description": "The individual's first name. Required by some services/countries.",
                    "example": "John"
                  },
                  "last_name": {
                    "type": "string",
                    "description": "The individual's last name. Required by some services/countries.",
                    "example": "Doe"
                  },
                  "middle_name": {
                    "type": "string",
                    "description": "Middle name, used by some country services (AUS, NZL, …)."
                  },
                  "full_name": {
                    "type": "string",
                    "description": "Full name — some services accept this in lieu of first/last name (e.g. CHN services, which match the native-script name)."
                  },
                  "date_of_birth": {
                    "type": "string",
                    "format": "date",
                    "description": "Date of birth, `YYYY-MM-DD`. Required by many services.",
                    "example": "1980-01-01"
                  },
                  "personal_number": {
                    "type": "string",
                    "description": "Government-issued unique personal identifier. Used by: CHL (RUT), COL (Cédula), CRI, DOM, ECU, ESP (DNI/NIE), MEX (CURP), PAN (Cédula), PER (DNI), URY. Consider `identification_number` instead."
                  },
                  "tax_number": {
                    "type": "string",
                    "description": "Tax identification number. Used by: BRA (CPF, 11 digits). Consider `identification_number` instead."
                  },
                  "document_number": {
                    "type": "string",
                    "description": "Document number. Used by: ARG (DNI), BOL (CI), GTM (DPI), HND (DNI), PRY (CI), SLV (DUI), VEN (Cédula). Consider `identification_number` instead."
                  },
                  "document_type": {
                    "type": "string",
                    "enum": [
                      "P",
                      "DL",
                      "ID",
                      "RP",
                      "SSC",
                      "HIC",
                      "WP",
                      "TC",
                      "VISA",
                      "PSC",
                      "BC",
                      "OTHER"
                    ],
                    "description": "Type of document being validated: `P` passport, `DL` driver license, `ID` national ID, `RP` residence permit (plus `SSC`, `HIC`, `WP`, `TC`, `VISA`, `PSC`, `BC`, `OTHER`). Required by some services (e.g. ESP)."
                  },
                  "expiration_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Document expiration date, `YYYY-MM-DD`. Required for ESP (Spain) validation.",
                    "example": "2030-01-15"
                  },
                  "date_of_issue": {
                    "type": "string",
                    "format": "date",
                    "description": "Document issue date, `YYYY-MM-DD` (fecha de expedición). Required for COL (Colombia) cédula validation.",
                    "example": "2015-06-20"
                  },
                  "nationality": {
                    "type": "string",
                    "description": "Nationality as ISO 3166-1 alpha-3. Required by some services."
                  },
                  "gender": {
                    "type": "string",
                    "enum": [
                      "M",
                      "F",
                      "X"
                    ],
                    "description": "Gender: `M`, `F`, or `X` (other/unknown). Required for Argentina's RENAPER validation (`arg_renaper`)."
                  },
                  "address": {
                    "description": "Residential address. Prefer the structured object `{\"street_1\":\"123 Main St\",\"street_2\":\"Apt 4B\",\"city\":\"Springfield\",\"region\":\"IL\",\"postal_code\":\"62701\",\"country\":\"US\"}`; a complete single-line string is still accepted. Required by address-verification services; when a service defines address requirements, missing parts return `400` with `address_fields_required_by`.",
                    "oneOf": [
                      {
                        "type": "object",
                        "properties": {
                          "street_1": {
                            "type": "string"
                          },
                          "street_2": {
                            "type": "string"
                          },
                          "city": {
                            "type": "string"
                          },
                          "region": {
                            "type": "string"
                          },
                          "postal_code": {
                            "type": "string"
                          },
                          "country": {
                            "type": "string"
                          }
                        }
                      },
                      {
                        "type": "string",
                        "description": "Complete single-line address (legacy)."
                      }
                    ]
                  },
                  "address_element_1": {
                    "type": "string",
                    "description": "Street address including street number and type. If omitted, derived from `address`."
                  },
                  "address_element_2": {
                    "type": "string",
                    "description": "Apartment, unit, building, floor, or extra address line. Only send when you have it explicitly."
                  },
                  "address_element_3": {
                    "type": "string",
                    "description": "City, suburb, district, locality, or neighborhood. If omitted, derived from `address`."
                  },
                  "address_element_4": {
                    "type": "string",
                    "description": "State, province, region, or town. If omitted, derived from `address`."
                  },
                  "address_element_5": {
                    "type": "string",
                    "description": "Postcode or postal code. `postal_code` is accepted as an alias."
                  },
                  "postal_code": {
                    "type": "string",
                    "description": "Postal code for address-based services (alias of `address_element_5`)."
                  },
                  "driver_license_number": {
                    "type": "string",
                    "description": "Driver licence number for government document-verification services (AUS, NZL, IND)."
                  },
                  "driver_license_card_number": {
                    "type": "string",
                    "description": "Physical driver licence card number, where required separately from the licence number (AUS)."
                  },
                  "driver_license_state": {
                    "type": "string",
                    "description": "Driver licence state or territory of issue (AUS)."
                  },
                  "driver_license_version": {
                    "type": "string",
                    "description": "Driver licence version code (NZL)."
                  },
                  "passport_number": {
                    "type": "string",
                    "description": "Passport number for government passport-verification services (AUS, NZL, IND, CHN)."
                  },
                  "passport_expiration_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Passport expiry date, `YYYY-MM-DD`, for passport-verification services."
                  },
                  "passport_file_number": {
                    "type": "string",
                    "description": "Passport file number (IND)."
                  },
                  "passport_issue_country": {
                    "type": "string",
                    "description": "Issuing country of the passport (ISO 3166-1 alpha-3) for passport-verification services."
                  },
                  "medicare_card_number": {
                    "type": "string",
                    "description": "Medicare card number (AUS)."
                  },
                  "immi_card_number": {
                    "type": "string",
                    "description": "Australian ImmiCard number."
                  },
                  "immi_card_expiry_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Australian ImmiCard expiry date."
                  },
                  "citizenship_certificate_number": {
                    "type": "string",
                    "description": "Citizenship certificate number (AUS)."
                  },
                  "birth_registration_number": {
                    "type": "string",
                    "description": "Birth-certificate registration number (AUS)."
                  },
                  "birth_registration_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Birth-certificate registration date (AUS)."
                  },
                  "birth_registration_state": {
                    "type": "string",
                    "description": "Birth-certificate registration state (AUS)."
                  },
                  "marriage_certificate_number": {
                    "type": "string",
                    "description": "Marriage certificate number (AUS)."
                  },
                  "change_of_name_certificate_number": {
                    "type": "string",
                    "description": "Change-of-name certificate number (AUS)."
                  },
                  "first_partner_name": {
                    "type": "string",
                    "description": "First name of the partner on a marriage certificate (AUS)."
                  },
                  "last_partner_name": {
                    "type": "string",
                    "description": "Last name of the partner on a marriage certificate (AUS)."
                  },
                  "voter_id": {
                    "type": "string",
                    "description": "Voter registration number (IND EPIC, IRL)."
                  },
                  "epic_card": {
                    "type": "string",
                    "description": "India EPIC voter card number."
                  },
                  "pan": {
                    "type": "string",
                    "description": "India PAN (Permanent Account Number)."
                  },
                  "national_id": {
                    "type": "string",
                    "description": "National ID number (CHN, MYS, KEN, KHM, NGA, ZAF, …)."
                  },
                  "cic": {
                    "type": "string",
                    "description": "Mexican INE/IFE Código de Identificación de Credencial (CIC), 9 digits. Used by the MEX INE credential-validity service (`mex_ine_vigencia`)."
                  },
                  "identificador_ciudadano": {
                    "type": "string",
                    "description": "Mexican INE Identificador del Ciudadano (9 digits). Used with `cic` for modern INE models (E/F/G/H) in `mex_ine_vigencia`."
                  },
                  "ocr": {
                    "type": "string",
                    "description": "Mexican INE OCR number (13 digits, back of card). Used with `cic` for Model D in `mex_ine_vigencia`."
                  },
                  "voter_number": {
                    "type": "string",
                    "description": "Mexican INE Clave de Elector (18 chars). Used with `emission_number` for legacy IFE models (A/B/C) in `mex_ine_vigencia`."
                  },
                  "emission_number": {
                    "type": "string",
                    "description": "Mexican INE Número de Emisión. Used with `voter_number` for legacy IFE models (A/B/C) in `mex_ine_vigencia`."
                  },
                  "bvn": {
                    "type": "string",
                    "description": "Nigerian Bank Verification Number."
                  },
                  "bank_card_number": {
                    "type": "string",
                    "description": "Bank card number (CHN bank-card verification)."
                  },
                  "ssn": {
                    "type": "string",
                    "description": "Social Security Number (USA)."
                  },
                  "phone": {
                    "type": "string",
                    "description": "Phone number for phone-verification services."
                  },
                  "landline": {
                    "type": "string",
                    "description": "Landline number for phone-verification services."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Email address for identity-verification services."
                  },
                  "country_of_residence": {
                    "type": "string",
                    "description": "ISO 3166-1 alpha-2 country of residence. Used by global identity-enrichment services (e.g. `glb_identity_enrichment`) to focus the lookup.",
                    "example": "US"
                  },
                  "partial_match_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "NO_ACTION",
                    "description": "What a `partial_match` does to `database_validation.status`. Defaults to `NO_ACTION` (status stays `Approved`, with a warning)."
                  },
                  "no_match_action": {
                    "type": "string",
                    "enum": [
                      "DECLINE",
                      "NO_ACTION"
                    ],
                    "default": "DECLINE",
                    "description": "What a `no_match` does to `database_validation.status`. Defaults to `DECLINE`."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "Persist the validation as a session (console visibility, decision endpoint, `status.updated` webhook). Also changes the `validations` response shape: per-service objects when `true` (default), a merged field map when `false`."
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for the validated user; echoed back and stored with the session."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON stored with the request and echoed back."
                  },
                  "selfie": {
                    "type": "string",
                    "format": "binary",
                    "description": "Selfie image (`jpg`, `jpeg`, `png`, `webp`; max 2 MB — images are compressed to ~1.5 MB before upload to the registry) for biometric validation services, e.g. Argentina RENAPER (`arg_renaper`) and Panama SIB (`pan_cedula_sib`, `pan_cedula_sib_plus`). Required whenever a selected service lists it as a required field. Only available via `multipart/form-data`."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/database-validation/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"issuing_state\": \"BRA\",\n    \"services\": [\"bra_cpf\"],\n    \"identification_number\": \"12345678900\",\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"date_of_birth\": \"1980-01-01\",\n    \"vendor_data\": \"user-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/database-validation/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\n        \"issuing_state\": \"BRA\",\n        \"services\": [\"bra_cpf\"],\n        \"identification_number\": \"12345678900\",\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"date_of_birth\": \"1980-01-01\",\n        \"vendor_data\": \"user-1234\",\n    },\n    timeout=45,\n)\nresp.raise_for_status()\ndv = resp.json()[\"database_validation\"]\nprint(dv[\"status\"], dv[\"match_type\"])  # e.g. Approved full_match\n\n# Biometric services need a selfie via multipart/form-data:\n# requests.post(..., data={\"issuing_state\": \"ARG\", \"services\": '[\"arg_renaper\"]',\n#                          \"identification_number\": \"12345678\", \"gender\": \"M\", ...},\n#               files={\"selfie\": open(\"selfie.jpg\", \"rb\")})"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/database-validation/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    issuing_state: 'BRA',\n    services: ['bra_cpf'],\n    identification_number: '12345678900',\n    first_name: 'John',\n    last_name: 'Doe',\n    date_of_birth: '1980-01-01',\n    vendor_data: 'user-1234',\n  }),\n});\nconst data = await res.json();\nconsole.log(data.database_validation.status, data.database_validation.match_type);"
          }
        ],
        "responses": {
          "200": {
            "description": "Validation completed — at least one selected service returned a usable result. Inspect `database_validation.match_type` for the aggregate outcome, `validations` for the per-service field comparisons and `outcome_code`s, and `errors` (when present) for services that failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Persisted session id when `save_api_request=true` (usable with `GET /v3/session/{sessionId}/decision/`); otherwise a transient correlation UUID."
                    },
                    "database_validation": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "Approved",
                            "Declined",
                            "In Review"
                          ],
                          "description": "`Declined` when the overall `match_type` triggers a `DECLINE` action (`no_match_action` defaults to `DECLINE`, `partial_match_action` to `NO_ACTION`); `In Review` when no service produced a usable comparison, for example when the only selected service came back `REGISTRY_UNAVAILABLE` or `INCONCLUSIVE`; `Approved` otherwise. A request that selected several services can be `Approved` on one service's match while another was unavailable, so check `errors` and the per-service `outcome_code`s too."
                        },
                        "issuing_state": {
                          "type": "string",
                          "description": "Echo of the ISO 3166-1 alpha-3 country validated against.",
                          "example": "BRA"
                        },
                        "validation_type": {
                          "type": "string",
                          "enum": [
                            "one_by_one",
                            "two_by_two"
                          ],
                          "description": "Derived from the results: `two_by_two` when ≥2 distinct services produced a full match (on the identification number, on full name + date of birth together, or on the address without contradictions); `one_by_one` otherwise. (The request field of the same name is deprecated and ignored.)"
                        },
                        "screened_data": {
                          "type": "object",
                          "description": "Echo of the input fields that were sent to the selected services (dates normalized to `YYYY-MM-DD`; a `selfie`, when sent, is returned as a pre-signed URL; `consent_obtained: true` is added when consent was given)."
                        },
                        "match_type": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "full_match",
                            "partial_match",
                            "no_match"
                          ],
                          "description": "Overall result aggregated across services with field-level comparisons: any `full_match` → `full_match`; else any `partial_match` → `partial_match`; else `no_match`. Outcome-only services, such as biometric criminal screening, can return `null`; inspect each item in `validations` for its `outcome_code`."
                        },
                        "validations": {
                          "description": "Shape depends on `save_api_request`. **`true` (default):** an array of per-service objects (`service_id`, `service_name`, `validation`, `outcome_code`, `outcome_detail`, `source_data`). **`false`:** a single flat object merging the field-level results of all services (`{\"full_name\": \"full_match\", ...}`).",
                          "oneOf": [
                            {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "description": "Per-service validation result (returned when `save_api_request=true`, the default).",
                                "properties": {
                                  "service_id": {
                                    "type": "string",
                                    "description": "Catalog id of the service that produced this result (e.g. `bra_cpf`).",
                                    "example": "bra_cpf"
                                  },
                                  "service_name": {
                                    "type": "string",
                                    "description": "Human-readable catalog name of the service.",
                                    "example": "Brazil - CPF status check"
                                  },
                                  "validation": {
                                    "type": "object",
                                    "description": "Field-by-field comparison between your input and the registry record. Keys are canonical field names (`full_name`, `date_of_birth`, `identification_number`, `address`, …); values are `full_match`, `partial_match`, or `no_match`.",
                                    "additionalProperties": {
                                      "type": "string",
                                      "enum": [
                                        "full_match",
                                        "partial_match",
                                        "no_match"
                                      ]
                                    }
                                  },
                                  "outcome_code": {
                                    "type": "string",
                                    "enum": [
                                      "MATCH",
                                      "PARTIAL_MATCH",
                                      "NO_MATCH",
                                      "DOCUMENT_NOT_FOUND",
                                      "INVALID_DOCUMENT_FORMAT",
                                      "INVALID_INPUT",
                                      "MINOR_BLOCKED",
                                      "DECEASED",
                                      "BIOMETRIC_NO_MATCH",
                                      "BIOMETRIC_IMAGE_UNUSABLE",
                                      "INCONCLUSIVE",
                                      "DOCUMENT_SUPERSEDED",
                                      "REGISTRY_UNAVAILABLE",
                                      "REGISTRY_ERROR"
                                    ],
                                    "description": "Vendor-neutral outcome of the registry lookup. `MATCH`/`PARTIAL_MATCH`/`NO_MATCH` describe the comparison; `DOCUMENT_NOT_FOUND` means the identifier is not in the registry; `INCONCLUSIVE` means the registry could not confirm either way (routed to review — NOT a no-match); `BIOMETRIC_NO_MATCH` is a definitive face mismatch while `BIOMETRIC_IMAGE_UNUSABLE` is a technical image problem (retake the selfie); `DECEASED`/`MINOR_BLOCKED` are registry-policy outcomes; `DOCUMENT_SUPERSEDED` means the identity matched but the edition of the document presented is not the one on file (a newer edition has been issued); `INVALID_DOCUMENT_FORMAT`/`INVALID_INPUT` mean the registry itself rejected the data it was sent; `REGISTRY_UNAVAILABLE`/`REGISTRY_ERROR` indicate upstream failures."
                                  },
                                  "outcome_detail": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Raw upstream status detail backing the outcome code (e.g. an HTTP or registry status code)."
                                  },
                                  "source_data": {
                                    "type": "object",
                                    "nullable": true,
                                    "description": "Cleaned, normalized view of the registry record using canonical field names (`identification_number`, `first_name`, `last_name`, `date_of_birth`, plus registry-specific flags). Image fields, when present, are returned as pre-signed URLs."
                                  }
                                }
                              }
                            },
                            {
                              "type": "object",
                              "additionalProperties": {
                                "type": "string",
                                "enum": [
                                  "full_match",
                                  "partial_match",
                                  "no_match"
                                ]
                              },
                              "description": "Merged field-level results (stateless `save_api_request=false` shape)."
                            }
                          ]
                        },
                        "warnings": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "feature": {
                                "type": "string",
                                "description": "Feature that raised the warning."
                              },
                              "risk": {
                                "type": "string",
                                "description": "Machine-readable risk identifier."
                              },
                              "additional_data": {
                                "type": "object",
                                "nullable": true,
                                "description": "Extra context for the warning, when available."
                              },
                              "log_type": {
                                "type": "string",
                                "description": "`warning`, `information`, or `error` — how the risk affected the outcome."
                              },
                              "short_description": {
                                "type": "string",
                                "description": "One-line human-readable summary."
                              },
                              "long_description": {
                                "type": "string",
                                "description": "Full human-readable explanation."
                              }
                            }
                          },
                          "description": "`DATABASE_VALIDATION_NO_MATCH` or `DATABASE_VALIDATION_PARTIAL_MATCH` when applicable; empty on a full match."
                        },
                        "errors": {
                          "type": "array",
                          "description": "Present only when some (but not all) selected services failed. Each entry carries `service_id`, `code`, `message`, and `retryable`. A service reported here is absent from `validations` and `services_used`, and is not billed. This array is the only place it appears, so inspect it even when `status` is `Approved`.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "service_id": {
                                "type": "string"
                              },
                              "code": {
                                "type": "string",
                                "example": "empty_provider_response"
                              },
                              "message": {
                                "type": "string"
                              },
                              "retryable": {
                                "type": "boolean",
                                "description": "`true` when the service produced no answer and retrying it later can succeed; `false` when the source refused the data it was sent and the input must be corrected first.",
                                "example": true
                              }
                            }
                          }
                        },
                        "services_used": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Catalog ids of the services that returned a billable result. **Only present when the request explicitly sent `services`.**"
                        },
                        "match_score": {
                          "type": "number",
                          "description": "Fraction (0.0–1.0) of attempted services that produced a full match (on the identification number, on full name + date of birth together, or on the address without contradictions). **Only present when the request explicitly sent `services`.**"
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "description": "Echo of the `metadata` you sent."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "examples": {
                  "Full match (Approved)": {
                    "summary": "Default save_api_request=true — per-service `validations` objects",
                    "value": {
                      "request_id": "7f9a1c0e-1f2b-4f6e-9d3a-2b1c0e7f9a1c",
                      "database_validation": {
                        "status": "Approved",
                        "issuing_state": "BRA",
                        "validation_type": "one_by_one",
                        "screened_data": {
                          "tax_number": "12345678900",
                          "first_name": "John",
                          "last_name": "Doe",
                          "date_of_birth": "1980-01-01"
                        },
                        "match_type": "full_match",
                        "validations": [
                          {
                            "validation": {
                              "full_name": "full_match",
                              "date_of_birth": "full_match",
                              "identification_number": "full_match"
                            },
                            "outcome_code": "MATCH",
                            "outcome_detail": "200",
                            "service_id": "bra_cpf",
                            "service_name": "Brazil - CPF status check",
                            "source_data": {
                              "identification_number": "12345678900",
                              "first_name": "JOHN",
                              "last_name": "DOE",
                              "date_of_birth": "1980-01-01",
                              "lgpd_minor": false,
                              "minor_under_16": false,
                              "minor_under_18": false
                            }
                          }
                        ],
                        "warnings": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:30:00.000000+00:00"
                    }
                  },
                  "Explicit services (extended shape)": {
                    "summary": "Request sent `services` — response adds `services_used` and `match_score`",
                    "value": {
                      "request_id": "b3e7c1a2-9d4f-4f0b-8a6c-5e2d1f0a9b3e",
                      "database_validation": {
                        "status": "Approved",
                        "issuing_state": "BRA",
                        "validation_type": "one_by_one",
                        "screened_data": {
                          "tax_number": "12345678900",
                          "first_name": "John",
                          "last_name": "Doe",
                          "date_of_birth": "1980-01-01"
                        },
                        "match_type": "full_match",
                        "validations": [
                          {
                            "validation": {
                              "full_name": "full_match",
                              "date_of_birth": "full_match",
                              "identification_number": "full_match"
                            },
                            "outcome_code": "MATCH",
                            "outcome_detail": "200",
                            "service_id": "bra_cpf",
                            "service_name": "Brazil - CPF status check",
                            "source_data": {
                              "identification_number": "12345678900",
                              "first_name": "JOHN",
                              "last_name": "DOE",
                              "date_of_birth": "1980-01-01",
                              "lgpd_minor": false,
                              "minor_under_16": false,
                              "minor_under_18": false
                            }
                          }
                        ],
                        "warnings": [],
                        "services_used": [
                          "bra_cpf"
                        ],
                        "match_score": 1.0
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:30:00.000000+00:00"
                    }
                  },
                  "No match (Declined)": {
                    "summary": "Registry record does not match — default `no_match_action=DECLINE`",
                    "value": {
                      "request_id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789",
                      "database_validation": {
                        "status": "Declined",
                        "issuing_state": "BRA",
                        "validation_type": "one_by_one",
                        "screened_data": {
                          "tax_number": "12345678900",
                          "first_name": "John",
                          "last_name": "Doe",
                          "date_of_birth": "1980-01-01"
                        },
                        "match_type": "no_match",
                        "validations": [
                          {
                            "validation": {
                              "full_name": "no_match",
                              "date_of_birth": "no_match",
                              "identification_number": "no_match"
                            },
                            "outcome_code": "NO_MATCH",
                            "outcome_detail": "200",
                            "service_id": "bra_cpf",
                            "service_name": "Brazil - CPF status check",
                            "source_data": {
                              "identification_number": "00987654321",
                              "first_name": "TOTALLY",
                              "last_name": "DIFFERENT NAME",
                              "date_of_birth": "1999-01-01",
                              "lgpd_minor": false,
                              "minor_under_16": false,
                              "minor_under_18": false
                            }
                          }
                        ],
                        "warnings": [
                          {
                            "feature": "DATABASE_VALIDATION",
                            "risk": "DATABASE_VALIDATION_NO_MATCH",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Database validation no match",
                            "long_description": "The system identified a no match in the database validation, requiring further investigation."
                          }
                        ]
                      },
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-06-11T10:31:00.000000+00:00"
                    }
                  },
                  "Stateless (save_api_request=false)": {
                    "summary": "`validations` collapses to a merged field map; nothing is stored",
                    "value": {
                      "request_id": "c4d5e6f7-8901-2345-6789-abcdef012345",
                      "database_validation": {
                        "status": "Approved",
                        "issuing_state": "BRA",
                        "validation_type": "one_by_one",
                        "screened_data": {
                          "tax_number": "12345678900",
                          "first_name": "John",
                          "last_name": "Doe",
                          "date_of_birth": "1980-01-01"
                        },
                        "match_type": "full_match",
                        "validations": {
                          "full_name": "full_match",
                          "date_of_birth": "full_match",
                          "identification_number": "full_match"
                        },
                        "warnings": []
                      },
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-06-11T10:32:00.000000+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error - nothing is billed. Preflight field errors occur before any external call. If every unanswered attempt explicitly refuses the input, the response instead includes `validation_errors` with `code: provider_rejected_input` and `retryable: false`; correct the input before retrying. Field-level problems use DRF's standard envelope; catalog problems return a `services` array (plus `requires_onboarding` or `services_requiring_consent` when relevant); missing-field errors include `fields_required_by` mapping each missing field to the services that demand it; services that need at least one extra identifier (e.g. `usa_states_credit_bureau`, which cannot verify a name alone) return `any_field_required_by` mapping each service to the fields of which at least one must be present; format problems checked per service return `invalid_fields_by_service`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid issuing_state": {
                    "summary": "Country not supported — message lists every valid alpha-3 code",
                    "value": {
                      "error": [
                        "Invalid issuing state. Valid options are: ARE, ARG, AUS, AUT, BEL, BGD, BOL, BRA, CAN, CHE, CHL, CHN, CIV, COL, CRI, CZE, DEU, DNK, DOM, ECU, ESP, FIN, FRA, GBR, GHA, GLB, GRC, GTM, HKG, HND, IDN, IND, IRL, ITA, KEN, KHM, MAR, MEX, MYS, NGA, NLD, NOR, NZL, OMN, PAN, PER, PHL, POL, PRT, PRY, QAT, SGP, SLV, SVK, SWE, THA, UGA, URY, USA, VEN, ZAF, ZMB, ZWE"
                      ]
                    }
                  },
                  "Missing required fields": {
                    "summary": "Union of required fields across selected services, with the universal-field hint",
                    "value": {
                      "error": [
                        "Missing required fields: tax_number (or use 'identification_number' which maps to 'tax_number' for BRA)"
                      ],
                      "fields_required_by": {
                        "tax_number": [
                          "bra_cpf"
                        ]
                      }
                    }
                  },
                  "Unknown service id": {
                    "summary": "`services` contains an id that is not in the catalog",
                    "value": {
                      "services": [
                        "Unknown service_id(s): ['bogus_service']"
                      ]
                    }
                  },
                  "Service not live for country": {
                    "summary": "`services` names a service from another country (or a stub entry)",
                    "value": {
                      "services": [
                        "Services not currently live for PER: ['bra_cpf']. Available services: ['per_dni', 'per_residential', 'per_tax_registration']"
                      ]
                    }
                  },
                  "Service requires onboarding": {
                    "summary": "Service exists but is not activated for your organization yet",
                    "value": {
                      "services": [
                        "Services require onboarding before they can be enabled for AUS: ['aus_australia_driver_licence']. Contact Didit support to activate them."
                      ],
                      "requires_onboarding": [
                        "aus_australia_driver_licence"
                      ]
                    }
                  },
                  "Consent missing": {
                    "summary": "A selected service is flagged requires_consent=true and `consent` was not `true`",
                    "value": {
                      "consent": [
                        "Explicit end-user consent is required for these database validation services: ['chn_national_id']. Send `consent=true`."
                      ],
                      "services_requiring_consent": [
                        "chn_national_id"
                      ]
                    }
                  },
                  "Country format rule violation": {
                    "summary": "Identifier fails the country's format rule (length/digits/regex)",
                    "value": {
                      "tax_number": [
                        "Invalid tax number for BRA: Brazilian CPF (exactly 11 digits). Must be exactly 11 characters long (got 10)."
                      ]
                    }
                  },
                  "Service-specific format violation": {
                    "summary": "A field fails the selected service's own format requirements",
                    "value": {
                      "error": [
                        "One or more fields do not match the format required by the selected service."
                      ],
                      "invalid_fields_by_service": {
                        "chn_national_id": [
                          "national_id_format"
                        ]
                      }
                    }
                  },
                  "Input refused by every attempt": {
                    "summary": "Correct the input before retrying",
                    "value": {
                      "error": "The source refused to run this query with the supplied input.",
                      "validation_errors": [
                        {
                          "service_id": "bra_cpf",
                          "code": "provider_rejected_input",
                          "message": "The source refused to run this query with the supplied input.",
                          "retryable": false
                        }
                      ]
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "error": {
                      "description": "Request-level explanation or preflight field errors.",
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ]
                    },
                    "validation_errors": {
                      "type": "array",
                      "description": "Present when every unanswered attempt refused the input after preflight.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "service_id": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          },
                          "retryable": {
                            "type": "boolean",
                            "description": "Whether retrying later can resolve this service failure. False means correct the supplied input first."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any screening or provider call happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "No selected service returned a usable result. Inspect each validation_errors entry before retrying; HTTP 502 alone does not establish a transient failure. An empty_provider_response with retryable: true indicates unavailable or unexplained results, including a refused primary followed by an unavailable fallback. Legacy provider_invalid_input and provider_validation_error entries instead require corrected input and may omit retryable. Nothing is billed. When save_api_request=true, the failed attempt is recorded as a session with status Not Finished. Partial failures return 200 with database_validation.errors.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "validation_errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "service_id": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          },
                          "retryable": {
                            "type": "boolean",
                            "description": "Whether retrying later can resolve this service failure. False means correct the supplied input first."
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Provider returned no result": {
                    "summary": "Every selected service failed",
                    "value": {
                      "error": "Database validation could not be performed. The external validation service did not return a result. Please try again later.",
                      "validation_errors": [
                        {
                          "service_id": "bra_cpf",
                          "code": "empty_provider_response",
                          "message": "The provider did not return a database validation result.",
                          "retryable": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/phone/send/": {
      "post": {
        "summary": "Send Phone Code",
        "description": "Send a one-time passcode (OTP) to a phone number over WhatsApp, SMS, or another supported channel, then verify it with [`POST /v3/phone/check/`](/standalone-apis/phone-check).\n\n**How send and check pair up.** Verification state is keyed by your application plus the E.164 `phone_number` — the check call does not take `request_id`. Each new send creates a pending verification that lives for **5 minutes**: call the check with the same number and the code the user received before the window closes. Calling send again for the same number while a verification is pending re-sends a code for that same verification (`status: \"Retry\"`, same `request_id`). At most one retry is attached this way (two sends total); a further send starts a fresh verification with a new `request_id`. The 5-minute window is measured from the first send and is not extended by retries.\n\n**Delivery channels.** `options.preferred_channel` selects the channel (`whatsapp` by default; `sms`, `telegram`, `voice`, `rcs`, `viber`, and `zalo` are also supported). When the preferred channel is unavailable for the destination country or number, delivery automatically falls back to SMS — the send still reports `Success`, and the channel actually used is reported by the check response (`phone.verification_method` and the `lifecycle` events).\n\n**Branding.** SMS codes carry your application's SMS sender name, set in the Business Console, at no extra cost. Pass `options.sms_sender_name` to sign one code with another name, or `options.use_white_label_customization: true` to fall back to your white-label public name when no sender name is set. WhatsApp codes use a fixed message and are not branded.\n\n**Send statuses.** `Success` — OTP sent for a new verification; `Retry` — OTP re-sent for the pending verification; `Blocked` — the anti-fraud layer refused to send (see `reason`, e.g. `repeated_attempts`, `suspicious`, `spam`). A `Blocked` send immediately finalizes the verification as `Declined` with a high-risk warning, so a follow-up check returns `Expired or Not Found`.\n\n**Billing.** The price depends on the destination country and the channel that actually delivers the message — see [Phone Verification Pricing](/getting-started/phone-verification-pricing). Only `Blocked` sends are guaranteed free: any other unbilled send attempt is charged at verification finalization or expiration, even if delivery was never confirmed or the delivery provider reported the message undeliverable. Checks are always free. As an anti-abuse measure, phone verification is disabled until your organization's first top-up (`403`).\n\n**Session persistence.** Every new verification is persisted as an API-type session: `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/`, the verification appears in the Business Console, and `status.updated` webhooks fire as it progresses.\n\n**Sandbox.** Sandbox API keys skip delivery and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Success` payload with a random `request_id`; no message is sent and nothing is persisted. Use code `123456` on the sandbox check.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limits.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints, plus an anti-abuse cap of 4 send attempts per phone number per hour; exceeding either returns `429`.",
        "operationId": "post_v3phone_send",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/phone/send/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"phone_number\": \"+14155552671\",\n    \"options\": {\n      \"code_size\": 6,\n      \"preferred_channel\": \"whatsapp\",\n      \"locale\": \"en-US\"\n    },\n    \"vendor_data\": \"user-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/phone/send/\",\n    headers={\n        \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"phone_number\": \"+14155552671\",\n        \"options\": {\n            \"code_size\": 6,\n            \"preferred_channel\": \"whatsapp\",\n            \"locale\": \"en-US\",\n        },\n        \"vendor_data\": \"user-1234\",\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nprint(resp.json())  # {request_id, status, reason, vendor_data, metadata}\n# Then verify with POST /v3/phone/check/ using the same phone_number"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/phone/send/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    phone_number: '+14155552671',\n    options: { code_size: 6, preferred_channel: 'whatsapp', locale: 'en-US' },\n    vendor_data: 'user-1234',\n  }),\n});\nif (!res.ok) throw new Error(`Phone send failed: ${res.status}`);\nconst data = await res.json();\nconsole.log(data); // { request_id, status, reason, vendor_data, metadata }\n// Then verify with POST /v3/phone/check/ using the same phone_number"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone_number": {
                    "type": "string",
                    "maxLength": 20,
                    "description": "Recipient phone number in E.164 format — leading `+` and country code (e.g., `+14155552671`). Numbers are validated and normalized to E.164; unparseable or invalid numbers return `400` with a `phone_number` field error.",
                    "example": "+14155552671"
                  },
                  "options": {
                    "type": "object",
                    "description": "OTP delivery options. All fields are optional.",
                    "properties": {
                      "code_size": {
                        "type": "integer",
                        "minimum": 4,
                        "maximum": 8,
                        "default": 6,
                        "description": "Number of digits in the OTP."
                      },
                      "locale": {
                        "type": "string",
                        "maxLength": 5,
                        "pattern": "^[a-z]{2,3}(-[A-Z]{2,3})?$",
                        "description": "BCP-47 locale used to localize the verification message (e.g., `en-US`, `fr`, `es`). Invalid formats return `400`.",
                        "example": "en-US"
                      },
                      "preferred_channel": {
                        "type": "string",
                        "enum": [
                          "whatsapp",
                          "sms",
                          "telegram",
                          "voice",
                          "rcs",
                          "viber",
                          "zalo"
                        ],
                        "default": "whatsapp",
                        "description": "Preferred delivery channel. If the channel is unavailable for the destination country or number, the message automatically falls back to SMS — the send still reports `Success`."
                      },
                      "use_white_label_customization": {
                        "type": "boolean",
                        "default": false,
                        "description": "When `true`, the send is white-labelled: if your application has no SMS sender name, the SMS names your white-label public name instead (\"123456 is your verification code for Acme Bank\"). Your SMS sender name, when set, is used with or without this flag. Applies to SMS messages, including an SMS fallback from another channel; WhatsApp codes are sent with a fixed message and are not branded. Defaults to `false`."
                      },
                      "sms_sender_name": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 30,
                        "example": "Acme Bank",
                        "description": "The name this code's SMS carries (\"123456 is your verification code for Acme Bank\"), instead of your application's SMS sender name. Free. 1 to 30 characters: letters, digits, spaces and ' & - ! only, not only digits, with single spaces between words; any other value returns `400` and no code is sent. Omitted, `null` or blank, your application's SMS sender name is used. Each application can start using up to two new names per day (UTC); past that, the code is sent with your application's name. Applies to SMS messages, including an SMS fallback from another channel; WhatsApp codes are not branded.",
                        "pattern": "^$|^(?![\\d ]+$)[\\p{L}\\p{N}'&!-]+( [\\p{L}\\p{N}'&!-]+)*$"
                      }
                    }
                  },
                  "signals": {
                    "type": "object",
                    "description": "Optional device and network signals about the end user, forwarded to the anti-fraud layer to improve detection of abusive or automated traffic. All fields are optional.",
                    "properties": {
                      "ip": {
                        "type": "string",
                        "description": "IP address of the end user's device. IPv4 or IPv6.",
                        "example": "192.0.2.1"
                      },
                      "device_id": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Unique identifier of the end user's device. Android: `ANDROID_ID`; iOS: `identifierForVendor`.",
                        "example": "8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2"
                      },
                      "device_platform": {
                        "type": "string",
                        "enum": [
                          "android",
                          "ios",
                          "ipados",
                          "tvos",
                          "web"
                        ],
                        "description": "Platform of the end user's device."
                      },
                      "device_model": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Model of the end user's device.",
                        "example": "iPhone17,2"
                      },
                      "os_version": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Operating-system version of the end user's device.",
                        "example": "18.0.1"
                      },
                      "app_version": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Version of your application.",
                        "example": "1.2.34"
                      },
                      "user_agent": {
                        "type": "string",
                        "maxLength": 512,
                        "description": "User agent of the end user's browser or app.",
                        "example": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1"
                      }
                    }
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional caller-controlled identifier (your internal user id, an email, a UUID, etc.) persisted on the session and echoed back in the send response, the matching check response, webhooks, and the Business Console. Use it to correlate Didit's `request_id` with your user record."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Optional free-form JSON object persisted on the session and echoed back in the send response, the matching check response, webhooks, and the Business Console."
                  }
                },
                "required": [
                  "phone_number"
                ]
              },
              "examples": {
                "WhatsApp (default)": {
                  "summary": "6-digit OTP via WhatsApp, falling back to SMS automatically",
                  "value": {
                    "phone_number": "+14155552671",
                    "options": {
                      "preferred_channel": "whatsapp",
                      "locale": "en-US"
                    },
                    "vendor_data": "user-1234"
                  }
                },
                "SMS with custom code length": {
                  "summary": "Force SMS delivery with a 4-digit code",
                  "value": {
                    "phone_number": "+34699999999",
                    "options": {
                      "preferred_channel": "sms",
                      "code_size": 4,
                      "locale": "es"
                    }
                  }
                },
                "With fraud signals": {
                  "summary": "Forward device signals to strengthen anti-fraud screening",
                  "value": {
                    "phone_number": "+14155552671",
                    "signals": {
                      "ip": "192.0.2.1",
                      "device_id": "8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2",
                      "device_platform": "ios",
                      "device_model": "iPhone17,2",
                      "os_version": "18.0.1",
                      "app_version": "1.2.34"
                    },
                    "vendor_data": "user-1234"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Send acknowledged. Inspect `status`: `Success` and `Retry` mean a code is on its way; `Blocked` means the anti-fraud layer refused and the verification is already finalized as `Declined`. `request_id` is the persisted session id (same id on a `Retry`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneVerificationSendResponse"
                },
                "examples": {
                  "Success": {
                    "summary": "OTP sent for a new verification",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Success",
                      "reason": null,
                      "vendor_data": "user-1234",
                      "metadata": null
                    }
                  },
                  "Retry": {
                    "summary": "Second send for the same number inside the 5-minute window — same request_id",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Retry",
                      "reason": null,
                      "vendor_data": "user-1234",
                      "metadata": null
                    }
                  },
                  "Blocked": {
                    "summary": "Anti-fraud refusal — verification finalized as Declined, nothing billed",
                    "value": {
                      "request_id": "0d8af1f4-0c43-46d7-b75c-6e4e22c0a7b3",
                      "status": "Blocked",
                      "reason": "repeated_attempts",
                      "vendor_data": "user-1234",
                      "metadata": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Malformed input returns DRF's field-error envelope (one array of messages per offending field, nested under `options` for option errors). A number that parses but is rejected at send time (unreachable, or an ineligible line type such as a short code) returns a `{\"detail\": ...}` envelope instead.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid phone number (field error)": {
                    "summary": "Number is not valid E.164",
                    "value": {
                      "phone_number": [
                        "Invalid phone number provided."
                      ]
                    }
                  },
                  "Missing phone number": {
                    "summary": "`phone_number` not included in the body",
                    "value": {
                      "phone_number": [
                        "This field is required."
                      ]
                    }
                  },
                  "Invalid options": {
                    "summary": "Out-of-range `code_size`, malformed `locale`, unknown `preferred_channel`",
                    "value": {
                      "options": {
                        "code_size": [
                          "Ensure this value is less than or equal to 8."
                        ],
                        "locale": [
                          "Ensure this field has no more than 5 characters."
                        ],
                        "preferred_channel": [
                          "\"carrier_pigeon\" is not a valid choice."
                        ]
                      }
                    }
                  },
                  "Number rejected at send time": {
                    "summary": "Valid E.164 shape but the number cannot receive an OTP",
                    "value": {
                      "detail": "Invalid phone number provided."
                    }
                  },
                  "Ineligible line type": {
                    "summary": "Line type cannot receive an OTP (e.g., short code)",
                    "value": {
                      "detail": "Invalid phone line type provided."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment (`{\"detail\": ...}`) — this API never returns `401`. Also returned before any send when the organization has never topped up (anti-abuse gate) or when its balance cannot cover the destination's send price (`{\"error\": ...}`).",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Top-up required": {
                    "summary": "Phone verification stays disabled until the organization's first top-up",
                    "value": {
                      "detail": "To protect against abuse, phone verification is disabled until your first top-up."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the send price",
                    "value": {
                      "error": "You don't have enough credits to perform this request."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. Additionally, an anti-abuse cap of 4 verification attempts per phone number per hour applies upstream. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers. Note: the `X-RateLimit-*`/`Retry-After` headers accompany only the 300/min write-limit 429; the per-number cap 429 carries no rate-limit headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Per-number cap": {
                    "summary": "More than 4 verification attempts for the same number in the last hour",
                    "value": {
                      "detail": "Maximum verification attempts reached for this phone number. Only 4 authentication attempts are allowed per hour. Try again later or use a different number."
                    }
                  },
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "The phone verification provider is temporarily unavailable - a 5xx response, timeout, or connection failure that survived the built-in retries. Safe to retry; nothing is billed and no attempt is consumed.",
            "content": {
              "application/json": {
                "examples": {
                  "Provider outage": {
                    "summary": "The provider did not answer the send request",
                    "value": {
                      "detail": "Phone verification is temporarily unavailable. Please try again shortly.",
                      "code": "phone_provider_unavailable"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected failure while creating the verification that is not a known provider outage. Safe to retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Provider error": {
                    "summary": "OTP delivery could not be initiated",
                    "value": {
                      "detail": "Error creating phone verification"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/phone/check/": {
      "post": {
        "summary": "Check Phone Code",
        "description": "Verify the OTP delivered by [`POST /v3/phone/send/`](/standalone-apis/phone-send) and get the final verification result plus phone intelligence: carrier name and line type, virtual (VoIP) and disposable flags, and duplicate usage of the number across your sessions.\n\n**How the check finds the verification.** Matching is by your application plus the E.164 `phone_number` — `request_id` is not an input. The most recent pending verification created within the last **5 minutes** is checked. If there is none (never sent, already finalized, or older than 5 minutes) the endpoint returns `200` with `status: \"Expired or Not Found\"`.\n\n**Attempt budget.** Each verification allows **3 code attempts**. The first two wrong codes return `status: \"Failed\"` with the attempts remaining and `phone: null`; the third wrong code finalizes the verification as `Declined` with a `VERIFICATION_CODE_ATTEMPTS_EXCEEDED` warning and returns the full phone report.\n\n**Outcomes.** `Approved` — correct code and no declining risk. `Declined` — terminal: the code was correct but a declining risk matched (a `DECLINE` action below, a blocklisted or high-risk number), or the attempt budget was exhausted. `Failed` — wrong code, attempts remaining. `Expired or Not Found` — nothing to check. On `Approved`/`Declined` the `request_id` equals the send's `request_id` (the session id) and `phone` carries the full report (`carrier`, `is_virtual`, `is_disposable`, `warnings`, `lifecycle`, `matches`); on `Failed` and `Expired or Not Found` the `request_id` is a one-off random UUID.\n\n**Risk actions.** `duplicated_phone_number_action`, `disposable_number_action`, and `voip_number_action` decide what happens when the corresponding risk is detected on a correct code: `DECLINE` flips the final status to `Declined`; `NO_ACTION` (default) records the risk in `phone.warnings` without affecting the status.\n\n**Billing.** Checks are free — delivery is billed on the send side (see [Phone Verification Pricing](/getting-started/phone-verification-pricing)).\n\n**Session persistence.** A finalized check updates the session created by the send (visible in the Business Console, queryable via `GET /v3/session/{sessionId}/decision/`) and fires a `status.updated` webhook.\n\n**Sandbox.** Sandbox API keys skip all processing: any well-formed code (4–8 digits, `123456` included) returns a static `Approved` payload with a simplified flat `phone` object (`status`, `phone_number`, `country_code`, `carrier_name`, `line_type`, `flags`); malformed input still returns `400`. Nothing is persisted.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limits.** Shared write budget of 300 requests/min per API key, plus the upstream anti-abuse cap of 4 attempts per number per hour; exceeding either returns `429`.\n\n**Social footprint.** Set `enable_social` to `true` to add a `phone_social` block: the online platforms this number is registered on, with per-category counts and any profile details available. `profiles_registered: 0` means the platforms were checked and the number was found on none of them - a valid, billable answer. The block is absent when the add-on was not requested or the check could not be completed, and it is not billed in that case. Billing adds one `phone_social` unit per request on top of this endpoint's own price.",
        "operationId": "post_v3phone_check",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/phone/check/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"phone_number\": \"+14155552671\",\n    \"code\": \"123456\",\n    \"voip_number_action\": \"DECLINE\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/phone/check/\",\n    headers={\n        \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"phone_number\": \"+14155552671\",  # same number as the send call\n        \"code\": \"123456\",\n        \"voip_number_action\": \"DECLINE\",\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result[\"status\"])  # Approved / Declined / Failed / Expired or Not Found\nif result[\"status\"] in (\"Approved\", \"Declined\"):\n    print(result[\"phone\"][\"carrier\"], result[\"phone\"][\"is_virtual\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/phone/check/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    phone_number: '+14155552671', // same number as the send call\n    code: '123456',\n    voip_number_action: 'DECLINE',\n  }),\n});\nconst data = await res.json();\nif (data.status === 'Approved') {\n  // full phone report is in data.phone (carrier, is_virtual, matches, ...)\n}"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phone_number": {
                    "type": "string",
                    "maxLength": 20,
                    "description": "The same phone number used in the matching [`POST /v3/phone/send/`](/standalone-apis/phone-send) call, in E.164 format. This is what links the check to the send.",
                    "example": "+14155552671"
                  },
                  "code": {
                    "type": "string",
                    "minLength": 4,
                    "maxLength": 8,
                    "pattern": "^[0-9]{4,8}$",
                    "description": "The OTP the end user received. Must be 4–8 numeric digits — anything else returns `400` without consuming an attempt. A well-formed but wrong code returns `200` with `status: \"Failed\"` and consumes one of the 3 attempts.",
                    "example": "123456"
                  },
                  "duplicated_phone_number_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when the same number was already used by a different user (different `vendor_data`) of your application. `DECLINE` flips the final `status` to `Declined`; `NO_ACTION` records the risk in `phone.warnings` and fills `phone.matches`."
                  },
                  "disposable_number_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when the carrier lookup flags the number as a temporary/burner line (`phone.is_disposable`). `DECLINE` flips the final `status` to `Declined`; `NO_ACTION` records the risk in `phone.warnings`."
                  },
                  "voip_number_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when the carrier lookup reports a virtual line type — `voip`, `isp`, or `vpn` (`phone.is_virtual`). `DECLINE` flips the final `status` to `Declined`; `NO_ACTION` records the risk in `phone.warnings`."
                  },
                  "enable_social": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, also look up the social footprint of the number - the messaging, social, e-commerce and professional platforms it is registered on. Billed as one `phone_social` unit per request in addition to this endpoint's own price.",
                    "example": true
                  },
                  "phone_no_social_presence_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "Action when the social footprint check finds the number registered on none of the platforms it covers. Only NO_ACTION and DECLINE are accepted on this endpoint; REVIEW is available on the workflow configuration key of the same name."
                  }
                },
                "required": [
                  "phone_number",
                  "code"
                ]
              },
              "examples": {
                "Default": {
                  "summary": "Record any risks but never auto-decline",
                  "value": {
                    "phone_number": "+14155552671",
                    "code": "123456"
                  }
                },
                "Strict risk policy": {
                  "summary": "Auto-decline VoIP and disposable lines",
                  "value": {
                    "phone_number": "+14155552671",
                    "code": "123456",
                    "voip_number_action": "DECLINE",
                    "disposable_number_action": "DECLINE"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check completed — wrong codes and missing verifications also return `200`; inspect `status`, not the HTTP code. `phone` is populated only on finalized outcomes (`Approved`/`Declined`), `null` on `Failed`, and absent on `Expired or Not Found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneVerificationCheckResponse"
                },
                "examples": {
                  "Approved": {
                    "summary": "Correct code — full phone report with carrier, lifecycle, and matches",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Approved",
                      "message": "The verification code is correct.",
                      "phone": {
                        "status": "Approved",
                        "phone_number_prefix": "+1",
                        "phone_number": "4155552671",
                        "full_number": "+14155552671",
                        "country_code": "US",
                        "country_name": "United States",
                        "carrier": {
                          "name": "AT&T",
                          "type": "mobile"
                        },
                        "is_disposable": false,
                        "is_virtual": false,
                        "verification_method": "whatsapp",
                        "verification_attempts": 1,
                        "verified_at": "2026-06-12T01:24:47.311323Z",
                        "warnings": [],
                        "lifecycle": [
                          {
                            "type": "PHONE_VERIFICATION_MESSAGE_SENT",
                            "timestamp": "2026-06-12T01:23:39.580554+00:00",
                            "details": {
                              "status": "Success",
                              "reason": null,
                              "channel": "whatsapp",
                              "actual_channel": "whatsapp"
                            },
                            "fee": 0.0709
                          },
                          {
                            "type": "PHONE_DELIVERY_DELIVERED",
                            "timestamp": "2026-06-12T01:23:43.118220+00:00",
                            "details": {
                              "channel": "whatsapp",
                              "status": "delivered"
                            },
                            "fee": 0
                          },
                          {
                            "type": "VALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:47.311201+00:00",
                            "details": {
                              "code_tried": "123456",
                              "status": "Approved"
                            },
                            "fee": 0
                          },
                          {
                            "type": "PHONE_VERIFICATION_APPROVED",
                            "timestamp": "2026-06-12T01:24:47.384292+00:00",
                            "details": null,
                            "fee": 0
                          }
                        ],
                        "matches": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.401719+00:00"
                    }
                  },
                  "Failed (attempts remaining)": {
                    "summary": "Wrong code — the user can retry; request_id here is a one-off UUID",
                    "value": {
                      "request_id": "11111111-2222-3333-4444-555555555555",
                      "status": "Failed",
                      "message": "The verification code is incorrect. Attempts remaining: 2",
                      "phone": null,
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:21.512340+00:00"
                    }
                  },
                  "Declined (max attempts)": {
                    "summary": "Third wrong code — verification finalized as Declined",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Declined",
                      "message": "The verification code is incorrect. Maximum attempts reached.",
                      "phone": {
                        "status": "Declined",
                        "phone_number_prefix": "+1",
                        "phone_number": "4155552671",
                        "full_number": "+14155552671",
                        "country_code": "US",
                        "country_name": "United States",
                        "carrier": {
                          "name": "AT&T",
                          "type": "mobile"
                        },
                        "is_disposable": false,
                        "is_virtual": false,
                        "verification_method": "whatsapp",
                        "verification_attempts": 1,
                        "verified_at": null,
                        "warnings": [
                          {
                            "feature": "PHONE",
                            "risk": "VERIFICATION_CODE_ATTEMPTS_EXCEEDED",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Verification code attempts exceeded",
                            "long_description": "The system detected that the phone number has exceeded the maximum number of verification code attempts."
                          }
                        ],
                        "lifecycle": [
                          {
                            "type": "PHONE_VERIFICATION_MESSAGE_SENT",
                            "timestamp": "2026-06-12T01:23:39.580554+00:00",
                            "details": {
                              "status": "Success",
                              "reason": null,
                              "channel": "whatsapp",
                              "actual_channel": "whatsapp"
                            },
                            "fee": 0.0709
                          },
                          {
                            "type": "INVALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:01.118220+00:00",
                            "details": {
                              "code_tried": "111111",
                              "status": "Failed"
                            },
                            "fee": 0
                          },
                          {
                            "type": "INVALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:21.512340+00:00",
                            "details": {
                              "code_tried": "222222",
                              "status": "Failed"
                            },
                            "fee": 0
                          },
                          {
                            "type": "INVALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:47.311201+00:00",
                            "details": {
                              "code_tried": "333333",
                              "status": "Failed"
                            },
                            "fee": 0
                          },
                          {
                            "type": "PHONE_VERIFICATION_DECLINED",
                            "timestamp": "2026-06-12T01:24:47.384292+00:00",
                            "details": {
                              "reason": "VERIFICATION_CODE_ATTEMPTS_EXCEEDED"
                            },
                            "fee": 0
                          }
                        ],
                        "matches": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.401719+00:00"
                    }
                  },
                  "Declined (risk policy)": {
                    "summary": "Correct code, but the line is VoIP and voip_number_action=DECLINE",
                    "value": {
                      "request_id": "7f1c9d2e-44a1-4b6e-9a3e-5b8e6f1c2d3a",
                      "status": "Declined",
                      "message": "The verification code is correct.",
                      "phone": {
                        "status": "Declined",
                        "phone_number_prefix": "+1",
                        "phone_number": "5005550006",
                        "full_number": "+15005550006",
                        "country_code": "US",
                        "country_name": "United States",
                        "carrier": {
                          "name": "CLEC LLC",
                          "type": "voip"
                        },
                        "is_disposable": false,
                        "is_virtual": true,
                        "verification_method": "sms",
                        "verification_attempts": 1,
                        "verified_at": "2026-06-12T01:24:47.311323Z",
                        "warnings": [
                          {
                            "feature": "PHONE",
                            "risk": "VOIP_NUMBER_DETECTED",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "VoIP number detected",
                            "long_description": "The system detected that the phone number is a VoIP number, which is not allowed."
                          }
                        ],
                        "lifecycle": [
                          {
                            "type": "PHONE_VERIFICATION_MESSAGE_SENT",
                            "timestamp": "2026-06-12T01:23:39.580554+00:00",
                            "details": {
                              "status": "Success",
                              "reason": null,
                              "channel": "whatsapp",
                              "actual_channel": "sms"
                            },
                            "fee": 0.0709
                          },
                          {
                            "type": "VALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:47.311201+00:00",
                            "details": {
                              "code_tried": "123456",
                              "status": "Approved"
                            },
                            "fee": 0
                          },
                          {
                            "type": "PHONE_VERIFICATION_DECLINED",
                            "timestamp": "2026-06-12T01:24:47.384292+00:00",
                            "details": {
                              "reason": "VOIP_NUMBER_DETECTED"
                            },
                            "fee": 0
                          }
                        ],
                        "matches": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.401719+00:00"
                    }
                  },
                  "Expired or Not Found": {
                    "summary": "No pending verification for this number in the last 5 minutes",
                    "value": {
                      "request_id": "69cc35c6-280a-47a6-ab8c-4f32abc02ed0",
                      "status": "Expired or Not Found",
                      "message": "No pending phone verification found in the last 5 minutes.",
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.311323+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — DRF's field-error envelope: one array of messages per offending field.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid code format": {
                    "summary": "`code` is not 4–8 numeric digits",
                    "value": {
                      "code": [
                        "Invalid code format. Enter 4 to 8 numeric digits."
                      ]
                    }
                  },
                  "Invalid phone number": {
                    "summary": "`phone_number` is not valid E.164",
                    "value": {
                      "phone_number": [
                        "Invalid phone number provided."
                      ]
                    }
                  },
                  "Invalid action": {
                    "summary": "Risk actions accept only NO_ACTION or DECLINE",
                    "value": {
                      "voip_number_action": [
                        "\"REVIEW\" is not a valid choice."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — this API never returns `401`. Checks are free, so there is no credit check here.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. Additionally, an anti-abuse cap of 4 verification attempts per phone number per hour applies upstream. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers. Note: the `X-RateLimit-*`/`Retry-After` headers accompany only the 300/min write-limit 429; the per-number cap 429 carries no rate-limit headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Per-number cap": {
                    "summary": "More than 4 verification attempts for the same number in the last hour",
                    "value": {
                      "detail": "Maximum verification attempts reached for this phone number. Only 4 authentication attempts are allowed per hour. Try again later or use a different number."
                    }
                  },
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "The phone verification provider is temporarily unavailable - a 5xx response, timeout, or connection failure that survived the built-in retries. Safe to retry; the attempt budget is not consumed.",
            "content": {
              "application/json": {
                "examples": {
                  "Provider outage": {
                    "summary": "The provider did not answer the check request",
                    "value": {
                      "detail": "Phone verification is temporarily unavailable. Please try again shortly.",
                      "code": "phone_provider_unavailable"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected failure while verifying the code upstream that is not a known provider outage. Safe to retry; the attempt budget is only consumed by completed checks.",
            "content": {
              "application/json": {
                "examples": {
                  "Provider error": {
                    "summary": "Code verification could not be completed",
                    "value": {
                      "detail": "Error checking phone verification"
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/email/send/": {
      "post": {
        "summary": "Send Email Code",
        "description": "Send a one-time passcode (OTP) to an email address, then verify it with [`POST /v3/email/check/`](/standalone-apis/email-check).\n\n**How send and check pair up.** Verification state is keyed by your application plus the `email` address — the check call does not take `request_id`. Each new send creates a pending verification that lives for **5 minutes**: call the check with the same address and the code the user received before the window closes. Calling send again for the same address while a verification is pending generates a fresh code for that same verification (`status: \"Retry\"`, same `request_id`); the previous code stops working. At most one retry is attached this way (two sends total); a further send starts a fresh verification with a new `request_id`. The 5-minute window is measured from the first send and is not extended by retries.\n\n**Deliverability pre-check.** Before anything is sent, the address goes through syntax and DNS/MX validation. Addresses that cannot receive mail return `200` with `status: \"Undeliverable\"` and `reason: \"email_can_not_be_delivered\"` — no email is sent, nothing is billed, and the verification is immediately finalized as `Declined` (a follow-up check returns `Expired or Not Found`). A downstream send failure reports the same way.\n\n**Code format and branding.** Codes are 4–8 characters (`options.code_size`, default 6), numeric by default; set `options.alphanumeric_code: true` for uppercase letters and digits (the check comparison is case-insensitive). The email template is localized via `options.locale` (54 supported languages) and can use your application's white-label branding via `options.use_white_label_customization`.\n\n**Billing.** One Email Verification API credit per successful send (`status: \"Success\"`), charged at send time. `Retry` and `Undeliverable` sends are free, and checks are free.\n\n**Session persistence.** Every new verification is persisted as an API-type session: `request_id` is a real session id you can pass to `GET /v3/session/{sessionId}/decision/`, the verification appears in the Business Console, and `status.updated` webhooks fire as it progresses.\n\n**Sandbox.** Sandbox API keys skip delivery and billing: after request validation (malformed input still returns `400`), the endpoint returns a static `Success` payload with a random `request_id`; no email is sent and nothing is persisted. Use code `123456` on the sandbox check.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.",
        "operationId": "post_v3email_send",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/email/send/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"email\": \"alice@example.com\",\n    \"options\": { \"code_size\": 6, \"locale\": \"en\" },\n    \"vendor_data\": \"user-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/email/send/\",\n    headers={\n        \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"email\": \"alice@example.com\",\n        \"options\": {\"code_size\": 6, \"locale\": \"en\"},\n        \"vendor_data\": \"user-1234\",\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nprint(resp.json())  # {request_id, status, reason, vendor_data, metadata}\n# Then verify with POST /v3/email/check/ using the same email"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/email/send/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    email: 'alice@example.com',\n    options: { code_size: 6, locale: 'en' },\n    vendor_data: 'user-1234',\n  }),\n});\nif (!res.ok) throw new Error(`Email send failed: ${res.status}`);\nconst data = await res.json();\nconsole.log(data); // { request_id, status, reason, vendor_data, metadata }\n// Then verify with POST /v3/email/check/ using the same email"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Recipient email address. Malformed addresses return `400`; syntactically valid addresses that cannot receive mail (failed DNS/MX validation) return `200` with `status: \"Undeliverable\"`.",
                    "example": "alice@example.com"
                  },
                  "options": {
                    "type": "object",
                    "description": "OTP format, localization, and branding options. All fields are optional.",
                    "properties": {
                      "code_size": {
                        "type": "integer",
                        "minimum": 4,
                        "maximum": 8,
                        "default": 6,
                        "description": "Number of characters in the OTP (digits by default; uppercase letters and digits when `alphanumeric_code` is `true`)."
                      },
                      "alphanumeric_code": {
                        "type": "boolean",
                        "default": false,
                        "description": "When `true`, the OTP is composed of uppercase letters `A–Z` and digits `0–9` instead of digits only. The `/v3/email/check/` comparison is case-insensitive."
                      },
                      "locale": {
                        "type": "string",
                        "maxLength": 5,
                        "enum": [
                          "en",
                          "ar",
                          "bn",
                          "bg",
                          "bs",
                          "ca",
                          "cs",
                          "da",
                          "de",
                          "el",
                          "es",
                          "et",
                          "fa",
                          "fi",
                          "fr",
                          "he",
                          "hi",
                          "hr",
                          "hu",
                          "hy",
                          "id",
                          "it",
                          "ja",
                          "ka",
                          "kk",
                          "ko",
                          "ky",
                          "lt",
                          "lv",
                          "cnr",
                          "mk",
                          "mn",
                          "ms",
                          "nl",
                          "no",
                          "pl",
                          "pt-BR",
                          "pt",
                          "ro",
                          "ru",
                          "sk",
                          "sl",
                          "so",
                          "sq",
                          "sr",
                          "sv",
                          "th",
                          "tr",
                          "uk",
                          "uz",
                          "vi",
                          "zh-CN",
                          "zh-TW",
                          "zh"
                        ],
                        "description": "Language of the OTP email template. Defaults to `en`. Unsupported values return `400` listing all supported locales.",
                        "example": "en"
                      },
                      "use_white_label_customization": {
                        "type": "boolean",
                        "default": false,
                        "description": "When `true`, the OTP email uses your application's white-label customization (logo, colors, sender branding) instead of the default Didit template."
                      }
                    }
                  },
                  "signals": {
                    "type": "object",
                    "description": "Optional device and network signals about the end user, forwarded to the anti-fraud layer to improve detection of abusive or automated traffic. All fields are optional.",
                    "properties": {
                      "ip": {
                        "type": "string",
                        "description": "IP address of the end user's device. IPv4 or IPv6.",
                        "example": "192.0.2.1"
                      },
                      "device_id": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Unique identifier of the end user's device. Android: `ANDROID_ID`; iOS: `identifierForVendor`.",
                        "example": "8F0B8FDD-C2CB-4387-B20A-56E9B2E5A0D2"
                      },
                      "device_platform": {
                        "type": "string",
                        "enum": [
                          "android",
                          "ios",
                          "ipados",
                          "tvos",
                          "web"
                        ],
                        "description": "Platform of the end user's device."
                      },
                      "device_model": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Model of the end user's device.",
                        "example": "iPhone17,2"
                      },
                      "os_version": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Operating-system version of the end user's device.",
                        "example": "18.0.1"
                      },
                      "app_version": {
                        "type": "string",
                        "maxLength": 64,
                        "description": "Version of your application.",
                        "example": "1.2.34"
                      },
                      "user_agent": {
                        "type": "string",
                        "maxLength": 512,
                        "description": "User agent of the end user's browser or app.",
                        "example": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1"
                      }
                    }
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Optional caller-controlled identifier (your internal user id, an email, a UUID, etc.) persisted on the session and echoed back in the send response, the matching check response, webhooks, and the Business Console. Use it to correlate Didit's `request_id` with your user record."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Optional free-form JSON object persisted on the session and echoed back in the send response, the matching check response, webhooks, and the Business Console."
                  }
                },
                "required": [
                  "email"
                ]
              },
              "examples": {
                "Numeric 6-digit code": {
                  "summary": "Default — 6-digit numeric code in English",
                  "value": {
                    "email": "alice@example.com",
                    "options": {
                      "locale": "en"
                    },
                    "vendor_data": "user-1234"
                  }
                },
                "Alphanumeric 8-character code": {
                  "summary": "Uppercase letters + digits, Spanish template",
                  "value": {
                    "email": "bob@example.com",
                    "options": {
                      "code_size": 8,
                      "alphanumeric_code": true,
                      "locale": "es"
                    }
                  }
                },
                "White-label branding": {
                  "summary": "Send the OTP email with your application's white-label customization",
                  "value": {
                    "email": "carol@example.com",
                    "options": {
                      "locale": "en",
                      "use_white_label_customization": true
                    },
                    "vendor_data": "user-5678"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Send acknowledged. Inspect `status`: `Success` and `Retry` mean a code is on its way; `Undeliverable` means the address cannot receive mail and the verification is already finalized as `Declined`. `request_id` is the persisted session id (same id on a `Retry`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailVerificationSendResponse"
                },
                "examples": {
                  "Success": {
                    "summary": "OTP emailed for a new verification (billed)",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Success",
                      "reason": null,
                      "vendor_data": "user-1234",
                      "metadata": null
                    }
                  },
                  "Retry": {
                    "summary": "Second send inside the 5-minute window — fresh code, same request_id, free",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Retry",
                      "reason": null,
                      "vendor_data": "user-1234",
                      "metadata": null
                    }
                  },
                  "Undeliverable": {
                    "summary": "Address failed DNS/MX validation — verification finalized as Declined, nothing billed",
                    "value": {
                      "request_id": "cb1a5011-344d-444d-bdce-218904745d7f",
                      "status": "Undeliverable",
                      "reason": "email_can_not_be_delivered",
                      "vendor_data": "user-1234",
                      "metadata": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — DRF's field-error envelope: one array of messages per offending field, nested under `options` for option errors.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid email": {
                    "summary": "Malformed email address",
                    "value": {
                      "email": [
                        "Enter a valid email address."
                      ]
                    }
                  },
                  "Unsupported locale": {
                    "summary": "`options.locale` outside the supported set",
                    "value": {
                      "options": {
                        "locale": [
                          "Invalid locale. Supported locales are en, ar, bn, bg, bs, ca, cs, da, de, el, es, et, fa, fi, fr, he, hi, hr, hu, hy, id, it, ja, ka, kk, ko, ky, lt, lv, cnr, mk, mn, ms, nl, no, pl, pt-BR, pt, ro, ru, sk, sl, so, sq, sr, sv, th, tr, uk, uz, vi, zh-CN, zh-TW, zh."
                        ]
                      }
                    }
                  },
                  "Code size out of range": {
                    "summary": "`options.code_size` outside 4–8",
                    "value": {
                      "options": {
                        "code_size": [
                          "Ensure this value is less than or equal to 8."
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment (`{\"detail\": ...}`) — this API never returns `401`. Also returned before any send when the organization's balance cannot cover one Email Verification API credit (`{\"error\": ...}`).",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the send price",
                    "value": {
                      "error": "You don't have enough credits to perform this request."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/email/check/": {
      "post": {
        "summary": "Check Email Code",
        "description": "Verify the OTP delivered by [`POST /v3/email/send/`](/standalone-apis/email-send) and get the final verification result plus email intelligence: deliverability, breach exposure (`is_breached` and the `breaches` list from a breach-intelligence database), disposable-provider detection, and duplicate usage of the address across your sessions.\n\n**How the check finds the verification.** Matching is by your application plus the `email` address — `request_id` is not an input. The most recent pending verification created within the last **5 minutes** is checked. If there is none (never sent, already finalized, undeliverable at send time, or older than 5 minutes) the endpoint returns `200` with `status: \"Expired or Not Found\"`.\n\n**Attempt budget.** Each verification allows **3 code attempts**. The first two wrong codes return `status: \"Failed\"` with the attempts remaining and `email: null`; the third wrong code finalizes the verification as `Declined` with an `EMAIL_CODE_ATTEMPTS_EXCEEDED` warning and returns the full email report. Codes are compared case-insensitively (relevant for `alphanumeric_code` sends); only the most recently sent code is valid.\n\n**Outcomes.** `Approved` — correct code and no declining risk. `Declined` — terminal: the code was correct but a declining risk matched (a `DECLINE` action below, a blocklisted address, or the address found undeliverable at finalization), or the attempt budget was exhausted. `Failed` — wrong code, attempts remaining. `Expired or Not Found` — nothing to check. On `Approved`/`Declined` the `request_id` equals the send's `request_id` (the session id) and `email` carries the full report (`is_breached`, `breaches`, `is_disposable`, `is_undeliverable`, `warnings`, `lifecycle`, `matches`); on `Failed` and `Expired or Not Found` the `request_id` is a one-off random UUID.\n\n**Risk actions.** `duplicated_email_action`, `breached_email_action`, and `disposable_email_action` decide what happens when the corresponding risk is detected on a correct code: `DECLINE` flips the final status to `Declined`; `NO_ACTION` (default) records the risk in `email.warnings` without affecting the status.\n\n**Billing.** Checks are free — the credit is consumed by the successful send.\n\n**Session persistence.** A finalized check updates the session created by the send (visible in the Business Console, queryable via `GET /v3/session/{sessionId}/decision/`) and fires a `status.updated` webhook.\n\n**Sandbox.** Sandbox API keys skip all processing: any well-formed code (`123456` included) returns a static `Approved` payload with a simplified `email` object (`status`, `email`, `is_breached`, `is_disposable`, `is_undeliverable`); malformed input still returns `400`. Nothing is persisted.\n\n**Authentication.** Send your application's API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`) — this API never returns `401`.\n\n**Rate limit.** Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.\n\n**Social footprint.** Set `enable_social` to `true` to add a `email_social` block: the online platforms this address is registered on, with per-category counts and any profile details available. `profiles_registered: 0` means the platforms were checked and the address was found on none of them - a valid, billable answer. The block is absent when the add-on was not requested or the check could not be completed, and it is not billed in that case. Billing adds one `email_social` unit per request on top of this endpoint's own price.",
        "operationId": "post_v3email_check",
        "tags": [
          "Standalone APIs"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/email/check/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"email\": \"alice@example.com\",\n    \"code\": \"123456\",\n    \"disposable_email_action\": \"DECLINE\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, requests\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/email/check/\",\n    headers={\n        \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"email\": \"alice@example.com\",  # same address as the send call\n        \"code\": \"123456\",\n        \"disposable_email_action\": \"DECLINE\",\n    },\n    timeout=15,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result[\"status\"])  # Approved / Declined / Failed / Expired or Not Found\nif result[\"status\"] in (\"Approved\", \"Declined\"):\n    print(result[\"email\"][\"is_breached\"], result[\"email\"][\"is_disposable\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/email/check/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    email: 'alice@example.com', // same address as the send call\n    code: '123456',\n    disposable_email_action: 'DECLINE',\n  }),\n});\nconst data = await res.json();\nif (data.status === 'Approved') {\n  // full email report is in data.email (breaches, is_disposable, matches, ...)\n}"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "The same email address used in the matching [`POST /v3/email/send/`](/standalone-apis/email-send) call. This is what links the check to the send.",
                    "example": "alice@example.com"
                  },
                  "code": {
                    "type": "string",
                    "maxLength": 10,
                    "description": "The OTP the end user received: 4–8 digits, or 4–8 letters/digits when `alphanumeric_code: true` was used at send time. Comparison is case-insensitive.",
                    "example": "123456"
                  },
                  "duplicated_email_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when the same address was already used and approved by a different user (only previously Approved verifications count) (different `vendor_data`) of your application. `DECLINE` flips the final `status` to `Declined`; `NO_ACTION` records the risk in `email.warnings` and fills `email.matches`."
                  },
                  "breached_email_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when the address appears in known data breaches (`email.is_breached`). `DECLINE` flips the final `status` to `Declined`; `NO_ACTION` records the risk in `email.warnings`."
                  },
                  "disposable_email_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "What to do when the domain belongs to a disposable/temporary-mail provider (`email.is_disposable`). `DECLINE` flips the final `status` to `Declined`; `NO_ACTION` records the risk in `email.warnings`."
                  },
                  "enable_social": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, also look up the social footprint of the address - the email, social, professional, e-commerce and entertainment platforms it is registered on. Billed as one `email_social` unit per request in addition to this endpoint's own price.",
                    "example": true
                  },
                  "email_no_social_presence_action": {
                    "type": "string",
                    "enum": [
                      "NO_ACTION",
                      "DECLINE"
                    ],
                    "default": "NO_ACTION",
                    "description": "Action when the social footprint check finds the address registered on none of the platforms it covers. Only NO_ACTION and DECLINE are accepted on this endpoint; REVIEW is available on the workflow configuration key of the same name."
                  }
                },
                "required": [
                  "email",
                  "code"
                ]
              },
              "examples": {
                "Default": {
                  "summary": "Record any risks but never auto-decline",
                  "value": {
                    "email": "alice@example.com",
                    "code": "123456"
                  }
                },
                "Strict risk policy": {
                  "summary": "Auto-decline disposable and breached inboxes",
                  "value": {
                    "email": "alice@example.com",
                    "code": "123456",
                    "disposable_email_action": "DECLINE",
                    "breached_email_action": "DECLINE"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check completed — wrong codes and missing verifications also return `200`; inspect `status`, not the HTTP code. `email` is populated only on finalized outcomes (`Approved`/`Declined`), `null` on `Failed`, and absent on `Expired or Not Found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailVerificationCheckResponse"
                },
                "examples": {
                  "Approved": {
                    "summary": "Correct code — clean address, full email report",
                    "value": {
                      "request_id": "e39cb057-92fc-4b59-b84e-02fec29a0f24",
                      "status": "Approved",
                      "message": "The verification code is correct.",
                      "email": {
                        "status": "Approved",
                        "email": "alice@example.com",
                        "is_breached": false,
                        "breaches": [],
                        "is_disposable": false,
                        "is_undeliverable": false,
                        "verification_attempts": 1,
                        "verified_at": "2026-06-12T01:24:47.311323Z",
                        "warnings": [],
                        "lifecycle": [
                          {
                            "type": "EMAIL_VERIFICATION_MESSAGE_SENT",
                            "timestamp": "2026-06-12T01:23:39.580554+00:00",
                            "details": {
                              "status": "Success",
                              "reason": null
                            },
                            "fee": 0.03
                          },
                          {
                            "type": "VALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:47.311201+00:00",
                            "details": {
                              "code_tried": "123456",
                              "status": "Approved"
                            },
                            "fee": 0
                          },
                          {
                            "type": "EMAIL_VERIFICATION_APPROVED",
                            "timestamp": "2026-06-12T01:24:47.384292+00:00",
                            "details": null,
                            "fee": 0
                          }
                        ],
                        "matches": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.401719+00:00"
                    }
                  },
                  "Approved with breach exposure": {
                    "summary": "Correct code; breach exposure recorded as a warning (breached_email_action=NO_ACTION)",
                    "value": {
                      "request_id": "3a1f2b6c-9d4e-4f7a-8b2c-1e5d6f7a8b9c",
                      "status": "Approved",
                      "message": "The verification code is correct.",
                      "email": {
                        "status": "Approved",
                        "email": "bob@example.com",
                        "is_breached": true,
                        "breaches": [
                          {
                            "name": "ExampleApp",
                            "domain": "exampleapp.com",
                            "breach_date": "2019-03-21",
                            "breach_emails_count": 763117,
                            "description": "In March 2019, the social platform ExampleApp suffered a data breach that exposed email addresses and passwords.",
                            "logo_path": "https://<media-host>/logos/ExampleApp.png",
                            "data_classes": [
                              "email_addresses",
                              "passwords"
                            ],
                            "is_verified": true
                          }
                        ],
                        "is_disposable": false,
                        "is_undeliverable": false,
                        "verification_attempts": 1,
                        "verified_at": "2026-06-12T01:24:47.311323Z",
                        "warnings": [
                          {
                            "feature": "EMAIL",
                            "risk": "BREACHED_EMAIL_DETECTED",
                            "additional_data": null,
                            "log_type": "information",
                            "short_description": "Breached email detected",
                            "long_description": "This email address was found in one or more known data breaches."
                          }
                        ],
                        "lifecycle": [
                          {
                            "type": "EMAIL_VERIFICATION_MESSAGE_SENT",
                            "timestamp": "2026-06-12T01:23:39.580554+00:00",
                            "details": {
                              "status": "Success",
                              "reason": null
                            },
                            "fee": 0.03
                          },
                          {
                            "type": "VALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:47.311201+00:00",
                            "details": {
                              "code_tried": "835126",
                              "status": "Approved"
                            },
                            "fee": 0
                          },
                          {
                            "type": "EMAIL_VERIFICATION_APPROVED",
                            "timestamp": "2026-06-12T01:24:47.384292+00:00",
                            "details": null,
                            "fee": 0
                          }
                        ],
                        "matches": []
                      },
                      "vendor_data": "user-5678",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.401719+00:00"
                    }
                  },
                  "Failed (attempts remaining)": {
                    "summary": "Wrong code — the user can retry; request_id here is a one-off UUID",
                    "value": {
                      "request_id": "11111111-2222-3333-4444-555555555555",
                      "status": "Failed",
                      "message": "The verification code is incorrect. Attempts remaining: 2",
                      "email": null,
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:21.512340+00:00"
                    }
                  },
                  "Declined (risk policy)": {
                    "summary": "Correct code, but the address is disposable and disposable_email_action=DECLINE",
                    "value": {
                      "request_id": "8c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                      "status": "Declined",
                      "message": "The verification code is correct.",
                      "email": {
                        "status": "Declined",
                        "email": "tempuser42@mailinator.com",
                        "is_breached": false,
                        "breaches": [],
                        "is_disposable": true,
                        "is_undeliverable": false,
                        "verification_attempts": 1,
                        "verified_at": "2026-06-12T01:24:47.311323Z",
                        "warnings": [
                          {
                            "feature": "EMAIL",
                            "risk": "DISPOSABLE_EMAIL_DETECTED",
                            "additional_data": null,
                            "log_type": "error",
                            "short_description": "Disposable email detected",
                            "long_description": "The system detected that the email is disposable, which is not allowed."
                          }
                        ],
                        "lifecycle": [
                          {
                            "type": "EMAIL_VERIFICATION_MESSAGE_SENT",
                            "timestamp": "2026-06-12T01:23:39.580554+00:00",
                            "details": {
                              "status": "Success",
                              "reason": null
                            },
                            "fee": 0.03
                          },
                          {
                            "type": "VALID_CODE_ENTERED",
                            "timestamp": "2026-06-12T01:24:47.311201+00:00",
                            "details": {
                              "code_tried": "123456",
                              "status": "Approved"
                            },
                            "fee": 0
                          },
                          {
                            "type": "EMAIL_VERIFICATION_DECLINED",
                            "timestamp": "2026-06-12T01:24:47.384292+00:00",
                            "details": {
                              "reason": "DISPOSABLE_EMAIL_DETECTED"
                            },
                            "fee": 0
                          }
                        ],
                        "matches": []
                      },
                      "vendor_data": "user-1234",
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:47.401719+00:00"
                    }
                  },
                  "Expired or Not Found": {
                    "summary": "No pending verification for this address in the last 5 minutes",
                    "value": {
                      "request_id": "88808a77-06e9-4cb0-85f5-9c052ddfd987",
                      "status": "Expired or Not Found",
                      "message": "No pending email verification found in the last 5 minutes.",
                      "vendor_data": null,
                      "metadata": null,
                      "created_at": "2026-06-12T01:24:59.887904+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — DRF's field-error envelope: one array of messages per offending field.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid email": {
                    "summary": "Malformed email address",
                    "value": {
                      "email": [
                        "Enter a valid email address."
                      ]
                    }
                  },
                  "Missing code": {
                    "summary": "`code` not included in the body",
                    "value": {
                      "code": [
                        "This field is required."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — this API never returns `401`. Checks are free, so there is no credit check here.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/workflows/": {
      "get": {
        "summary": "List workflows",
        "description": "List your workflows, newest first, in a limit/offset pagination envelope (`{count, next, previous, results}`, default page size 50). Each row is one version; `workflow_id` is the stable group ID and new sessions use the latest `published` version.",
        "operationId": "list_workflows",
        "tags": [
          "Workflows"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "Page size (number of workflows per page)."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of rows to skip before the first returned workflow."
          }
        ],
        "responses": {
          "200": {
            "description": "One page of workflows ordered by `created_at` descending, wrapped in the pagination envelope. Each item in `results` is a `WorkflowListItem`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Total number of workflow versions for the application."
                    },
                    "next": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "URL of the next page, or `null` on the last page."
                    },
                    "previous": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "URL of the previous page, or `null` on the first page."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WorkflowListItem"
                      }
                    }
                  }
                },
                "examples": {
                  "Two workflows": {
                    "summary": "A default KYC workflow and a draft KYC + AML workflow",
                    "value": {
                      "count": 2,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "uuid": "a1b2c3d4-5678-90ab-cdef-111111111111",
                          "workflow_id": "a1b2c3d4-5678-90ab-cdef-111111111111",
                          "workflow_label": "Standard KYC",
                          "workflow_type": "kyc",
                          "is_default": true,
                          "is_archived": false,
                          "is_white_label_enabled": false,
                          "total_price": 0.15,
                          "min_price": 0.15,
                          "max_price": 0.15,
                          "features": "OCR + LIVENESS + FACE_MATCH",
                          "is_simple_workflow": true,
                          "is_editable": false,
                          "workflow_url": "https://verify.didit.me/u/_yljPOx8RWG3UAz5ZRQGVQ",
                          "max_retry_attempts": 3,
                          "retry_window_days": 7,
                          "session_expiration_time": 604800,
                          "version": 2,
                          "status": "published",
                          "has_draft": false,
                          "created_by": {
                            "name": "Alex Mateo",
                            "email": "alex@example.com",
                            "type": "user"
                          },
                          "updated_at": "2026-04-12T10:30:00Z"
                        },
                        {
                          "uuid": "b2c3d4e5-6789-01bc-defa-222222222222",
                          "workflow_id": "b2c3d4e5-6789-01bc-defa-222222222222",
                          "workflow_label": "Full Verification + AML",
                          "workflow_type": "kyc",
                          "is_default": false,
                          "is_archived": false,
                          "is_white_label_enabled": false,
                          "total_price": 0.25,
                          "min_price": 0.25,
                          "max_price": 0.25,
                          "features": "OCR + LIVENESS + FACE_MATCH + AML",
                          "is_simple_workflow": true,
                          "is_editable": true,
                          "workflow_url": "https://verify.didit.me/u/Aq3kPOx8RWG3UAz5ZRQGVQ",
                          "max_retry_attempts": 3,
                          "retry_window_days": 7,
                          "session_expiration_time": 604800,
                          "version": 1,
                          "status": "draft",
                          "has_draft": true,
                          "created_by": null,
                          "updated_at": "2026-04-15T18:05:21Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The API key is missing, malformed, expired, or belongs to a different application. Body: `{\"detail\": \"You do not have permission to perform this action.\"}`. Refresh the token via the [Auth API](/auth-api/get-credentials) and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff and honour any `Retry-After` header."
          },
          "500": {
            "description": "Unexpected server error while building the list. The request can be safely retried."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET 'https://verification.didit.me/v3/workflows/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Accept: application/json'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.get(\n    \"https://verification.didit.me/v3/workflows/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    timeout=10,\n)\nresp.raise_for_status()\npage = resp.json()\nfor workflow in page[\"results\"]:\n    print(workflow[\"uuid\"], workflow[\"workflow_label\"], workflow[\"status\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(\"https://verification.didit.me/v3/workflows/\", {\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst page = await res.json();\npage.results.forEach((w) => console.log(w.uuid, w.workflow_label, w.status));"
          }
        ]
      },
      "post": {
        "summary": "Create workflow",
        "description": "Create a simple workflow. Send `features` in execution order (ordering rules apply); defaults to `published` v1. The body accepts ONLY the fields listed in `SimpleWorkflowRequest` — any other key (including `workflow_type`) is rejected with a 400. Not idempotent — each call creates a new workflow. Maximum 50 workflows per application.",
        "operationId": "create_workflow",
        "tags": [
          "Workflows"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimpleWorkflowRequest"
              },
              "examples": {
                "Simple KYC": {
                  "summary": "Linear ID, liveness, and face match workflow",
                  "value": {
                    "workflow_label": "Standard KYC",
                    "features": [
                      {
                        "feature": "OCR",
                        "config": {
                          "duplicated_user_action": "review"
                        }
                      },
                      {
                        "feature": "LIVENESS",
                        "config": {
                          "face_liveness_method": "passive"
                        }
                      },
                      {
                        "feature": "FACE_MATCH",
                        "config": {
                          "face_match_score_decline_threshold": 40,
                          "face_match_score_review_threshold": 60
                        }
                      }
                    ]
                  }
                },
                "KYC + AML": {
                  "summary": "Run AML after ID verification",
                  "value": {
                    "workflow_label": "KYC with AML",
                    "features": [
                      {
                        "feature": "OCR"
                      },
                      {
                        "feature": "AML",
                        "config": {
                          "aml_score_review_threshold": 70,
                          "aml_score_approve_threshold": 30
                        }
                      }
                    ]
                  }
                },
                "Questionnaire workflow": {
                  "summary": "Run a questionnaire created with POST /v3/questionnaires/",
                  "value": {
                    "workflow_label": "Source of Funds",
                    "features": [
                      {
                        "feature": "QUESTIONNAIRE",
                        "config": {
                          "questionnaire_uuid": "11111111-2222-3333-4444-555555555555",
                          "review_questionnaire_manually": true
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Workflow created. The response body is the FULL workflow configuration — the same raw `VerificationSettings` serialization returned by `GET /v3/workflows/{settings_uuid}/` (~190 fields: every feature toggle, threshold, action and the generated `workflow_graph`), not the compact list item. Store the `uuid` (also exposed as `workflow_id`) so you can reference it from later session-creation calls. Note: `features` is a `\" + \"`-joined string and prices are JSON numbers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Full workflow configuration (abbreviated here — see `GET /v3/workflows/{settings_uuid}/`).",
                  "additionalProperties": true
                },
                "examples": {
                  "Created (abbreviated)": {
                    "summary": "Key fields of the full configuration object",
                    "value": {
                      "uuid": "c3d4e5f6-7890-12cd-ef34-333333333333",
                      "workflow_id": "c3d4e5f6-7890-12cd-ef34-333333333333",
                      "workflow_label": "Standard KYC",
                      "workflow_type": null,
                      "is_default": false,
                      "is_archived": false,
                      "total_price": 0.15,
                      "min_price": 0.15,
                      "max_price": 0.15,
                      "features": "OCR + LIVENESS + FACE_MATCH",
                      "is_simple_workflow": false,
                      "is_editable": false,
                      "workflow_url": "https://verify.didit.me/u/w9TkPOx8RWG3UAz5ZRQGVQ",
                      "workflow_graph": {
                        "start_node": "ocr",
                        "nodes": "... one node per feature plus a final status node ..."
                      },
                      "max_retry_attempts": 3,
                      "retry_window_days": 7,
                      "session_expiration_time": 604800,
                      "version": 1,
                      "status": "published",
                      "published_at": "2026-05-17T10:30:00Z",
                      "created_at": "2026-05-17T10:30:00Z",
                      "updated_at": "2026-05-17T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Common causes: a top-level key outside the accepted whitelist (e.g. `workflow_type`), an unknown `feature` value, a feature placed before its dependency (e.g., `FACE_MATCH` before `OCR`), a passive feature (`AML`, `IP_ANALYSIS`, `DATABASE_VALIDATION`, `KYB_KEY_PEOPLE`) used as the first step, a `QUESTIONNAIRE` feature whose `config.questionnaire_uuid` does not exist for this application, or an out-of-range threshold. Body is a DRF validation error object — keys are field names, values are arrays of human-readable messages.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing feature": {
                    "value": {
                      "features": [
                        "At least one feature is required."
                      ]
                    }
                  },
                  "Unknown top-level field": {
                    "value": {
                      "workflow_type": [
                        "The v3 workflow API only accepts `workflow_label`, `is_default`, `status`, `features`, `is_white_label_enabled`, `is_desktop_allowed`, `max_retry_attempts`, `retry_window_days`, `session_expiration_time`, `face_liveness_max_attempts`, `face_match_max_attempts`."
                      ]
                    }
                  },
                  "Unknown feature": {
                    "value": {
                      "features": [
                        "Invalid feature 'FOO'. Allowed values: AGE_ESTIMATION, AML, DATABASE_VALIDATION, EMAIL_VERIFICATION, FACE_MATCH, IP_ANALYSIS, KYB_DOCUMENTS, KYB_KEY_PEOPLE, KYB_REGISTRY, LIVENESS, NFC, OCR, PHONE_VERIFICATION, PROOF_OF_ADDRESS, QUESTIONNAIRE."
                      ]
                    }
                  },
                  "Ordering": {
                    "value": {
                      "features": [
                        "Feature 'FACE_MATCH' must appear after one of: OCR."
                      ]
                    }
                  },
                  "Questionnaire not found": {
                    "value": {
                      "features": "Questionnaire '11111111-2222-3333-4444-555555555555' was not found for this application. Create the questionnaire first, then use its questionnaire_id."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The API key is missing, malformed, expired, or scoped to a different application. Refresh via the [Auth API](/auth-api/get-credentials) and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported media type. Set `Content-Type: application/json` and send a JSON body."
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error while creating the workflow. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/workflows/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"workflow_label\": \"Standard KYC\",\n    \"features\": [\n      {\"feature\": \"OCR\"},\n      {\"feature\": \"LIVENESS\", \"config\": {\"face_liveness_method\": \"passive\"}},\n      {\"feature\": \"FACE_MATCH\", \"config\": {\"face_match_score_decline_threshold\": 40, \"face_match_score_review_threshold\": 60}}\n    ]\n  }'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\npayload = {\n    \"workflow_label\": \"Standard KYC\",\n    \"features\": [\n        {\"feature\": \"OCR\"},\n        {\"feature\": \"LIVENESS\", \"config\": {\"face_liveness_method\": \"passive\"}},\n        {\"feature\": \"FACE_MATCH\"},\n    ],\n}\nresp = requests.post(\n    \"https://verification.didit.me/v3/workflows/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    json=payload,\n    timeout=10,\n)\nresp.raise_for_status()\nworkflow = resp.json()\nprint(\"Workflow id:\", workflow[\"uuid\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(\"https://verification.didit.me/v3/workflows/\", {\n  method: \"POST\",\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    workflow_label: \"Standard KYC\",\n    features: [\n      { feature: \"OCR\" },\n      { feature: \"LIVENESS\", config: { face_liveness_method: \"passive\" } },\n      { feature: \"FACE_MATCH\" },\n    ],\n  }),\n});\nif (!res.ok) throw new Error(`Didit ${res.status}: ${await res.text()}`);\nconst workflow = await res.json();\nconsole.log(\"Workflow id:\", workflow.uuid);"
          }
        ]
      }
    },
    "/v3/workflows/{settings_uuid}/": {
      "get": {
        "summary": "Get workflow",
        "description": "Fetch full configuration for one workflow version by `settings_uuid`: feature toggles, thresholds, allowed documents, graph, retry policy, callbacks, and pricing.",
        "operationId": "get_workflow",
        "tags": [
          "Workflows"
        ],
        "parameters": [
          {
            "name": "settings_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Per-version UUID of the workflow (the `uuid` value returned by the list endpoint). Each version of a workflow has its own `settings_uuid`."
          }
        ],
        "responses": {
          "200": {
            "description": "Full workflow configuration. The shape is the raw `VerificationSettings` serialization (~190 fields: every feature toggle, threshold, warning action, allowed-documents config, the `workflow_graph`, retry policy, callbacks and pricing). The example below is abbreviated. Notes: `features` is a `\" + \"`-joined string (e.g. `\"OCR + LIVENESS\"`), prices are JSON numbers, and `is_editable` is `true` only for `draft` versions.",
            "content": {
              "application/json": {
                "examples": {
                  "KYC workflow with face match (abbreviated)": {
                    "value": {
                      "uuid": "a1b2c3d4-5678-90ab-cdef-111111111111",
                      "workflow_id": "a1b2c3d4-5678-90ab-cdef-111111111111",
                      "workflow_label": "Standard KYC",
                      "workflow_type": "kyc",
                      "is_default": true,
                      "is_archived": false,
                      "is_liveness_enabled": true,
                      "face_liveness_method": "passive",
                      "face_liveness_score_decline_threshold": 50,
                      "face_liveness_score_review_threshold": 70,
                      "is_face_match_enabled": true,
                      "face_match_score_decline_threshold": 40,
                      "face_match_score_review_threshold": 60,
                      "is_aml_enabled": false,
                      "is_phone_verification_enabled": false,
                      "is_email_verification_enabled": false,
                      "is_database_validation_enabled": false,
                      "is_ip_analysis_enabled": false,
                      "is_nfc_enabled": false,
                      "duplicated_user_action": "no_action",
                      "documents_allowed": {
                        "ESP": {
                          "P": {
                            "sides": 1,
                            "enabled": 1,
                            "subtypes": [
                              "EPASSPORT",
                              "PASSPORT_GENERIC"
                            ],
                            "preferred_characters": "latin",
                            "expiration_check_mode": "strict"
                          }
                        }
                      },
                      "max_retry_attempts": 3,
                      "retry_window_days": 7,
                      "session_expiration_time": 604800,
                      "version": 2,
                      "status": "published",
                      "published_at": "2026-04-12T10:30:00Z",
                      "is_simple_workflow": false,
                      "is_editable": false,
                      "workflow_url": "https://verify.didit.me/u/_yljPOx8RWG3UAz5ZRQGVQ",
                      "total_price": 0.15,
                      "min_price": 0.15,
                      "max_price": 0.15,
                      "features": "OCR + LIVENESS + FACE_MATCH",
                      "created_at": "2025-01-15T10:30:00Z",
                      "updated_at": "2026-04-12T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key is missing, malformed, expired, or scoped to a different application.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No workflow with this `settings_uuid` exists for the authenticated application. Either the UUID is wrong or it belongs to another application — Didit deliberately does not distinguish the two cases to avoid leaking the existence of cross-application records.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET 'https://verification.didit.me/v3/workflows/a1b2c3d4-5678-90ab-cdef-111111111111/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.get(\n    f\"https://verification.didit.me/v3/workflows/{settings_uuid}/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    timeout=10,\n)\nresp.raise_for_status()\nworkflow = resp.json()\nprint(workflow[\"workflow_label\"], workflow[\"status\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(`https://verification.didit.me/v3/workflows/${settingsUuid}/`, {\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst workflow = await res.json();\nconsole.log(workflow.workflow_label, workflow.status);"
          }
        ]
      },
      "patch": {
        "summary": "Update workflow",
        "description": "Update a workflow. Versioning depends on the `status` field you send and the current state of the version: (1) no `status` on a **published** version → the published version is updated in place (same `uuid`, same `version`); (2) no `status` on a **draft** → the draft is updated and immediately published; (3) `status: \"published\"` on a **published** version → a NEW published version is created under the same `workflow_id` (new `uuid`, `version` + 1) and returned, and any existing draft in the group is deleted; (4) `status: \"draft\"` keeps a draft as a draft (autosave) but is rejected with 400 on a published version (`\"Cannot revert a published version to draft.\"`). The body accepts the same strict field whitelist as create — unknown keys are rejected with 400.",
        "operationId": "update_workflow",
        "tags": [
          "Workflows"
        ],
        "parameters": [
          {
            "name": "settings_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Per-version UUID of the workflow to update."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimpleWorkflowUpdateRequest"
              },
              "examples": {
                "Replace features": {
                  "summary": "Send the full desired feature order",
                  "value": {
                    "features": [
                      {
                        "feature": "OCR"
                      },
                      {
                        "feature": "AML"
                      }
                    ]
                  }
                },
                "Rename": {
                  "summary": "Rename a workflow",
                  "value": {
                    "workflow_label": "Premium KYC"
                  }
                },
                "Set as default": {
                  "summary": "Make this workflow the application's default",
                  "value": {
                    "is_default": true
                  }
                },
                "Update config": {
                  "summary": "Change feature configuration",
                  "value": {
                    "features": [
                      {
                        "feature": "OCR"
                      },
                      {
                        "feature": "LIVENESS",
                        "config": {
                          "face_liveness_method": "passive"
                        }
                      }
                    ]
                  }
                },
                "Publish a draft": {
                  "summary": "Promote a draft to published",
                  "value": {
                    "status": "published"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Workflow updated. The body is the FULL configuration of the resulting version (same raw `VerificationSettings` shape as `GET /v3/workflows/{settings_uuid}/`). When the update created a new version (`status: \"published\"` sent on a published row) the returned `uuid` and `version` differ from the ones you patched — use the returned `uuid` for subsequent calls.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Full workflow configuration (see `GET /v3/workflows/{settings_uuid}/`).",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Validation error — a top-level key outside the accepted whitelist, an unknown feature, invalid ordering, out-of-range threshold, referencing a non-existent questionnaire, or `status: \"draft\"` sent for a published version (`\"Cannot revert a published version to draft.\"`). The response body is a DRF validation error keyed by field name."
          },
          "403": {
            "description": "API key missing or invalid.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No workflow with this `settings_uuid` exists for the authenticated application."
          },
          "415": {
            "description": "Unsupported media type. Set `Content-Type: application/json`."
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/workflows/a1b2c3d4-5678-90ab-cdef-111111111111/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"workflow_label\": \"Premium KYC\"}'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.patch(\n    f\"https://verification.didit.me/v3/workflows/{settings_uuid}/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    json={\"workflow_label\": \"Premium KYC\"},\n    timeout=10,\n)\nresp.raise_for_status()\nprint(resp.json()[\"workflow_label\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(`https://verification.didit.me/v3/workflows/${settingsUuid}/`, {\n  method: \"PATCH\",\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ workflow_label: \"Premium KYC\" }),\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst workflow = await res.json();\nconsole.log(workflow.workflow_label);"
          }
        ]
      },
      "delete": {
        "summary": "Delete workflow",
        "description": "Permanently delete one workflow version (no undo). Existing sessions keep their verification results but their workflow reference is cleared; other versions in the same `workflow_id` group are not deleted.",
        "operationId": "delete_workflow",
        "tags": [
          "Workflows"
        ],
        "parameters": [
          {
            "name": "settings_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Per-version UUID of the workflow to delete."
          }
        ],
        "responses": {
          "204": {
            "description": "Workflow deleted. The response body is empty."
          },
          "403": {
            "description": "API key missing or invalid.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No workflow with this `settings_uuid` exists for the authenticated application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/workflows/a1b2c3d4-5678-90ab-cdef-111111111111/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.delete(\n    f\"https://verification.didit.me/v3/workflows/{settings_uuid}/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    timeout=10,\n)\nresp.raise_for_status()  # raises on 4xx/5xx; 204 is success"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(`https://verification.didit.me/v3/workflows/${settingsUuid}/`, {\n  method: \"DELETE\",\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (res.status !== 204) throw new Error(`Didit ${res.status}`);"
          }
        ]
      }
    },
    "/v3/questionnaires/": {
      "get": {
        "summary": "List questionnaires",
        "description": "List your questionnaires, newest first, in a limit/offset pagination envelope (`{count, next, previous, results}`, default page size 50). Each row is one version; `questionnaire_group_id` is the stable group ID resolved to the latest `published` version.",
        "operationId": "list_questionnaires",
        "tags": [
          "Questionnaires"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "Page size (number of questionnaires per page)."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Number of rows to skip before the first returned questionnaire."
          }
        ],
        "responses": {
          "200": {
            "description": "One page of questionnaires ordered by `created_at` descending, wrapped in the pagination envelope. Each item in `results` is a `QuestionnaireListItem`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Total number of questionnaire versions for the application."
                    },
                    "next": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "URL of the next page, or `null` on the last page."
                    },
                    "previous": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "URL of the previous page, or `null` on the first page."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/QuestionnaireListItem"
                      }
                    }
                  }
                },
                "examples": {
                  "One questionnaire": {
                    "summary": "A simple bilingual questionnaire",
                    "value": {
                      "count": 1,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "uuid": "11111111-2222-3333-4444-555555555555",
                          "title": "KYC Questionnaire",
                          "description": "Additional verification questions",
                          "languages": [
                            "en",
                            "es"
                          ],
                          "default_language": "en",
                          "is_active": true,
                          "is_simple_questionnaire": true,
                          "created_at": "2026-04-23T09:55:00Z",
                          "updated_at": "2026-04-23T10:00:00Z",
                          "question_types": [
                            "SHORT_TEXT",
                            "MULTIPLE_CHOICE",
                            "FILE_UPLOAD"
                          ],
                          "workflow_names": [],
                          "questionnaire_group_id": "11111111-2222-3333-4444-555555555555",
                          "version": 1,
                          "status": "published",
                          "published_at": "2026-04-23T10:00:00Z",
                          "is_editable": false
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error while building the list. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET 'https://verification.didit.me/v3/questionnaires/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.get(\n    \"https://verification.didit.me/v3/questionnaires/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    timeout=10,\n)\nresp.raise_for_status()\npage = resp.json()\nfor q in page[\"results\"]:\n    print(q[\"uuid\"], q[\"title\"], q[\"status\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(\"https://verification.didit.me/v3/questionnaires/\", {\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst page = await res.json();\npage.results.forEach((q) => console.log(q.uuid, q.title, q.status));"
          }
        ]
      },
      "post": {
        "summary": "Create questionnaire",
        "description": "Create a simple linear questionnaire. Send `form_elements` in display order; branching and repeatable groups require the Console. Defaults to `published` v1.",
        "operationId": "create_questionnaire",
        "tags": [
          "Questionnaires"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimpleQuestionnaireRequest"
              },
              "examples": {
                "Simple": {
                  "summary": "Basic questionnaire",
                  "value": {
                    "title": "Customer Onboarding",
                    "description": "Additional information needed for verification",
                    "default_language": "en",
                    "languages": [
                      "en"
                    ],
                    "is_active": true,
                    "form_elements": [
                      {
                        "id": "occupation",
                        "element_type": "short_text",
                        "label": {
                          "en": "What is your occupation?"
                        },
                        "is_required": true,
                        "placeholder": {
                          "en": "Software engineer"
                        }
                      },
                      {
                        "id": "source_of_funds",
                        "element_type": "multiple_choice",
                        "label": {
                          "en": "Source of funds"
                        },
                        "is_required": true,
                        "options": [
                          {
                            "value": "employment",
                            "label": {
                              "en": "Employment"
                            }
                          },
                          {
                            "value": "business",
                            "label": {
                              "en": "Business"
                            }
                          },
                          {
                            "value": "investments",
                            "label": {
                              "en": "Investments"
                            }
                          },
                          {
                            "value": "other",
                            "label": {
                              "en": "Other"
                            }
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Questionnaire created. The response includes the `questionnaire_id` — store it to reference this questionnaire from workflows or future update/delete calls.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuestionnaireDetail"
                },
                "examples": {
                  "Created": {
                    "value": {
                      "questionnaire_id": "11111111-2222-3333-4444-555555555555",
                      "title": "Customer Onboarding",
                      "description": "Additional information needed for verification",
                      "languages": [
                        "en"
                      ],
                      "default_language": "en",
                      "is_active": true,
                      "is_simple_questionnaire": true,
                      "graph": {
                        "start_node": "occupation",
                        "nodes": {
                          "occupation": {
                            "element_type": "SHORT_TEXT",
                            "is_required": true,
                            "title": {
                              "en": "What is your occupation?"
                            },
                            "next": "source_of_funds"
                          },
                          "source_of_funds": {
                            "element_type": "MULTIPLE_CHOICE",
                            "is_required": true,
                            "title": {
                              "en": "Source of funds"
                            },
                            "choices": [
                              {
                                "value": "employment",
                                "label": {
                                  "en": "Employment"
                                }
                              },
                              {
                                "value": "business",
                                "label": {
                                  "en": "Business"
                                }
                              }
                            ],
                            "next": null
                          }
                        }
                      },
                      "sections": [],
                      "questionnaire_group_id": "11111111-2222-3333-4444-555555555555",
                      "version": 1,
                      "status": "published",
                      "published_at": "2026-04-23T10:00:00Z",
                      "is_editable": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Common causes: an unknown `element_type`, a translatable field missing a translation for one of `languages`, `languages` missing `en`, `default_language` not in `languages`, an option without a `label`, a question that has `branches`/`required_if`/`repeatable_config` (not supported by this endpoint), or sending a raw `graph` instead of `form_elements`. The body is a DRF validation error keyed by field name.",
            "content": {
              "application/json": {
                "examples": {
                  "Graph not accepted": {
                    "value": {
                      "graph": "The v3 questionnaire API only accepts simple `form_elements`, not `graph`."
                    }
                  },
                  "Missing label": {
                    "value": {
                      "form_elements": [
                        {
                          "label": [
                            "This field is required."
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "Unsupported media type. Set `Content-Type: application/json` and send a JSON body."
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error while creating the questionnaire. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST 'https://verification.didit.me/v3/questionnaires/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"title\": \"Customer Onboarding\",\n    \"default_language\": \"en\",\n    \"languages\": [\"en\"],\n    \"form_elements\": [\n      {\n        \"id\": \"occupation\",\n        \"element_type\": \"short_text\",\n        \"label\": {\"en\": \"What is your occupation?\"},\n        \"is_required\": true\n      }\n    ]\n  }'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\npayload = {\n    \"title\": \"Customer Onboarding\",\n    \"default_language\": \"en\",\n    \"languages\": [\"en\"],\n    \"form_elements\": [\n        {\n            \"id\": \"occupation\",\n            \"element_type\": \"short_text\",\n            \"label\": {\"en\": \"What is your occupation?\"},\n            \"is_required\": True,\n        },\n    ],\n}\nresp = requests.post(\n    \"https://verification.didit.me/v3/questionnaires/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    json=payload,\n    timeout=10,\n)\nresp.raise_for_status()\nquestionnaire = resp.json()\nprint(\"Questionnaire id:\", questionnaire[\"questionnaire_id\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(\"https://verification.didit.me/v3/questionnaires/\", {\n  method: \"POST\",\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    title: \"Customer Onboarding\",\n    default_language: \"en\",\n    languages: [\"en\"],\n    form_elements: [\n      {\n        id: \"occupation\",\n        element_type: \"short_text\",\n        label: { en: \"What is your occupation?\" },\n        is_required: true,\n      },\n    ],\n  }),\n});\nif (!res.ok) throw new Error(`Didit ${res.status}: ${await res.text()}`);\nconst questionnaire = await res.json();\nconsole.log(\"Questionnaire id:\", questionnaire.questionnaire_id);"
          }
        ]
      }
    },
    "/v3/questionnaires/{questionnaire_uuid}/": {
      "get": {
        "summary": "Get questionnaire",
        "description": "Fetch full questionnaire detail for one version by `questionnaire_uuid`: title, `languages`, canonical `graph`, derived `sections`, and version metadata.",
        "operationId": "get_questionnaire",
        "tags": [
          "Questionnaires"
        ],
        "parameters": [
          {
            "name": "questionnaire_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Per-version UUID of the questionnaire (the `uuid` value returned by the list endpoint, also returned as `questionnaire_id` on detail endpoints)."
          }
        ],
        "responses": {
          "200": {
            "description": "Full questionnaire detail including the canonical `graph`, the derived `sections` view, version metadata, and `is_editable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuestionnaireDetail"
                },
                "examples": {
                  "Published questionnaire": {
                    "value": {
                      "questionnaire_id": "11111111-2222-3333-4444-555555555555",
                      "title": "Customer Onboarding",
                      "description": "Additional information needed for verification",
                      "languages": [
                        "en"
                      ],
                      "default_language": "en",
                      "is_active": true,
                      "is_simple_questionnaire": true,
                      "graph": {
                        "start_node": "occupation",
                        "nodes": {
                          "occupation": {
                            "element_type": "SHORT_TEXT",
                            "is_required": true,
                            "title": {
                              "en": "What is your occupation?"
                            },
                            "next": "source_of_funds"
                          },
                          "source_of_funds": {
                            "element_type": "MULTIPLE_CHOICE",
                            "is_required": true,
                            "title": {
                              "en": "Source of funds"
                            },
                            "choices": [
                              {
                                "value": "employment",
                                "label": {
                                  "en": "Employment"
                                }
                              },
                              {
                                "value": "business",
                                "label": {
                                  "en": "Business"
                                }
                              }
                            ],
                            "next": null
                          }
                        }
                      },
                      "sections": [
                        {
                          "title": {},
                          "description": {},
                          "items": [
                            {
                              "uuid": "11111111-2222-3333-4444-666666666666",
                              "value": "occupation",
                              "element_type": "SHORT_TEXT",
                              "is_required": true,
                              "title": {
                                "en": "What is your occupation?"
                              }
                            }
                          ]
                        }
                      ],
                      "questionnaire_group_id": "11111111-2222-3333-4444-555555555555",
                      "version": 1,
                      "status": "published",
                      "published_at": "2026-04-23T10:00:00Z",
                      "is_editable": false
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No questionnaire with this `questionnaire_uuid` exists for the authenticated application. Either the UUID is wrong or it belongs to another application — the API deliberately does not distinguish the two cases.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET 'https://verification.didit.me/v3/questionnaires/11111111-2222-3333-4444-555555555555/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.get(\n    f\"https://verification.didit.me/v3/questionnaires/{questionnaire_uuid}/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    timeout=10,\n)\nresp.raise_for_status()\nquestionnaire = resp.json()\nprint(questionnaire[\"title\"], questionnaire[\"status\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(`https://verification.didit.me/v3/questionnaires/${questionnaireUuid}/`, {\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst questionnaire = await res.json();\nconsole.log(questionnaire.title, questionnaire.status);"
          }
        ]
      },
      "patch": {
        "summary": "Update questionnaire",
        "description": "Update a questionnaire. Versioning depends on the `status` field you send and the current state of the version: (1) no `status` on a **published** version → the published version is updated in place (same `questionnaire_id`, same `version`); (2) no `status` on a **draft** → the draft is updated and immediately published; (3) `status: \"published\"` on a **published** version → a NEW published version is created under the same `questionnaire_group_id` (new `questionnaire_id`, `version` + 1) and returned, and any existing draft in the group is deleted; (4) `status: \"draft\"` keeps a draft as a draft (autosave) but is rejected with 400 on a published version (`\"Cannot revert a published version to draft.\"`).",
        "operationId": "update_questionnaire",
        "tags": [
          "Questionnaires"
        ],
        "parameters": [
          {
            "name": "questionnaire_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Per-version UUID of the questionnaire to update."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimpleQuestionnaireUpdateRequest"
              },
              "examples": {
                "Rename": {
                  "summary": "Rename a questionnaire",
                  "value": {
                    "title": "Updated Customer Onboarding"
                  }
                },
                "Replace questions": {
                  "summary": "Replace the full linear question list",
                  "value": {
                    "form_elements": [
                      {
                        "id": "occupation",
                        "element_type": "short_text",
                        "label": {
                          "en": "What is your occupation?"
                        },
                        "is_required": true
                      },
                      {
                        "id": "source_of_funds",
                        "element_type": "multiple_choice",
                        "label": {
                          "en": "Source of funds"
                        },
                        "options": [
                          {
                            "value": "employment",
                            "label": {
                              "en": "Employment"
                            }
                          },
                          {
                            "value": "business",
                            "label": {
                              "en": "Business"
                            }
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Questionnaire updated. The body is the latest state of the resulting version — the in-place updated version, or the newly created published version when you sent `status: \"published\"` on a published row (in that case `questionnaire_id` and `version` differ from the ones you patched). `questionnaire_id` in the response is the per-version UUID; use `questionnaire_group_id` if you need the stable group identifier.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuestionnaireDetail"
                }
              }
            }
          },
          "400": {
            "description": "Validation error — unknown `element_type`, missing translation, unsupported branching/conditional fields, `languages` missing `en`, `default_language` not in `languages`, option without a label, sending a raw `graph`, or `status: \"draft\"` on a published version (`\"Cannot revert a published version to draft.\"`). Response body is a DRF validation error keyed by field name."
          },
          "403": {
            "description": "API key missing or invalid.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No questionnaire with this `questionnaire_uuid` exists for the authenticated application."
          },
          "415": {
            "description": "Unsupported media type. Set `Content-Type: application/json`."
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/questionnaires/11111111-2222-3333-4444-555555555555/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"title\": \"Updated Customer Onboarding\"}'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.patch(\n    f\"https://verification.didit.me/v3/questionnaires/{questionnaire_uuid}/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    json={\"title\": \"Updated Customer Onboarding\"},\n    timeout=10,\n)\nresp.raise_for_status()\nprint(resp.json()[\"questionnaire_id\"], resp.json()[\"status\"])"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(`https://verification.didit.me/v3/questionnaires/${questionnaireUuid}/`, {\n  method: \"PATCH\",\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ title: \"Updated Customer Onboarding\" }),\n});\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst q = await res.json();\nconsole.log(q.questionnaire_id, q.status);"
          }
        ]
      },
      "delete": {
        "summary": "Delete questionnaire",
        "description": "Permanently delete one questionnaire version (no undo). Stored questionnaire responses linked to this version are deleted with it, and sessions referencing it lose the link; other versions in the same group are not deleted. Workflows that referenced it keep running but the questionnaire step can no longer load it.",
        "operationId": "delete_questionnaire",
        "tags": [
          "Questionnaires"
        ],
        "parameters": [
          {
            "name": "questionnaire_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Per-version UUID of the questionnaire to delete."
          }
        ],
        "responses": {
          "204": {
            "description": "Questionnaire deleted. The response body is empty."
          },
          "403": {
            "description": "API key missing or invalid.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No questionnaire with this `questionnaire_uuid` exists for the authenticated application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          },
          "500": {
            "description": "Unexpected server error. Safe to retry."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/questionnaires/11111111-2222-3333-4444-555555555555/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nresp = requests.delete(\n    f\"https://verification.didit.me/v3/questionnaires/{questionnaire_uuid}/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    timeout=10,\n)\nresp.raise_for_status()  # raises on 4xx/5xx; 204 is success"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const res = await fetch(`https://verification.didit.me/v3/questionnaires/${questionnaireUuid}/`, {\n  method: \"DELETE\",\n  headers: { 'x-api-key': 'YOUR_API_KEY' },\n});\nif (res.status !== 204) throw new Error(`Didit ${res.status}`);"
          }
        ]
      }
    },
    "/v3/users/": {
      "get": {
        "summary": "List users",
        "description": "List [users](/entities/users) Didit assembles from KYC sessions sharing the same `vendor_data` (free-form string, NOT a UUID), plus users created via the API. Paginated, ordered by `last_session_at` desc. This endpoint does not support filtering or search parameters — fetch pages and filter client-side.",
        "operationId": "list_users",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size. Defaults to 50 when omitted. There is no enforced maximum, but keep pages small for latency."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset of the first record to return. Prefer following the `next` URL from the previous page over computing this by hand."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/users/?limit=50' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/users/',\n    headers={'x-api-key': 'YOUR_API_KEY'},\n    params={'limit': 50},\n)\nresp.raise_for_status()\npage = resp.json()\nfor user in page['results']:\n    print(user['vendor_data'], user['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = new URL('https://verification.didit.me/v3/users/');\nurl.searchParams.set('limit', '50');\n\nconst page = await fetch(url, {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n}).then((r) => r.json());\n\nconsole.log(page.count, page.results.length);"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of users with verification status, session counts, and feature breakdown.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows — exact up to 100, capped at 100 beyond that for performance. Do not use it to detect the last page; rely on `next` being `null` instead."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or `null` on the last page."
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or `null` on the first page."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/UserListItem"
                      }
                    }
                  }
                },
                "examples": {
                  "Example": {
                    "value": {
                      "count": 2,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "didit_internal_id": "f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418",
                          "vendor_data": "user-abc-123",
                          "display_name": null,
                          "full_name": "John Michael Doe",
                          "date_of_birth": "1990-05-15",
                          "effective_name": "John Michael Doe",
                          "status": "ACTIVE",
                          "portrait_image_url": "https://<media-host>/...",
                          "session_count": 3,
                          "approved_count": 2,
                          "declined_count": 0,
                          "in_review_count": 1,
                          "issuing_states": [
                            "USA"
                          ],
                          "approved_emails": [
                            "john@example.com"
                          ],
                          "approved_phones": [
                            "+14155551234"
                          ],
                          "features": {
                            "ID_VERIFICATION": "Approved",
                            "LIVENESS": "Approved",
                            "FACE_MATCH": "Approved",
                            "AML": "Approved"
                          },
                          "features_list": [
                            {
                              "feature": "ID_VERIFICATION",
                              "status": "Approved"
                            },
                            {
                              "feature": "LIVENESS",
                              "status": "Approved"
                            },
                            {
                              "feature": "FACE_MATCH",
                              "status": "Approved"
                            },
                            {
                              "feature": "AML",
                              "status": "Approved"
                            }
                          ],
                          "last_session_at": "2025-06-15T10:30:00Z",
                          "last_activity_at": "2025-06-15T10:30:00Z",
                          "first_session_at": "2025-06-01T08:00:00Z",
                          "tags": [
                            {
                              "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                              "name": "VIP",
                              "color": "#2567FF"
                            }
                          ],
                          "created_at": "2025-06-01T08:00:00Z"
                        },
                        {
                          "didit_internal_id": "6ed99d53-e8f5-4cf8-9ac1-4a506cb40f6b",
                          "vendor_data": null,
                          "display_name": "Jane S.",
                          "full_name": "Jane Elizabeth Smith",
                          "date_of_birth": "1985-11-22",
                          "effective_name": "Jane S.",
                          "status": "FLAGGED",
                          "portrait_image_url": null,
                          "session_count": 1,
                          "approved_count": 0,
                          "declined_count": 0,
                          "in_review_count": 1,
                          "issuing_states": [],
                          "approved_emails": [],
                          "approved_phones": [],
                          "features": {
                            "ID_VERIFICATION": "In Review"
                          },
                          "features_list": [
                            {
                              "feature": "ID_VERIFICATION",
                              "status": "In Review"
                            }
                          ],
                          "last_session_at": "2025-06-20T14:00:00Z",
                          "last_activity_at": "2025-06-20T14:05:00Z",
                          "first_session_at": "2025-06-20T14:00:00Z",
                          "tags": [],
                          "created_at": "2025-06-20T14:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Invalid or revoked API key, or the key cannot list users for this application. Note: on this endpoint an *invalid* key returns `403` (not `401`).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/users/{vendor_data}/": {
      "get": {
        "summary": "Get user",
        "description": "Fetch one [user](/entities/users) by `vendor_data` (exact match). Adds `metadata`, `comments`, and `updated_at` to the list view, and switches `tags` to the detailed tag-link shape.",
        "operationId": "get_user",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the user — a free-form string (NOT a UUID). This is the same value you passed as `vendor_data` when creating the session that first introduced this user, matched exactly as sent.",
            "example": "user-abc-123"
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/users/user-abc-123/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/users/user-abc-123/',\n    headers={'x-api-key': 'YOUR_API_KEY'},\n)\nresp.raise_for_status()\nuser = resp.json()\nprint(user['didit_internal_id'], user['status'], user['session_count'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const vendorData = encodeURIComponent('user-abc-123');\nconst user = await fetch(\n  `https://verification.didit.me/v3/users/${vendorData}/`,\n  { headers: { 'x-api-key': process.env.DIDIT_API_KEY } },\n).then((r) => r.json());\n\nconsole.log(user.didit_internal_id, user.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "Full user detail including metadata, comments/activity log, and aggregated session data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserDetailItem"
                },
                "examples": {
                  "Active user": {
                    "value": {
                      "didit_internal_id": "f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418",
                      "vendor_data": "user-abc-123",
                      "display_name": null,
                      "full_name": "John Michael Doe",
                      "date_of_birth": "1990-05-15",
                      "effective_name": "John Michael Doe",
                      "status": "ACTIVE",
                      "metadata": {
                        "tier": "premium",
                        "source": "website"
                      },
                      "portrait_image_url": "https://<media-host>/...",
                      "session_count": 3,
                      "approved_count": 2,
                      "declined_count": 0,
                      "in_review_count": 1,
                      "issuing_states": [
                        "USA"
                      ],
                      "approved_emails": [
                        "john@example.com"
                      ],
                      "approved_phones": [
                        "+14155551234"
                      ],
                      "features": {
                        "ID_VERIFICATION": "Approved",
                        "LIVENESS": "Approved",
                        "FACE_MATCH": "Approved",
                        "AML": "Approved"
                      },
                      "features_list": [
                        {
                          "feature": "ID_VERIFICATION",
                          "status": "Approved"
                        },
                        {
                          "feature": "LIVENESS",
                          "status": "Approved"
                        },
                        {
                          "feature": "FACE_MATCH",
                          "status": "Approved"
                        },
                        {
                          "feature": "AML",
                          "status": "Approved"
                        }
                      ],
                      "last_session_at": "2025-06-15T10:30:00Z",
                      "last_activity_at": "2025-06-15T10:30:00Z",
                      "first_session_at": "2025-06-01T08:00:00Z",
                      "tags": [
                        {
                          "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                          "tag": {
                            "uuid": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
                            "name": "VIP",
                            "color": "#2567FF",
                            "description": null,
                            "source": "custom",
                            "created_at": "2025-05-01T09:00:00Z",
                            "updated_at": "2025-05-01T09:00:00Z"
                          },
                          "added_by_email": "analyst@acme.com",
                          "added_by_name": "Jane Analyst",
                          "created_at": "2025-06-02T11:00:00Z"
                        }
                      ],
                      "comments": [
                        {
                          "uuid": "c1111111-2222-4333-8444-555555555555",
                          "comment_type": "STATUS_CHANGED",
                          "comment": null,
                          "actor_email": "analyst@acme.com",
                          "actor_name": "Jane Analyst",
                          "previous_status": "FLAGGED",
                          "new_status": "ACTIVE",
                          "previous_value": null,
                          "new_value": null,
                          "changed_fields": [],
                          "metadata": null,
                          "mentioned_emails": [],
                          "created_at": "2025-06-01T10:30:00Z"
                        }
                      ],
                      "created_at": "2025-06-01T08:00:00Z",
                      "updated_at": "2025-06-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Invalid or revoked API key, or the key cannot read this application's users. Note: on this endpoint an *invalid* key returns `403` (not `401`).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No user with the supplied `vendor_data` exists for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update user",
        "description": "Partial update of a user: `display_name`, `full_name`, `date_of_birth`, `status`, `metadata`, `approved_emails`/`approved_phones`/`issuing_states`. `metadata` fully replaces. **Note:** unlike [Update User Status](#patch-/v3/users/-vendor_data-/update-status/), changing `status` here does NOT record a status-change activity and does NOT sync the system blocklist — use the dedicated update-status endpoint for `BLOCKED`/unblock flows.",
        "operationId": "update_user",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the user (free-form string, NOT a UUID).",
            "example": "user-abc-123"
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/users/user-abc-123/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"display_name\": \"Jane S.\", \"status\": \"FLAGGED\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.patch(\n    'https://verification.didit.me/v3/users/user-abc-123/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'display_name': 'Jane S.', 'status': 'FLAGGED'},\n)\nresp.raise_for_status()\nprint(resp.json()['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/users/user-abc-123/', {\n  method: 'PATCH',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ display_name: 'Jane S.', status: 'FLAGGED' }),\n});\nconst user = await resp.json();\nconsole.log(user.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "User updated. The full updated user record (same shape as Get User) is returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserDetailItem"
                },
                "examples": {
                  "Updated": {
                    "value": {
                      "didit_internal_id": "f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418",
                      "vendor_data": "user-abc-123",
                      "display_name": "Jane S.",
                      "full_name": "Jane Elizabeth Smith",
                      "date_of_birth": "1985-11-22",
                      "effective_name": "Jane S.",
                      "status": "FLAGGED",
                      "metadata": {
                        "tier": "premium"
                      },
                      "portrait_image_url": "https://<media-host>/...",
                      "session_count": 3,
                      "approved_count": 2,
                      "declined_count": 0,
                      "in_review_count": 1,
                      "issuing_states": [
                        "USA"
                      ],
                      "approved_emails": [
                        "john@example.com"
                      ],
                      "approved_phones": [
                        "+14155551234"
                      ],
                      "features": {
                        "ID_VERIFICATION": "Approved",
                        "LIVENESS": "Approved",
                        "FACE_MATCH": "Approved",
                        "AML": "Approved"
                      },
                      "features_list": [
                        {
                          "feature": "ID_VERIFICATION",
                          "status": "Approved"
                        },
                        {
                          "feature": "LIVENESS",
                          "status": "Approved"
                        },
                        {
                          "feature": "FACE_MATCH",
                          "status": "Approved"
                        },
                        {
                          "feature": "AML",
                          "status": "Approved"
                        }
                      ],
                      "last_session_at": "2025-06-15T10:30:00Z",
                      "last_activity_at": "2025-06-15T10:30:00Z",
                      "first_session_at": "2025-06-01T08:00:00Z",
                      "tags": [
                        {
                          "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                          "tag": {
                            "uuid": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
                            "name": "VIP",
                            "color": "#2567FF",
                            "description": null,
                            "source": "custom",
                            "created_at": "2025-05-01T09:00:00Z",
                            "updated_at": "2025-05-01T09:00:00Z"
                          },
                          "added_by_email": "analyst@acme.com",
                          "added_by_name": "Jane Analyst",
                          "created_at": "2025-06-02T11:00:00Z"
                        }
                      ],
                      "comments": [],
                      "created_at": "2025-06-01T08:00:00Z",
                      "updated_at": "2025-06-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body — typically an unknown `status` or a `date_of_birth` not in `YYYY-MM-DD`.",
            "content": {
              "application/json": {
                "examples": {
                  "Bad status": {
                    "value": {
                      "status": [
                        "\"INVALID\" is not a valid choice."
                      ]
                    }
                  },
                  "Bad date_of_birth": {
                    "value": {
                      "date_of_birth": [
                        "Date has wrong format. Use one of these formats instead: YYYY-MM-DD."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Invalid or revoked API key, or the key cannot update users for this application. Note: on this endpoint an *invalid* key returns `403` (not `401`).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No user with the supplied `vendor_data` exists for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "full_name": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 512,
                    "description": "Full name of the user"
                  },
                  "display_name": {
                    "type": "string",
                    "nullable": true,
                    "description": "Custom display name for this user"
                  },
                  "date_of_birth": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Date of birth in YYYY-MM-DD format"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "FLAGGED",
                      "BLOCKED"
                    ],
                    "description": "User lifecycle status. Changing it via this generic PATCH does NOT sync the system blocklist or record a status-change activity; prefer the update-status endpoint."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Arbitrary JSON object you attach to the user. **Fully replaces** the existing metadata on update — merge client-side if you only want to add keys."
                  },
                  "approved_emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Verified email addresses for this user, e.g. `[\"john@example.com\"]`. Fully replaces the stored list."
                  },
                  "approved_phones": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Verified phone numbers for this user. Fully replaces the stored list."
                  },
                  "issuing_states": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Issuing countries (ISO 3166-1 alpha-3), e.g. `[\"USA\"]`. Fully replaces the stored list."
                  }
                }
              },
              "examples": {
                "Rename": {
                  "summary": "Set display name",
                  "value": {
                    "display_name": "Jane S."
                  }
                },
                "Override status": {
                  "summary": "Flag the user for review",
                  "value": {
                    "status": "FLAGGED"
                  }
                },
                "Add metadata": {
                  "summary": "Replace metadata JSON",
                  "value": {
                    "metadata": {
                      "tier": "premium",
                      "risk_level": "low"
                    }
                  }
                },
                "Fix extracted DOB": {
                  "summary": "Correct extracted profile fields",
                  "value": {
                    "full_name": "Jane Elizabeth Smith",
                    "date_of_birth": "1985-11-22"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/users/{vendor_data}/generate-pdf/": {
      "get": {
        "summary": "Download the full user history PDF report",
        "description": "Render and download one compliance-ready PDF containing the full verification history of the user identified by `vendor_data`. It is the same document the Console produces from **User detail → Actions → Download PDF**, so periodic compliance exports no longer need a person clicking in the Console.\n\n**What the report contains.** A cover page with the profile summary (name, date of birth, issuing states, approved emails and phones), the latest status of every feature, the session counters and an index of the sessions included — followed by the standard report of every included session, in chronological order (oldest first). Each session report is the same document `GET /v3/session/{sessionId}/generate-pdf/` returns for that session.\n\n**Eligible sessions.** Only User Verification (KYC) sessions in `Approved`, `Declined`, `In Review` or `Kyc Expired` are included; sessions in any other status are skipped. If the user has no session in one of those statuses the endpoint returns `403` — see below.\n\n**Cap.** The report is capped at the **20 most recent** reportable sessions. When a user has more, the newest 20 are included and the cover page states how many older sessions were left out. Use `GET /v3/sessions/?vendor_data=…` for the complete list as JSON.\n\n**Branding.** If your application has white-label customization, the cover and every session report are rendered with your logo and privacy-policy URL; otherwise they carry Didit branding. Reports are rendered in English — there is no language parameter.\n\n**No caching.** Every call re-renders the PDF from the current data, so a report generated after a manual review reflects the reviewer's decision. Two calls for the same user can produce byte-different files — archive the downloaded file if you need an immutable copy.\n\n**Latency.** Rendering is synchronous and downloads every stored image of every included session, so a user with many media-heavy sessions can take tens of seconds. Use a generous client read timeout (120 s recommended) and stream the body to disk. Generation stops at a server-side time budget instead of running until your client gives up: if that budget is reached, the response is still a valid PDF containing the most recent sessions, and the cover states how many were omitted.\n\n**Scope.** The user is resolved inside the application that owns the API key. A key can never export a user of another application — such a user does not exist for it and the endpoint returns `404`.\n\n**Trailing slash.** The canonical route ends with a trailing slash (`…/generate-pdf/`). A request without it is served directly with the same response — there is no `301` redirect, so no client has to follow redirects and `curl` does not need `-L`. Use the slashed URL as in the samples.",
        "operationId": "get_user_generate_pdf",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the user — a free-form string (NOT a UUID). This is the same value you passed as `vendor_data` when creating the user's sessions, matched exactly as sent. URL-encode it; a value containing `/` cannot be addressed by this route.",
            "example": "user-abc-123"
          }
        ],
        "responses": {
          "200": {
            "description": "The rendered PDF document, returned directly as binary `application/pdf` — there is no JSON wrapper and no download-URL indirection. The body starts with the `%PDF` magic bytes. Save it to a `.pdf` file or stream it through to your caller.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=user_{didit_internal_id}.pdf` — the file is named after the user's stable Didit identifier (`didit_internal_id` on `GET /v3/users/{vendor_data}/`), not after `vendor_data`.",
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=user_f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418.pdf"
                }
              },
              "Content-Length": {
                "description": "Total size of the PDF in bytes; the body is not chunked.",
                "schema": {
                  "type": "integer",
                  "example": 148213
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Authorization or eligibility failure. Distinguish the two by the `detail` string:\n\n- `\"You do not have permission to perform this action.\"` — the API key is invalid or revoked, or the request carries a Console user token instead of an application API key.\n- `\"This user has no sessions in review, declined, approved or kyc expired to report.\"` — the user exists in your application but none of its sessions is in a reportable status yet (for example every session is still `In Progress`, or the user was created through `POST /v3/users/create/` and has never verified). Wait for a `status.updated` webhook before requesting the report.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "This user has no sessions in review, declined, approved or kyc expired to report."
                    }
                  }
                },
                "examples": {
                  "Invalid credentials": {
                    "summary": "Revoked or invalid API key, or a Console user token",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "No reportable sessions": {
                    "summary": "User exists but has no Approved / Declined / In Review / Kyc Expired session",
                    "value": {
                      "detail": "This user has no sessions in review, declined, approved or kyc expired to report."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No user with the supplied `vendor_data` exists in the application behind the API key. Users of other applications are invisible to this key and return the same `404`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "User not found."
                    }
                  }
                },
                "examples": {
                  "Unknown user": {
                    "summary": "vendor_data does not match any user of this application",
                    "value": {
                      "detail": "User not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. PDF generation has a dedicated limit of **50 requests per minute per credential** (API key, Bearer token, or source IP when unauthenticated), shared between this endpoint and `GET /v3/session/{sessionId}/generate-pdf/`, in addition to the global 600/min GET limit. Wait `Retry-After` seconds (also reflected in the `X-RateLimit-*` headers), then retry. Reports are not cached server-side, so download each report once and store the file instead of re-fetching it.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "minimum": 1,
                  "example": 30
                }
              },
              "X-RateLimit-Limit": {
                "description": "Maximum number of PDF generations allowed in the current window (50).",
                "schema": {
                  "type": "integer",
                  "example": 50
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests remaining in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the current window resets.",
                "schema": {
                  "type": "integer",
                  "example": 1750000000
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "description": "Human-readable explanation of the rate-limit breach.",
                      "example": "Session PDF generation rate limit exceeded. You can make up to 50 requests per minute."
                    }
                  }
                },
                "examples": {
                  "Throttled": {
                    "summary": "More than 50 PDF generations in one minute from the same credential",
                    "value": {
                      "detail": "Session PDF generation rate limit exceeded. You can make up to 50 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --fail \\\n  'https://verification.didit.me/v3/users/user-abc-123/generate-pdf/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  --output user-history.pdf"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.get(\n    \"https://verification.didit.me/v3/users/user-abc-123/generate-pdf/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"},\n    stream=True,\n    timeout=120,\n)\nresponse.raise_for_status()\nwith open(\"user-history.pdf\", \"wb\") as fh:\n    for chunk in response.iter_content(chunk_size=8192):\n        fh.write(chunk)"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "import { writeFile } from 'node:fs/promises';\n\nconst vendorData = encodeURIComponent('user-abc-123');\nconst response = await fetch(\n  `https://verification.didit.me/v3/users/${vendorData}/generate-pdf/`,\n  { headers: { 'x-api-key': process.env.DIDIT_API_KEY } },\n);\nif (!response.ok) throw new Error(`PDF generation failed: HTTP ${response.status}`);\nawait writeFile('user-history.pdf', Buffer.from(await response.arrayBuffer()));"
          }
        ]
      }
    },
    "/v3/users/delete/": {
      "post": {
        "summary": "Batch delete users",
        "description": "**Permanently delete** users — the user records are removed permanently. For everyday blocking prefer [Update User Status](#patch-/v3/users/-vendor_data-/update-status/) with `BLOCKED`. Select users with `vendor_data_list`, with `didit_internal_id_list`, or with both at once; or pass `delete_all: true`. The Console's `filter_*` batch params are rejected with a `400` rather than ignored, so a narrowed intent can never turn into a full wipe.\n\n**Biometric templates:** every image-free biometric template retained for these users after session deletion (see `/v3/biometric-templates/`) is purged before the user is deleted, so the person stops matching in duplicate detection and Face Search. If a template cannot be purged because a biometric store is unavailable, the call returns `503`, no user in the request is deleted, and repeating the request finishes the job.",
        "operationId": "batch_delete_users",
        "tags": [
          "Users"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Provide `vendor_data_list`, `didit_internal_id_list`, or `delete_all: true`. The two lists can be combined and are OR'd. When `delete_all` is `true` it takes precedence and both lists are ignored.",
                "properties": {
                  "vendor_data_list": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Your own identifiers to delete, matched exactly as sent."
                  },
                  "didit_internal_id_list": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Didit internal user IDs to delete - the `didit_internal_id` returned by the create and get endpoints."
                  },
                  "delete_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "If `true`, deletes every user in the application."
                  }
                }
              },
              "examples": {
                "Specific users": {
                  "summary": "Delete users by vendor_data",
                  "value": {
                    "vendor_data_list": [
                      "user-123",
                      "user-456"
                    ]
                  }
                },
                "By Didit internal ID": {
                  "summary": "Delete users by didit_internal_id",
                  "value": {
                    "didit_internal_id_list": [
                      "3f1c0d3e-8f0a-4c2e-9a3d-9b1f5f4a2c11"
                    ]
                  }
                },
                "All users": {
                  "summary": "Wipe every user in this application",
                  "value": {
                    "delete_all": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/users/delete/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"vendor_data_list\": [\"user-123\", \"user-456\"]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/users/delete/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'vendor_data_list': ['user-123', 'user-456']},\n)\nresp.raise_for_status()\nprint('deleted', resp.json()['deleted'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/users/delete/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ vendor_data_list: ['user-123', 'user-456'] }),\n});\nconst body = await resp.json();\nconsole.log('deleted', body.deleted);"
          }
        ],
        "responses": {
          "200": {
            "description": "Users deleted. Returns the number of users actually deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "integer",
                      "description": "Number of users deleted (excludes vendor_data values that didn't match anything)."
                    }
                  }
                },
                "examples": {
                  "Deleted some": {
                    "value": {
                      "deleted": 2
                    }
                  },
                  "Nothing matched": {
                    "value": {
                      "deleted": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No selector supplied (`vendor_data_list` missing/empty and `delete_all` not `true`). The error body is a JSON array.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing selector": {
                    "value": [
                      "Provide vendor_data_list or set delete_all=true."
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Invalid or revoked API key, or the key cannot delete users for this application. Note: on this endpoint an *invalid* key returns `403` (not `401`).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "A biometric store was unavailable while retaining or purging a biometric template. Nothing is deleted; repeat the same request. Retries are idempotent and converge on a single template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Retryable": {
                    "value": {
                      "detail": "The biometric-template operation could not finish because an external store is unavailable. The operation is retryable."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/sessions/delete/": {
      "post": {
        "summary": "Bulk delete KYC sessions by session_number",
        "description": "Bulk delete User Verification (KYC) sessions by their numeric `session_number`, or every KYC session in your application with `delete_all: true`.\n\n`session_number` is the human-friendly incrementing counter shown in the Console session list and returned as `session_number` by the create-session and decision endpoints; it is **not** the `session_id` UUID. To delete a session by UUID, or to delete a Business Verification (KYB) session, which this endpoint never touches, use `DELETE /v3/session/{sessionId}/delete/` instead.\n\n**Up to 20 sessions are deleted in the request, more run as a job.** The number of matching sessions decides, whether they are selected by `session_numbers` or with `delete_all`:\n- Up to 20 matching sessions: they are deleted before the response, which is `200` with one entry per session in `results[]`.\n- More than 20: the response is `202` with a deletion job, and the sessions are deleted in the background. Poll `GET /v3/sessions/delete/{job_id}/` until `status` is `COMPLETED` or `FAILED`. A job reports counts per outcome, never which sessions it deleted. A `delete_all` job deletes only the sessions created before the request; sessions started while it runs are not deleted.\n\nEach deleted session gets exactly the same treatment as the single-session delete endpoint: the session, every verification attempt it holds, its decision and extracted data, its related feature records (ID verification, face, liveness, face match, and so on) and all of its stored files are deleted, it disappears from every read endpoint, and previously issued media URLs stop resolving. Webhook deliveries still queued for a deleted session, and their retries, are dropped; webhooks already delivered are not affected. Blocklist entries are **not** removed, credits already consumed are **not** refunded, and the parent User entities are **not** deleted (use `POST /v3/users/delete/` for those); no webhook is emitted for the deletion. Deletion is permanent and irreversible.\n\n**Selection semantics:**\n- Entries in `session_numbers` that do not match a live KYC session in your application (unknown numbers, already-deleted sessions, or sessions owned by another application) are **silently skipped**: they do not appear in `results` and are not counted in a job's `total`.\n- Validation failures (a non-numeric entry, an empty list, neither `session_numbers` nor `delete_all` provided, or a template retention the application cannot honour) reject the **whole request** with `400` and delete nothing.\n- Sessions are deleted in groups. If a group cannot be deleted (for example because a storage service is unavailable), every session in that group is reported as `face_retention_outcome: failed_retryable` and stays in place; the other groups are unaffected. Repeat the request for those sessions. A job retries such a group by itself.\n- There is no documented cap on the list length; the shared write rate limit (below) is the practical bound.\n\n**Face biometric data:** the optional `retain_face_embeddings`, `face_retention_days`, `face_retention_deadline`, `deletion_instruction`, and `instruction_id` fields have the same meaning as on `DELETE /v3/session/{sessionId}/delete/` and apply to every matched session. Each result reports its own `face_retention_outcome`.\n\n**Response:** `200 OK` with `results[]` for up to 20 matching sessions, or `202 Accepted` with a deletion job for more. Every result confirms deletion except `face_retention_outcome: failed_retryable`, which reports a session that was NOT deleted and should be retried. Earlier versions of this endpoint returned `204 No Content`; update clients that assert on `204`.\n\n**Idempotency:** repeating the same request deletes nothing more: numbers that no longer match a session are skipped.\n\n**`delete_all: true` (destructive):** deletes **every** remaining KYC session in the application; `session_numbers` is ignored when set. There is no confirmation step and no undo.\n\n**Authentication:** API key in the `x-api-key` header. Missing or invalid credentials return `403` (`{\"detail\": \"You do not have permission to perform this action.\"}`); this API never returns `401`.\n\n**Rate limit:** shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns `429`.\n\nThis endpoint accepts API keys only. Business Console user Bearer tokens are rejected with `403` (unlike the single-session delete, which accepts both).",
        "operationId": "batch_delete_sessions",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_numbers": {
                    "type": "array",
                    "description": "Numeric `session_number` values of the KYC sessions to delete, as digit-only strings (JSON numbers are also accepted and coerced). Required unless `delete_all` is `true`; an empty list returns `400`. Any non-digit entry rejects the whole request with `400` (unless `delete_all` is `true`, in which case validation is skipped and the entries are ignored). Numbers that do not match a live session in your application are silently skipped.",
                    "items": {
                      "type": "string",
                      "pattern": "^[0-9]+$",
                      "example": "1001"
                    },
                    "minItems": 1,
                    "example": [
                      "1001",
                      "1002",
                      "1003"
                    ]
                  },
                  "delete_all": {
                    "type": "boolean",
                    "description": "When `true`, every remaining KYC session in the calling application is deleted and `session_numbers` is ignored. More than 20 matching sessions run as a deletion job (`202`) that covers only the sessions created before the request. Defaults to `false`. Irreversible; there is no confirmation step.",
                    "default": false,
                    "example": false
                  },
                  "retain_face_embeddings": {
                    "type": "boolean",
                    "nullable": true,
                    "description": "Override the application's `face_retention_policy` for this deletion. `true` keeps one image-free face biometric template anchored to the session's User after the session is deleted; `false` deletes the face embedding with the session; omit or `null` to follow the application policy. Ignored for KYB sessions and for sessions without a face embedding.",
                    "example": true
                  },
                  "face_retention_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3650,
                    "description": "Finite retention duration, in days, for a retained template. Required when a template is retained unless the application already sets `face_retention_days`. The template's `expires_at` is the earliest of this duration, the application's general data-retention window, and `face_retention_deadline`.",
                    "example": 365
                  },
                  "face_retention_deadline": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Optional hard expiry for a retained template. Must be in the future.",
                    "example": "2027-08-28T00:00:00Z"
                  },
                  "deletion_instruction": {
                    "type": "string",
                    "enum": [
                      "operational_session_delete",
                      "privacy_erasure"
                    ],
                    "default": "operational_session_delete",
                    "description": "The class of instruction you are giving. `operational_session_delete` deletes the session and retains a template only when the policy or `retain_face_embeddings` says so. `privacy_erasure` purges every retained biometric template anchored to the session's User before deleting the session, cannot be overridden by the application policy, and cannot be combined with `retain_face_embeddings: true` (`400`).",
                    "example": "operational_session_delete"
                  },
                  "instruction_id": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Your durable reference for this deletion instruction (for example an erasure-ticket id). Recorded on the audit trail and on any retained template. Generated by Didit when omitted.",
                    "example": "dsar-2026-0142"
                  }
                }
              },
              "examples": {
                "Specific sessions": {
                  "summary": "Delete specific sessions by number",
                  "value": {
                    "session_numbers": [
                      "1001",
                      "1002",
                      "1003"
                    ]
                  }
                },
                "All sessions": {
                  "summary": "Delete every KYC session in the application",
                  "value": {
                    "delete_all": true
                  }
                },
                "Delete and retain templates": {
                  "summary": "Delete sessions but keep image-free biometric templates for 365 days",
                  "value": {
                    "session_numbers": [
                      "1001",
                      "1002"
                    ],
                    "retain_face_embeddings": true,
                    "face_retention_days": 365,
                    "instruction_id": "post-approval-cleanup-2026-08"
                  }
                },
                "Privacy erasure": {
                  "summary": "Delete sessions and purge every retained template for their Users",
                  "value": {
                    "session_numbers": [
                      "1001"
                    ],
                    "deletion_instruction": "privacy_erasure",
                    "instruction_id": "dsar-2026-0142"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Up to 20 sessions matched and were processed in the request. One result per matched session; numbers that matched nothing (unknown or already deleted) are skipped and do not appear. A result confirms deletion except when `face_retention_outcome` is `failed_retryable`: that session was NOT deleted and should be retried.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "session_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The deleted session."
                          },
                          "session_number": {
                            "type": "integer",
                            "nullable": true,
                            "description": "The deleted session's number."
                          },
                          "face_retention_outcome": {
                            "type": "string",
                            "enum": [
                              "retained_with_user",
                              "deleted",
                              "none",
                              "ineligible_no_vendor_user",
                              "failed_retryable"
                            ],
                            "description": "What happened to the session's face biometric data. `deleted`: the face embedding was deleted with the session (default). `retained_with_user`: the session is deleted and one image-free biometric template stays anchored to the User; see `biometric_template_uuid`. `none`: the session had no face embedding (for example a document-only KYC session without a liveness selfie; KYB sessions are never selected by this endpoint). `ineligible_no_vendor_user`: retention was requested but the session has no linked User, so the embedding was deleted with the session. `failed_retryable` (batch endpoint only): the group this session was deleted with could not be deleted (a storage service, a biometric store, or a monitoring provider was unavailable); this session is still in place, repeat the request for it."
                          },
                          "biometric_template_uuid": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true,
                            "description": "Id of the retained biometric template when `face_retention_outcome` is `retained_with_user`; `null` otherwise. Manage it through `/v3/biometric-templates/{template_uuid}/`."
                          },
                          "biometric_template_expires_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true,
                            "description": "When the retained biometric template is deleted, when `face_retention_outcome` is `retained_with_user`; `null` when no template is retained."
                          },
                          "deleted_child_verifications": {
                            "type": "integer",
                            "description": "Always `0` on this endpoint, which deletes KYC sessions only. Deleting a Business Verification (KYB) session with `DELETE /v3/session/{sessionId}/delete/` reports the verifications it created that were deleted with it."
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Mixed outcomes": {
                    "value": {
                      "results": [
                        {
                          "session_id": "4c5c7f3a-3b1d-4b7e-9c39-2b4f7e6a1d02",
                          "session_number": 1001,
                          "face_retention_outcome": "deleted",
                          "biometric_template_uuid": null,
                          "biometric_template_expires_at": null,
                          "deleted_child_verifications": 0
                        },
                        {
                          "session_id": "b8e1d2c3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
                          "session_number": 1002,
                          "face_retention_outcome": "retained_with_user",
                          "biometric_template_uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                          "biometric_template_expires_at": "2027-10-09T10:15:00Z",
                          "deleted_child_verifications": 0
                        },
                        {
                          "session_id": "7a1e9c2d-5f4b-4c3a-8e2d-1b0a9f8e7d6c",
                          "session_number": 1003,
                          "face_retention_outcome": "ineligible_no_vendor_user",
                          "biometric_template_uuid": null,
                          "biometric_template_expires_at": null,
                          "deleted_child_verifications": 0
                        },
                        {
                          "session_id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                          "session_number": 1004,
                          "face_retention_outcome": "failed_retryable",
                          "biometric_template_uuid": null,
                          "biometric_template_expires_at": null,
                          "deleted_child_verifications": 0
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "More than 20 sessions matched. They are deleted in the background; poll `GET /v3/sessions/delete/{job_id}/` until `status` is `COMPLETED` or `FAILED`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "A bulk session deletion running in the background: progress and counts per outcome, never which sessions it deleted.",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Poll `GET /v3/sessions/delete/{job_id}/` with this id."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ],
                      "description": "`PENDING`: accepted, not started yet. `PROCESSING`: deleting; `processed` and `outcomes` are updating. `COMPLETED`: every selected session is accounted for. `FAILED`: the job stopped early; see `error`."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Sessions selected when the deletion was requested."
                    },
                    "processed": {
                      "type": "integer",
                      "description": "Sessions the job has finished with so far."
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "How many sessions ended in each outcome. Every key is always present.",
                      "properties": {
                        "deleted": {
                          "type": "integer",
                          "description": "Sessions deleted together with their face embedding."
                        },
                        "none": {
                          "type": "integer",
                          "description": "Sessions deleted that had no face embedding."
                        },
                        "retained_with_user": {
                          "type": "integer",
                          "description": "Sessions deleted while one image-free biometric template was retained for their User, as the request or the application policy asked."
                        },
                        "ineligible_no_vendor_user": {
                          "type": "integer",
                          "description": "Sessions deleted, with their face embedding, because retention was requested but they had no linked User."
                        },
                        "failed_retryable": {
                          "type": "integer",
                          "description": "Sessions reported as not deleted. A job retries a group it could not delete by itself instead of counting it here."
                        },
                        "already_deleted": {
                          "type": "integer",
                          "description": "Selected sessions that were already deleted, for example by another request, when the job reached them."
                        }
                      }
                    },
                    "deleted_child_verifications": {
                      "type": "integer",
                      "description": "Verifications that the deleted business verifications created, deleted with them. Always `0` for a job started by `POST /v3/sessions/delete/`, which deletes KYC sessions only."
                    },
                    "error": {
                      "type": "string",
                      "nullable": true,
                      "description": "`null` unless `status` is `FAILED`; then why the deletion stopped. The sessions the job had not reached are still in place: repeat the request to delete them."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the deletion was requested."
                    },
                    "completed_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "When the job finished; `null` while it runs."
                    }
                  }
                },
                "examples": {
                  "Job accepted": {
                    "value": {
                      "job_id": "5b8f2c1e-7d3a-4f6b-9e2c-1a0d8f7e6c5b",
                      "status": "PENDING",
                      "total": 250,
                      "processed": 0,
                      "outcomes": {
                        "deleted": 0,
                        "none": 0,
                        "retained_with_user": 0,
                        "ineligible_no_vendor_user": 0,
                        "failed_retryable": 0,
                        "already_deleted": 0
                      },
                      "deleted_child_verifications": 0,
                      "error": null,
                      "created_at": "2026-10-09T10:15:00Z",
                      "completed_at": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — nothing was deleted. Error values are arrays of message strings keyed by field name.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_numbers": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "examples": {
                  "Missing selector": {
                    "summary": "Neither session_numbers nor delete_all provided",
                    "value": {
                      "session_numbers": [
                        "This field is required unless delete_all is true."
                      ]
                    }
                  },
                  "Empty list": {
                    "summary": "session_numbers is an empty array",
                    "value": {
                      "session_numbers": [
                        "This list may not be empty."
                      ]
                    }
                  },
                  "Non-numeric entry": {
                    "summary": "session_numbers contains a non-digit string",
                    "value": {
                      "session_numbers": [
                        "All session_numbers must be numeric."
                      ]
                    }
                  },
                  "Privacy erasure cannot retain": {
                    "summary": "deletion_instruction privacy_erasure combined with retain_face_embeddings true",
                    "value": {
                      "retain_face_embeddings": [
                        "Privacy erasure cannot retain biometric templates."
                      ]
                    }
                  },
                  "No finite retention duration": {
                    "summary": "Retention requested without face_retention_days on the request or the application",
                    "value": {
                      "detail": "A finite biometric-template retention duration is required."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid API key. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No x-api-key header, or the key is invalid",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared write rate limit exceeded (300 POST/PATCH/DELETE requests per minute per API key). Inspect `Retry-After` and the `X-RateLimit-*` response headers before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Rate limited": {
                    "summary": "Write budget exhausted",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST \\\n  https://verification.didit.me/v3/sessions/delete/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"session_numbers\": [\"1001\", \"1002\", \"1003\"]\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/sessions/delete/\",\n    headers={\n        \"x-api-key\": \"YOUR_API_KEY\",\n        \"Content-Type\": \"application/json\",\n    },\n    json={\"session_numbers\": [\"1001\", \"1002\", \"1003\"]},\n)\nresponse.raise_for_status()\nif response.status_code == 202:  # more than 20 sessions: poll the job\n    job_id = response.json()[\"job_id\"]\nelse:  # 200: one result per matched session\n    print(response.json()[\"results\"])\n\n# Destructive: delete every KYC session in the application\n# requests.post(\n#     \"https://verification.didit.me/v3/sessions/delete/\",\n#     headers={\"x-api-key\": \"YOUR_API_KEY\"},\n#     json={\"delete_all\": True},\n# )"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/sessions/delete/',\n  {\n    method: 'POST',\n    headers: {\n      'x-api-key': 'YOUR_API_KEY',\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({ session_numbers: ['1001', '1002', '1003'] }),\n  },\n);\nif (response.status !== 200 && response.status !== 202) throw new Error(`HTTP ${response.status}`);\nconst body = await response.json();\n// 200: body.results, one per matched session. 202: poll /v3/sessions/delete/${body.job_id}/"
          }
        ]
      }
    },
    "/v3/sessions/delete/{job_id}/": {
      "get": {
        "summary": "Get a bulk session deletion job",
        "description": "Progress of a bulk session deletion that `POST /v3/sessions/delete/` answered with `202` (more than 20 matching sessions, selected by `session_numbers` or with `delete_all`). Poll every few seconds while `status` is `PENDING` or `PROCESSING`; stop when it is `COMPLETED` or `FAILED`.\n\nThe job reports how many sessions ended in each outcome and how many it has processed, never which sessions it deleted. A `FAILED` job carries the reason in `error`; the sessions it had not reached are still in place, so repeat the deletion request to delete them.\n\n**Authentication:** API key in the `x-api-key` header. A job is only visible to the application that created it; any other `job_id` returns `404`. Missing or invalid credentials return `403`; this API never returns `401`.",
        "operationId": "get_session_deletion_job",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The `job_id` returned with the `202` from `POST /v3/sessions/delete/`."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl 'https://verification.didit.me/v3/sessions/delete/JOB_ID/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import time\nimport requests\n\nurl = 'https://verification.didit.me/v3/sessions/delete/JOB_ID/'\nwhile True:\n    job = requests.get(url, headers={'x-api-key': 'YOUR_API_KEY'}).json()\n    if job['status'] in ('COMPLETED', 'FAILED'):\n        break\n    time.sleep(3)\nprint(job['status'], job['outcomes'], job['error'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = 'https://verification.didit.me/v3/sessions/delete/JOB_ID/';\nlet job;\ndo {\n  await new Promise((r) => setTimeout(r, 3000));\n  job = await (await fetch(url, { headers: { 'x-api-key': 'YOUR_API_KEY' } })).json();\n} while (job.status === 'PENDING' || job.status === 'PROCESSING');\nconsole.log(job.status, job.outcomes, job.error);"
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "A bulk session deletion running in the background: progress and counts per outcome, never which sessions it deleted.",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Poll `GET /v3/sessions/delete/{job_id}/` with this id."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ],
                      "description": "`PENDING`: accepted, not started yet. `PROCESSING`: deleting; `processed` and `outcomes` are updating. `COMPLETED`: every selected session is accounted for. `FAILED`: the job stopped early; see `error`."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Sessions selected when the deletion was requested."
                    },
                    "processed": {
                      "type": "integer",
                      "description": "Sessions the job has finished with so far."
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "How many sessions ended in each outcome. Every key is always present.",
                      "properties": {
                        "deleted": {
                          "type": "integer",
                          "description": "Sessions deleted together with their face embedding."
                        },
                        "none": {
                          "type": "integer",
                          "description": "Sessions deleted that had no face embedding."
                        },
                        "retained_with_user": {
                          "type": "integer",
                          "description": "Sessions deleted while one image-free biometric template was retained for their User, as the request or the application policy asked."
                        },
                        "ineligible_no_vendor_user": {
                          "type": "integer",
                          "description": "Sessions deleted, with their face embedding, because retention was requested but they had no linked User."
                        },
                        "failed_retryable": {
                          "type": "integer",
                          "description": "Sessions reported as not deleted. A job retries a group it could not delete by itself instead of counting it here."
                        },
                        "already_deleted": {
                          "type": "integer",
                          "description": "Selected sessions that were already deleted, for example by another request, when the job reached them."
                        }
                      }
                    },
                    "deleted_child_verifications": {
                      "type": "integer",
                      "description": "Verifications that the deleted business verifications created, deleted with them. Always `0` for a job started by `POST /v3/sessions/delete/`, which deletes KYC sessions only."
                    },
                    "error": {
                      "type": "string",
                      "nullable": true,
                      "description": "`null` unless `status` is `FAILED`; then why the deletion stopped. The sessions the job had not reached are still in place: repeat the request to delete them."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the deletion was requested."
                    },
                    "completed_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "When the job finished; `null` while it runs."
                    }
                  }
                },
                "examples": {
                  "Processing": {
                    "value": {
                      "job_id": "5b8f2c1e-7d3a-4f6b-9e2c-1a0d8f7e6c5b",
                      "status": "PROCESSING",
                      "total": 250,
                      "processed": 100,
                      "outcomes": {
                        "deleted": 82,
                        "none": 18,
                        "retained_with_user": 0,
                        "ineligible_no_vendor_user": 0,
                        "failed_retryable": 0,
                        "already_deleted": 0
                      },
                      "deleted_child_verifications": 0,
                      "error": null,
                      "created_at": "2026-10-09T10:15:00Z",
                      "completed_at": null
                    }
                  },
                  "Completed": {
                    "value": {
                      "job_id": "5b8f2c1e-7d3a-4f6b-9e2c-1a0d8f7e6c5b",
                      "status": "COMPLETED",
                      "total": 250,
                      "processed": 250,
                      "outcomes": {
                        "deleted": 204,
                        "none": 44,
                        "retained_with_user": 0,
                        "ineligible_no_vendor_user": 0,
                        "failed_retryable": 0,
                        "already_deleted": 2
                      },
                      "deleted_child_verifications": 0,
                      "error": null,
                      "created_at": "2026-10-09T10:15:00Z",
                      "completed_at": "2026-10-09T10:16:40Z"
                    }
                  },
                  "Failed": {
                    "value": {
                      "job_id": "5b8f2c1e-7d3a-4f6b-9e2c-1a0d8f7e6c5b",
                      "status": "FAILED",
                      "total": 250,
                      "processed": 100,
                      "outcomes": {
                        "deleted": 82,
                        "none": 18,
                        "retained_with_user": 0,
                        "ineligible_no_vendor_user": 0,
                        "failed_retryable": 0,
                        "already_deleted": 0
                      },
                      "deleted_child_verifications": 0,
                      "error": "The deletion stopped before it finished. The sessions it had not reached are still in place; repeat the request to delete them.",
                      "created_at": "2026-10-09T10:15:00Z",
                      "completed_at": "2026-10-09T10:15:52Z"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing or invalid API key. This API returns `403` for authentication failures, never `401`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No x-api-key header, or the key is invalid",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No deletion job with this `job_id` exists for the calling application. Jobs are only visible to the application that created them."
          }
        }
      }
    },
    "/v3/sessions/{session_id}/reviews/": {
      "get": {
        "summary": "List session reviews and activity log",
        "description": "Return the audit trail / activity feed for a User Verification (KYC) session, newest first, in a paginated envelope (`count` / `next` / `previous` / `results`, 50 entries per page by default).\n\nFeed entries are written by every actor that touches the session: manual decisions made through `PATCH /v3/session/{session_id}/update-status/` (which records `previous_status` → `new_status`), Console reviewer activity (comments with `@email` mentions, KYC/POA data edits, file uploads/removals, tag changes, detail-page views), AML ongoing-monitoring matches, and notes appended via `POST` on this same path. Reading this feed is the API-side equivalent of the **Activity** panel in the Didit Console session view.\n\nOnly User Verification (KYC) sessions are addressable here; Business Verification (KYB) session IDs return `404`.",
        "operationId": "list_session_reviews",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "description": "UUID of the User Verification (KYC) session. Must belong to the same application as the API key — cross-application UUIDs, deleted sessions, and Business Verification (KYB) session IDs all return `404`.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Defaults to `50`.",
            "schema": {
              "type": "integer",
              "default": 50,
              "example": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of entries to skip from the start of the (ordered) feed. Defaults to `0`. The `next` / `previous` URLs in the response carry the right values for walking the feed.",
            "schema": {
              "type": "integer",
              "default": 0,
              "example": 0
            }
          },
          {
            "name": "ordering",
            "in": "query",
            "required": false,
            "description": "Sort order. The feed defaults to newest first (`-created_at`); pass `created_at` to read it oldest first. Unknown values are silently ignored (default order is used); other serializer field names are also accepted.",
            "schema": {
              "type": "string",
              "default": "-created_at",
              "example": "created_at"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated activity feed, newest first by default. `count` is the total number of entries; `next` / `previous` are ready-made page URLs (`null` at the ends). A `count` of `0` with empty `results` means no activity has been recorded yet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Total number of feed entries for this session (across all pages).",
                      "example": 3
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "URL of the next page, or `null` on the last page.",
                      "example": null
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "URL of the previous page, or `null` on the first page.",
                      "example": null
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ReviewItem"
                      },
                      "description": "Feed entries for this page."
                    }
                  }
                },
                "examples": {
                  "DecisionTrail": {
                    "summary": "Manual approval plus API-added notes",
                    "value": {
                      "count": 3,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "uuid": "de0561bc-5583-4409-9171-1a31a4c8a5f4",
                          "activity_type": "STATUS_UPDATED",
                          "actor_display": "API Client",
                          "actor_email": null,
                          "actor_type": "API_KEY",
                          "new_status": "Approved",
                          "previous_status": "In Review",
                          "comment": "Document re-checked manually; address matches.",
                          "mentioned_emails": [],
                          "previous_value": {
                            "status": "In Review"
                          },
                          "new_value": {
                            "status": "Approved"
                          },
                          "changed_fields": [
                            "status"
                          ],
                          "metadata": null,
                          "created_at": "2026-06-12T00:19:31.918735Z"
                        },
                        {
                          "uuid": "35370f58-5098-44ee-8a06-8c9af80b2455",
                          "activity_type": "STATUS_UPDATED",
                          "actor_display": "Unknown",
                          "actor_email": null,
                          "actor_type": "CONSOLE_USER",
                          "new_status": null,
                          "previous_status": null,
                          "comment": "Note without status.",
                          "mentioned_emails": [],
                          "previous_value": null,
                          "new_value": null,
                          "changed_fields": [],
                          "metadata": null,
                          "created_at": "2026-06-12T00:18:44.504157Z"
                        },
                        {
                          "uuid": "00338f82-f1c5-4f57-8614-c49bb258af1a",
                          "activity_type": "STATUS_UPDATED",
                          "actor_display": "Unknown",
                          "actor_email": null,
                          "actor_type": "CONSOLE_USER",
                          "new_status": "In Review",
                          "previous_status": null,
                          "comment": "Flagging for manual document re-check.",
                          "mentioned_emails": [],
                          "previous_value": null,
                          "new_value": null,
                          "changed_fields": [],
                          "metadata": null,
                          "created_at": "2026-06-12T00:18:44.466537Z"
                        }
                      ]
                    }
                  },
                  "PaginatedFirstPage": {
                    "summary": "First page with limit=2 — next holds the follow-up URL",
                    "value": {
                      "count": 4,
                      "next": "https://verification.didit.me/v3/sessions/8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d/reviews/?limit=2&offset=2",
                      "previous": null,
                      "results": [
                        {
                          "uuid": "de0561bc-5583-4409-9171-1a31a4c8a5f4",
                          "activity_type": "STATUS_UPDATED",
                          "actor_display": "API Client",
                          "actor_email": null,
                          "actor_type": "API_KEY",
                          "new_status": "Approved",
                          "previous_status": "In Review",
                          "comment": "Document re-checked manually; address matches.",
                          "mentioned_emails": [],
                          "previous_value": {
                            "status": "In Review"
                          },
                          "new_value": {
                            "status": "Approved"
                          },
                          "changed_fields": [
                            "status"
                          ],
                          "metadata": null,
                          "created_at": "2026-06-12T00:19:31.918735Z"
                        },
                        {
                          "uuid": "bd4e6227-bdd2-42b2-a726-1d12f785a457",
                          "activity_type": "STATUS_UPDATED",
                          "actor_display": "Unknown",
                          "actor_email": null,
                          "actor_type": "CONSOLE_USER",
                          "new_status": null,
                          "previous_status": null,
                          "comment": null,
                          "mentioned_emails": [],
                          "previous_value": null,
                          "new_value": null,
                          "changed_fields": [],
                          "metadata": null,
                          "created_at": "2026-06-12T00:18:44.540238Z"
                        }
                      ]
                    }
                  },
                  "Empty": {
                    "summary": "Session with no recorded activity yet",
                    "value": {
                      "count": 0,
                      "next": null,
                      "previous": null,
                      "results": []
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, malformed, expired, or revoked `x-api-key`. Authentication is checked before the session lookup, so an invalid key returns `403` even when the session UUID does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "You do not have permission to perform this action."
                    }
                  }
                },
                "examples": {
                  "InvalidKey": {
                    "summary": "Missing or invalid x-api-key header",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No User Verification (KYC) session with this UUID is visible to your application: the UUID does not exist, the session was deleted, or it belongs to a different application. Business Verification (KYB) session IDs also return `404` here — the reviews feed is only addressable for KYC sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "Session not found."
                    }
                  }
                },
                "examples": {
                  "NotFound": {
                    "summary": "Unknown, deleted, or cross-application session UUID",
                    "value": {
                      "detail": "Session not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Inspect `Retry-After` and `X-RateLimit-*` response headers. See [Rate limiting](/integration/rate-limiting)."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -s 'https://verification.didit.me/v3/sessions/8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d/reviews/?limit=50' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import os, requests\n\nsession_id = \"8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d\"\nurl = f\"https://verification.didit.me/v3/sessions/{session_id}/reviews/\"\n\nwhile url:  # walk every page of the feed\n    resp = requests.get(url, headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]}, timeout=10)\n    resp.raise_for_status()\n    page = resp.json()\n    for entry in page[\"results\"]:\n        print(entry[\"created_at\"], entry[\"activity_type\"], entry[\"actor_display\"], entry.get(\"new_status\"))\n    url = page[\"next\"]"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "const sessionId = \"8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d\";\nconst res = await fetch(\n  `https://verification.didit.me/v3/sessions/${sessionId}/reviews/`,\n  { headers: { 'x-api-key': 'YOUR_API_KEY' } },\n);\nif (!res.ok) throw new Error(`Didit ${res.status}`);\nconst { count, results } = await res.json();\nconsole.log(`${count} feed entries`);\nfor (const entry of results) {\n  console.log(entry.created_at, entry.activity_type, entry.actor_display, entry.new_status ?? \"\");\n}"
          }
        ]
      },
      "post": {
        "summary": "Add a review note to a session's audit trail",
        "description": "Append a note to a User Verification (KYC) session's review / activity feed. **This endpoint only records an entry — it never changes the session.** The session's `status` is left untouched, no status-transition validation runs, and no webhook fires. To actually approve, decline, or re-open a session (which also writes a fully-attributed `STATUS_UPDATED` entry to this feed), use `PATCH /v3/session/{session_id}/update-status/` instead.\n\nBoth body fields are optional and an empty JSON object is accepted. `new_status` is stored purely as a label on the entry and accepts any of the ten session status values (case-sensitive). `@email` mentions inside `comment` are stored as plain text only — they trigger no notifications on this endpoint, and the entry's `mentioned_emails` stays empty.\n\nNote on attribution: entries created here carry no actor information. In the feed they show `actor_display: \"Unknown\"`, `actor_type: \"CONSOLE_USER\"`, and `activity_type: \"STATUS_UPDATED\"` (storage defaults), and the `201` body's `user` field is `\"Unknown\"`.",
        "operationId": "create_session_review",
        "tags": [
          "Sessions"
        ],
        "parameters": [
          {
            "name": "Content-Type",
            "in": "header",
            "required": false,
            "description": "Set to `application/json` when sending a JSON body.",
            "schema": {
              "type": "string",
              "example": "application/json"
            }
          },
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "description": "UUID of the User Verification (KYC) session. Must belong to the same application as the API key — cross-application UUIDs, deleted sessions, and Business Verification (KYB) session IDs all return `404`.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "new_status": {
                    "type": "string",
                    "nullable": true,
                    "enum": [
                      "Not Started",
                      "In Progress",
                      "Approved",
                      "Declined",
                      "In Review",
                      "Expired",
                      "Abandoned",
                      "Kyc Expired",
                      "Resubmitted",
                      "Awaiting User"
                    ],
                    "description": "Optional status label to record on the entry. Accepts any session status value, case-sensitive (`\"approved\"` is rejected with `400`). Recording a status here does **not** change the session's actual status — use the update-status endpoint for that.",
                    "example": "In Review"
                  },
                  "comment": {
                    "type": "string",
                    "nullable": true,
                    "description": "Optional free-text note (no enforced length limit). Stored verbatim; `@email` mentions are not processed on this endpoint.",
                    "example": "Flagging for manual document re-check."
                  }
                }
              },
              "examples": {
                "NoteWithStatusLabel": {
                  "summary": "Note carrying a status label (session status unchanged)",
                  "value": {
                    "new_status": "In Review",
                    "comment": "Flagging for manual document re-check."
                  }
                },
                "CommentOnly": {
                  "summary": "Plain note without a status label",
                  "value": {
                    "comment": "Customer emailed an updated utility bill; awaiting upload."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Entry recorded on the session's audit trail. The session itself is unchanged — its `status` keeps its previous value and no webhook is sent. The new entry also appears at the top of `GET …/reviews/` (with `actor_display: \"Unknown\"`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "string",
                      "description": "Display name of the entry's author. Always `\"Unknown\"` for entries created through this endpoint, because it records no actor attribution.",
                      "example": "Unknown"
                    },
                    "new_status": {
                      "type": "string",
                      "nullable": true,
                      "enum": [
                        "Not Started",
                        "In Progress",
                        "Approved",
                        "Declined",
                        "In Review",
                        "Expired",
                        "Abandoned",
                        "Kyc Expired",
                        "Resubmitted",
                        "Awaiting User"
                      ],
                      "description": "The status label recorded on the entry, or `null` if none was sent. The session's actual status is not affected.",
                      "example": "In Review"
                    },
                    "comment": {
                      "type": "string",
                      "nullable": true,
                      "description": "The note recorded on the entry, or `null` if none was sent.",
                      "example": "Flagging for manual document re-check."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the entry was written, ISO 8601 UTC.",
                      "example": "2026-06-12T00:18:44.466537Z"
                    }
                  }
                },
                "examples": {
                  "NoteWithStatusLabel": {
                    "summary": "Note with a status label",
                    "value": {
                      "user": "Unknown",
                      "new_status": "In Review",
                      "comment": "Flagging for manual document re-check.",
                      "created_at": "2026-06-12T00:18:44.466537Z"
                    }
                  },
                  "CommentOnly": {
                    "summary": "Plain note",
                    "value": {
                      "user": "Unknown",
                      "new_status": null,
                      "comment": "Note without status.",
                      "created_at": "2026-06-12T00:18:44.504157Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error, returned as a per-field map of messages. The usual cause is a `new_status` value that is not one of the ten allowed statuses — the check is case-sensitive.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_status": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "example": [
                        "\"approved\" is not a valid choice."
                      ]
                    }
                  }
                },
                "examples": {
                  "InvalidStatusChoice": {
                    "summary": "Lowercase / unknown status value",
                    "value": {
                      "new_status": [
                        "\"approved\" is not a valid choice."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, malformed, expired, or revoked `x-api-key`. Authentication is checked before the session lookup, so an invalid key returns `403` even when the session UUID does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "You do not have permission to perform this action."
                    }
                  }
                },
                "examples": {
                  "InvalidKey": {
                    "summary": "Missing or invalid x-api-key header",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No User Verification (KYC) session with this UUID is visible to your application: the UUID does not exist, the session was deleted, or it belongs to a different application. Business Verification (KYB) session IDs also return `404` here — the reviews feed is only addressable for KYC sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string",
                      "example": "Session not found."
                    }
                  }
                },
                "examples": {
                  "NotFound": {
                    "summary": "Unknown, deleted, or cross-application session UUID",
                    "value": {
                      "detail": "Session not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Inspect `Retry-After` and `X-RateLimit-*` response headers. See [Rate limiting](/integration/rate-limiting)."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "# Records an audit-trail note only -- the session's status does NOT change.\ncurl -s -X POST https://verification.didit.me/v3/sessions/8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d/reviews/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"new_status\": \"In Review\",\n    \"comment\": \"Flagging for manual document re-check.\"\n  }'"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import os, requests\n\n# Records an audit-trail note only -- the session's status does NOT change.\n# To approve/decline a session use PATCH /v3/session/{session_id}/update-status/.\nsession_id = \"8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d\"\nresp = requests.post(\n    f\"https://verification.didit.me/v3/sessions/{session_id}/reviews/\",\n    headers={\n        \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"new_status\": \"In Review\",\n        \"comment\": \"Flagging for manual document re-check.\",\n    },\n    timeout=10,\n)\nresp.raise_for_status()\nprint(resp.json())  # {'user': 'Unknown', 'new_status': 'In Review', ...}"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js (fetch)",
            "source": "// Records an audit-trail note only -- the session's status does NOT change.\n// To approve/decline a session use PATCH /v3/session/{session_id}/update-status/.\nconst sessionId = \"8c2f3a14-7e9b-4d23-9e83-3f7d5e8a1c6d\";\nconst res = await fetch(\n  `https://verification.didit.me/v3/sessions/${sessionId}/reviews/`,\n  {\n    method: \"POST\",\n    headers: {\n      'x-api-key': 'YOUR_API_KEY',\n      \"Content-Type\": \"application/json\",\n    },\n    body: JSON.stringify({\n      new_status: \"In Review\",\n      comment: \"Flagging for manual document re-check.\",\n    }),\n  },\n);\nif (!res.ok) throw new Error(`Didit ${res.status}: ${await res.text()}`);\nconsole.log(await res.json()); // { user: 'Unknown', new_status: 'In Review', ... }"
          }
        ]
      }
    },
    "/v3/billing/balance/": {
      "get": {
        "summary": "Get credit balance",
        "description": "Get current pre-paid credit balance in USD (organization-wide) plus auto-refill config. Amounts are decimal strings — parse with a decimal library.",
        "operationId": "get_billing_balance",
        "tags": [
          "Billing"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/billing/balance/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nfrom decimal import Decimal\n\nimport requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/billing/balance/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    timeout=10,\n)\nresp.raise_for_status()\ndata = resp.json()\nbalance = Decimal(data['balance'])\nif balance < Decimal('50'):\n    print(f'Low balance: ${balance} - top up before launching new sessions.')\nelse:\n    print(f'Balance OK: ${balance}')"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/billing/balance/', {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n});\nif (!resp.ok) throw new Error(`Billing balance failed: ${resp.status}`);\nconst { balance, auto_refill_enabled, auto_refill_threshold } = await resp.json();\nconsole.log({ balance, auto_refill_enabled, auto_refill_threshold });"
          }
        ],
        "responses": {
          "200": {
            "description": "Current credit balance plus the organization's auto-refill configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "balance",
                    "auto_refill_enabled"
                  ],
                  "properties": {
                    "balance": {
                      "type": "string",
                      "description": "Current pre-paid credit balance in USD, as a fixed-point decimal string. Decreases as verifications are billed and increases when a top-up settles."
                    },
                    "auto_refill_enabled": {
                      "type": "boolean",
                      "description": "When `true`, Didit will automatically charge the saved Stripe payment method to add credits once the balance crosses `auto_refill_threshold`. Configured from Console → Billing."
                    },
                    "auto_refill_amount": {
                      "type": "string",
                      "nullable": true,
                      "description": "USD amount that will be charged on each auto-refill. `null` when auto-refill is disabled or unset."
                    },
                    "auto_refill_threshold": {
                      "type": "string",
                      "nullable": true,
                      "description": "Trigger threshold in USD. Auto-refill fires when `balance` falls below this value. `null` when auto-refill is disabled or unset."
                    }
                  }
                },
                "examples": {
                  "Healthy balance with auto-refill": {
                    "value": {
                      "balance": "1234.5600",
                      "auto_refill_enabled": true,
                      "auto_refill_amount": "500.00",
                      "auto_refill_threshold": "100.00"
                    }
                  },
                  "Low balance, manual top-up only": {
                    "value": {
                      "balance": "12.0000",
                      "auto_refill_enabled": false,
                      "auto_refill_amount": null,
                      "auto_refill_threshold": null
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot read billing data for this organization. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/billing/top-up/": {
      "post": {
        "summary": "Top up credits",
        "description": "Add credits via a hosted Stripe Checkout session (**$50 minimum**); not available on annual plans. Redirect the customer to the returned `checkout_session_url`.",
        "operationId": "billing_top_up",
        "tags": [
          "Billing"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_in_dollars"
                ],
                "properties": {
                  "amount_in_dollars": {
                    "type": "number",
                    "minimum": 50,
                    "description": "Amount to charge, in USD. **Must be at least 50.** Tax is added automatically at checkout based on the customer's billing address."
                  },
                  "success_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL Stripe redirects the customer to after a successful payment. Currently defaults to `https://console.didit.me`. Pass a working URL explicitly; the default host is unavailable. Append the literal placeholder `{CHECKOUT_SESSION_ID}` if you want Stripe to substitute the session ID."
                  },
                  "cancel_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "URL Stripe redirects the customer to when they abort or close the Checkout window. Currently defaults to `https://console.didit.me`. Pass a working URL explicitly; the default host is unavailable."
                  }
                }
              },
              "examples": {
                "Minimum top-up": {
                  "value": {
                    "amount_in_dollars": 50
                  }
                },
                "Custom amount with redirects": {
                  "value": {
                    "amount_in_dollars": 500,
                    "success_url": "https://yourapp.com/billing/top-up/success",
                    "cancel_url": "https://yourapp.com/billing/top-up/cancel"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/billing/top-up/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"amount_in_dollars\": 500,\n    \"success_url\": \"https://yourapp.com/billing/success\",\n    \"cancel_url\": \"https://yourapp.com/billing/cancel\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/billing/top-up/',\n    headers={\n        'x-api-key': os.environ['DIDIT_API_KEY'],\n        'Content-Type': 'application/json',\n    },\n    json={\n        'amount_in_dollars': 500,\n        'success_url': 'https://yourapp.com/billing/success',\n        'cancel_url': 'https://yourapp.com/billing/cancel',\n    },\n    timeout=10,\n)\nresp.raise_for_status()\nsession = resp.json()\nprint('Redirect customer to:', session['checkout_session_url'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/billing/top-up/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    amount_in_dollars: 500,\n    success_url: 'https://yourapp.com/billing/success',\n    cancel_url: 'https://yourapp.com/billing/cancel',\n  }),\n});\nif (!resp.ok) throw new Error(`Top-up failed: ${resp.status}`);\nconst { checkout_session_url } = await resp.json();\nwindow.location.assign(checkout_session_url);"
          }
        ],
        "responses": {
          "200": {
            "description": "Stripe Checkout session created. Redirect the user to `checkout_session_url` to complete payment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "checkout_session_id",
                    "checkout_session_url"
                  ],
                  "properties": {
                    "checkout_session_id": {
                      "type": "string",
                      "description": "Stripe Checkout Session identifier (e.g. `cs_test_a1B2c3...`). Useful for server-side reconciliation."
                    },
                    "checkout_session_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Single-use Stripe-hosted payment page URL. Redirect the customer here to complete payment."
                    }
                  }
                },
                "examples": {
                  "Created": {
                    "value": {
                      "checkout_session_id": "cs_test_a1B2c3D4e5F6g7H8i9J0",
                      "checkout_session_url": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3D4e5F6g7H8i9J0"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload — the amount is missing, not a number, below the $50 minimum, or the organization is on an annual plan. The error body is a JSON array.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing amount": {
                    "value": [
                      "amount_in_dollars is required."
                    ]
                  },
                  "Not a number": {
                    "value": [
                      "amount_in_dollars must be a number."
                    ]
                  },
                  "Below minimum": {
                    "value": [
                      "Amount must be at least $50."
                    ]
                  },
                  "Annual plan": {
                    "value": [
                      "You have an annual plan. Contact your account manager to top up."
                    ]
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot create top-up sessions for this organization. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/webhook/destinations/": {
      "get": {
        "summary": "List webhook destinations",
        "description": "List all webhook destinations (unpaginated array, oldest first). Each row includes URL, subscribed events, and delivery health metrics. The signing secret is NOT included in the list — fetch a single destination (`GET /v3/webhook/destinations/{destination_uuid}/`) to read `secret_shared_key`.",
        "operationId": "list_webhook_destinations",
        "tags": [
          "Webhook"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/webhook/destinations/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/webhook/destinations/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    timeout=10,\n)\nresp.raise_for_status()\nfor dest in resp.json():\n    health = 'OK' if dest['error_rate_percentage'] < 5 else 'DEGRADED'\n    print(f\"{dest['label']:30s} {dest['url']:50s} {health}\")"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/webhook/destinations/', {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n});\nconst destinations = await resp.json();\nfor (const d of destinations) {\n  console.log(d.label, d.url, `${d.error_rate_percentage}% errors`);\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhook destinations (unpaginated, oldest first).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "uuid": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Stable destination identifier; use as `{destination_uuid}` for update/delete."
                      },
                      "label": {
                        "type": "string",
                        "description": "Human-readable name shown in the Console."
                      },
                      "url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Destination URL that receives `POST` requests with the webhook payload."
                      },
                      "enabled": {
                        "type": "boolean",
                        "description": "When `false`, Didit silently skips delivery to this destination."
                      },
                      "webhook_version": {
                        "type": "string",
                        "enum": [
                          "v1",
                          "v2",
                          "v3"
                        ],
                        "description": "Payload schema version sent to this destination. `v3` is the current/recommended format."
                      },
                      "subscribed_events": {
                        "$ref": "#/components/schemas/WebhookSubscribedEvents"
                      },
                      "subscribed_events_count": {
                        "type": "integer",
                        "description": "Cached length of `subscribed_events`, useful for UI rendering."
                      },
                      "deliveries_count": {
                        "type": "integer",
                        "description": "Total delivery attempts (successful + failed) recorded for this destination."
                      },
                      "failed_deliveries_count": {
                        "type": "integer",
                        "description": "Delivery attempts whose target responded with HTTP ≥ 400 (or did not respond)."
                      },
                      "average_response_time_ms": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Average target response time in milliseconds, rounded to an integer. `null` if no deliveries yet."
                      },
                      "error_rate_percentage": {
                        "type": "integer",
                        "description": "`round(failed_deliveries_count / deliveries_count * 100)`; `0` when there are no deliveries."
                      },
                      "last_delivery_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Timestamp of the most recent delivery attempt (success or failure). `null` if never delivered."
                      },
                      "created_at": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "updated_at": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                },
                "examples": {
                  "Two destinations": {
                    "value": [
                      {
                        "uuid": "11111111-2222-3333-4444-555555555555",
                        "label": "Production session webhooks",
                        "url": "https://yourapp.com/webhooks/didit",
                        "enabled": true,
                        "webhook_version": "v3",
                        "subscribed_events": [
                          "status.updated",
                          "data.updated"
                        ],
                        "subscribed_events_count": 2,
                        "deliveries_count": 12453,
                        "failed_deliveries_count": 14,
                        "average_response_time_ms": 187,
                        "error_rate_percentage": 0,
                        "last_delivery_at": "2026-05-17T09:21:18Z",
                        "created_at": "2026-01-04T08:00:00Z",
                        "updated_at": "2026-04-22T14:09:11Z"
                      },
                      {
                        "uuid": "22222222-3333-4444-5555-666666666666",
                        "label": "Staging mirror",
                        "url": "https://staging.yourapp.com/webhooks/didit",
                        "enabled": false,
                        "webhook_version": "v3",
                        "subscribed_events": [
                          "status.updated"
                        ],
                        "subscribed_events_count": 1,
                        "deliveries_count": 0,
                        "failed_deliveries_count": 0,
                        "average_response_time_ms": null,
                        "error_rate_percentage": 0,
                        "last_delivery_at": null,
                        "created_at": "2026-03-12T10:15:02Z",
                        "updated_at": "2026-03-12T10:15:02Z"
                      }
                    ]
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create webhook destination",
        "description": "Create a webhook destination. The response includes the auto-generated `secret_shared_key` HMAC signing secret (also readable later via `GET /v3/webhook/destinations/{destination_uuid}/`). Always send `subscribed_events` with at least one event (no wildcards): an explicit empty list is rejected with 400, and omitting the field creates a destination subscribed to nothing, which never receives a webhook. The `(application, url)` pair must be unique among non-deleted destinations.",
        "operationId": "create_webhook_destination",
        "tags": [
          "Webhook"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/webhook/destinations/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"label\": \"Production session webhooks\",\n    \"url\": \"https://yourapp.com/webhooks/didit\",\n    \"webhook_version\": \"v3\",\n    \"subscribed_events\": [\"status.updated\", \"data.updated\"]\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/webhook/destinations/',\n    headers={\n        'x-api-key': os.environ['DIDIT_API_KEY'],\n        'Content-Type': 'application/json',\n    },\n    json={\n        'label': 'Production session webhooks',\n        'url': 'https://yourapp.com/webhooks/didit',\n        'webhook_version': 'v3',\n        'subscribed_events': ['status.updated', 'data.updated'],\n    },\n    timeout=10,\n)\nresp.raise_for_status()\ndestination = resp.json()\n# Store secret_shared_key in your secret manager.\nprint('Destination UUID:', destination['uuid'])\nprint('Signing secret:', destination['secret_shared_key'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/webhook/destinations/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    label: 'Production session webhooks',\n    url: 'https://yourapp.com/webhooks/didit',\n    webhook_version: 'v3',\n    subscribed_events: ['status.updated', 'data.updated'],\n  }),\n});\nif (!resp.ok) throw new Error(await resp.text());\nconst destination = await resp.json();\nconsole.log('Store this secret securely:', destination.secret_shared_key);"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "label",
                  "url"
                ],
                "properties": {
                  "label": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Human-readable name displayed in Console → Webhooks. Helps distinguish destinations when you have several (e.g. \"Prod\", \"Staging mirror\")."
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "HTTPS URL that will receive `POST` requests. Must be unique per application among non-deleted destinations. Use a stable, hardened endpoint — Didit retries failed deliveries on a backoff schedule."
                  },
                  "enabled": {
                    "type": "boolean",
                    "default": true,
                    "description": "When `false`, the destination is saved but Didit will not push any webhooks to it. Useful for staging configs you want to keep parked."
                  },
                  "webhook_version": {
                    "type": "string",
                    "enum": [
                      "v1",
                      "v2",
                      "v3"
                    ],
                    "description": "Payload schema version Didit will send. `v3` is the current/recommended format; older versions are kept for backward compatibility with legacy integrations."
                  },
                  "subscribed_events": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/WebhookSubscribedEvents"
                      }
                    ],
                    "description": "Events to deliver. Effectively required: an explicit `[]` is rejected with 400, and omitting the field creates a destination with no subscriptions that receives nothing."
                  }
                }
              },
              "examples": {
                "session_updates": {
                  "summary": "Session status and data updates",
                  "value": {
                    "label": "Production session webhooks",
                    "url": "https://yourapp.com/webhooks/didit",
                    "webhook_version": "v3",
                    "subscribed_events": [
                      "status.updated",
                      "data.updated"
                    ]
                  }
                },
                "transaction_updates": {
                  "summary": "Transaction monitoring updates",
                  "value": {
                    "label": "Transaction monitoring webhooks",
                    "url": "https://yourapp.com/webhooks/didit-transactions",
                    "webhook_version": "v3",
                    "subscribed_events": [
                      "transaction.created",
                      "transaction.status.updated"
                    ]
                  }
                },
                "entity_updates": {
                  "summary": "User and Business entity updates",
                  "value": {
                    "label": "Entity lifecycle webhooks",
                    "url": "https://yourapp.com/webhooks/didit-entities",
                    "webhook_version": "v3",
                    "subscribed_events": [
                      "user.status.updated",
                      "user.data.updated",
                      "business.status.updated",
                      "business.data.updated",
                      "activity.created"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Destination created. `secret_shared_key` is the HMAC signing secret — store it now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Stable destination identifier. Use as `{destination_uuid}` in subsequent calls."
                    },
                    "label": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "webhook_version": {
                      "type": "string",
                      "enum": [
                        "v1",
                        "v2",
                        "v3"
                      ]
                    },
                    "secret_shared_key": {
                      "type": "string",
                      "description": "Auto-generated HMAC signing secret bound to this destination (43-character URL-safe token). Use it to verify the signature headers on incoming webhooks. Always returned in full to API-key callers; Console users need the `read:webhooks` permission, otherwise they see an empty string."
                    },
                    "subscribed_events": {
                      "$ref": "#/components/schemas/WebhookSubscribedEvents"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "summary": {
                      "type": "object",
                      "description": "Delivery health summary (all zero/null on a brand-new destination).",
                      "properties": {
                        "total_deliveries": {
                          "type": "integer"
                        },
                        "failed_deliveries": {
                          "type": "integer"
                        },
                        "error_rate_percentage": {
                          "type": "integer"
                        },
                        "min_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "avg_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "max_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "last_delivery_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Created": {
                    "value": {
                      "uuid": "11111111-2222-3333-4444-555555555555",
                      "label": "Production session webhooks",
                      "url": "https://yourapp.com/webhooks/didit",
                      "enabled": true,
                      "webhook_version": "v3",
                      "secret_shared_key": "tno2NTeRC1ZK3sBOYlBJDyEzBVENl3pQ1AcZyAW0xnQ",
                      "subscribed_events": [
                        "status.updated",
                        "data.updated"
                      ],
                      "created_at": "2026-05-17T10:00:00Z",
                      "updated_at": "2026-05-17T10:00:00Z",
                      "summary": {
                        "total_deliveries": 0,
                        "failed_deliveries": 0,
                        "error_rate_percentage": 0,
                        "min_response_time_ms": null,
                        "avg_response_time_ms": null,
                        "max_response_time_ms": null,
                        "last_delivery_at": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed — usually a duplicate URL, missing/invalid `subscribed_events`, or unknown event name.",
            "content": {
              "application/json": {
                "examples": {
                  "Duplicate URL": {
                    "value": {
                      "url": [
                        "This webhook destination already exists for the application."
                      ]
                    }
                  },
                  "Empty events list": {
                    "value": {
                      "subscribed_events": [
                        "At least one subscribed event is required."
                      ]
                    }
                  },
                  "Unknown event": {
                    "value": {
                      "subscribed_events": [
                        "Unsupported webhook events: foo.bar"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/webhook/destinations/{destination_uuid}/": {
      "get": {
        "summary": "Get webhook destination",
        "description": "Retrieve one webhook destination with its `secret_shared_key` signing secret and delivery health summary. API-key callers always receive the secret in full; Console users without `read:webhooks` see an empty string.",
        "operationId": "get_webhook_destination",
        "tags": [
          "Webhook"
        ],
        "parameters": [
          {
            "name": "destination_uuid",
            "in": "path",
            "required": true,
            "description": "UUID of the destination (the `uuid` returned from create / list).",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "11111111-2222-3333-4444-555555555555"
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/webhook/destinations/11111111-2222-3333-4444-555555555555/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nuuid = '11111111-2222-3333-4444-555555555555'\nresp = requests.get(\n    f'https://verification.didit.me/v3/webhook/destinations/{uuid}/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    timeout=10,\n)\nresp.raise_for_status()\nprint(resp.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const uuid = '11111111-2222-3333-4444-555555555555';\nconst resp = await fetch(`https://verification.didit.me/v3/webhook/destinations/${uuid}/`, {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n});\nif (!resp.ok) throw new Error(`Lookup failed: ${resp.status}`);\nconst destination = await resp.json();\nconsole.log(destination);"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook destination details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "label": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "webhook_version": {
                      "type": "string",
                      "enum": [
                        "v1",
                        "v2",
                        "v3"
                      ]
                    },
                    "secret_shared_key": {
                      "type": "string",
                      "description": "HMAC signing secret (43-character URL-safe token). Always returned in full to API-key callers; Console users need `read:webhooks`, otherwise an empty string."
                    },
                    "subscribed_events": {
                      "$ref": "#/components/schemas/WebhookSubscribedEvents"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "summary": {
                      "type": "object",
                      "description": "Delivery health metrics aggregated over the destination's lifetime.",
                      "properties": {
                        "total_deliveries": {
                          "type": "integer"
                        },
                        "failed_deliveries": {
                          "type": "integer"
                        },
                        "error_rate_percentage": {
                          "type": "integer"
                        },
                        "min_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "avg_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "max_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "last_delivery_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Healthy destination": {
                    "value": {
                      "uuid": "11111111-2222-3333-4444-555555555555",
                      "label": "Production session webhooks",
                      "url": "https://yourapp.com/webhooks/didit",
                      "enabled": true,
                      "webhook_version": "v3",
                      "secret_shared_key": "tno2NTeRC1ZK3sBOYlBJDyEzBVENl3pQ1AcZyAW0xnQ",
                      "subscribed_events": [
                        "status.updated",
                        "data.updated"
                      ],
                      "created_at": "2026-01-04T08:00:00Z",
                      "updated_at": "2026-04-22T14:09:11Z",
                      "summary": {
                        "total_deliveries": 12453,
                        "failed_deliveries": 14,
                        "error_rate_percentage": 0,
                        "min_response_time_ms": 41,
                        "avg_response_time_ms": 187,
                        "max_response_time_ms": 2103,
                        "last_delivery_at": "2026-05-17T09:21:18Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No destination with this UUID exists, or it belongs to a different application, or it has been deleted.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Webhook destination not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update webhook destination",
        "description": "Update a webhook destination. **`subscribed_events` is REPLACED wholesale, not merged** — fetch first, append, resend. Secret is not rotated.",
        "operationId": "update_webhook_destination",
        "tags": [
          "Webhook"
        ],
        "parameters": [
          {
            "name": "destination_uuid",
            "in": "path",
            "required": true,
            "description": "UUID of the destination to update.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "11111111-2222-3333-4444-555555555555"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "description": "New human-readable name."
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "New target URL. Must be unique within the application."
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "Set to `false` to pause deliveries to this destination without deleting it."
                  },
                  "webhook_version": {
                    "type": "string",
                    "enum": [
                      "v1",
                      "v2",
                      "v3"
                    ],
                    "description": "New payload schema version for future deliveries."
                  },
                  "subscribed_events": {
                    "$ref": "#/components/schemas/WebhookSubscribedEvents"
                  }
                }
              },
              "examples": {
                "Pause destination": {
                  "value": {
                    "enabled": false
                  }
                },
                "Add transaction events": {
                  "value": {
                    "subscribed_events": [
                      "status.updated",
                      "data.updated",
                      "transaction.created",
                      "transaction.status.updated"
                    ]
                  }
                },
                "Move target URL": {
                  "value": {
                    "label": "Production session webhooks v2",
                    "url": "https://api.yourapp.com/webhooks/didit/v2"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/webhook/destinations/11111111-2222-3333-4444-555555555555/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"subscribed_events\": [\n      \"status.updated\",\n      \"data.updated\",\n      \"transaction.created\"\n    ]\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nuuid = '11111111-2222-3333-4444-555555555555'\nresp = requests.patch(\n    f'https://verification.didit.me/v3/webhook/destinations/{uuid}/',\n    headers={\n        'x-api-key': os.environ['DIDIT_API_KEY'],\n        'Content-Type': 'application/json',\n    },\n    json={'enabled': False},\n    timeout=10,\n)\nresp.raise_for_status()\nprint('Paused destination:', resp.json()['label'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const uuid = '11111111-2222-3333-4444-555555555555';\nconst resp = await fetch(`https://verification.didit.me/v3/webhook/destinations/${uuid}/`, {\n  method: 'PATCH',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({ enabled: false }),\n});\nif (!resp.ok) throw new Error(await resp.text());\nconsole.log(await resp.json());"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated webhook destination. Body has the same shape as `GET /v3/webhook/destinations/{destination_uuid}/`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "label": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "webhook_version": {
                      "type": "string",
                      "enum": [
                        "v1",
                        "v2",
                        "v3"
                      ]
                    },
                    "secret_shared_key": {
                      "type": "string"
                    },
                    "subscribed_events": {
                      "$ref": "#/components/schemas/WebhookSubscribedEvents"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "total_deliveries": {
                          "type": "integer"
                        },
                        "failed_deliveries": {
                          "type": "integer"
                        },
                        "error_rate_percentage": {
                          "type": "integer"
                        },
                        "min_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "avg_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "max_response_time_ms": {
                          "type": "integer",
                          "nullable": true
                        },
                        "last_delivery_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Paused": {
                    "value": {
                      "uuid": "11111111-2222-3333-4444-555555555555",
                      "label": "Production session webhooks",
                      "url": "https://yourapp.com/webhooks/didit",
                      "enabled": false,
                      "webhook_version": "v3",
                      "secret_shared_key": "tno2NTeRC1ZK3sBOYlBJDyEzBVENl3pQ1AcZyAW0xnQ",
                      "subscribed_events": [
                        "status.updated",
                        "data.updated"
                      ],
                      "created_at": "2026-01-04T08:00:00Z",
                      "updated_at": "2026-05-17T11:02:55Z",
                      "summary": {
                        "total_deliveries": 12453,
                        "failed_deliveries": 14,
                        "error_rate_percentage": 0,
                        "min_response_time_ms": 41,
                        "avg_response_time_ms": 187,
                        "max_response_time_ms": 2103,
                        "last_delivery_at": "2026-05-17T09:21:18Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (duplicate URL, empty/unknown events list, malformed body).",
            "content": {
              "application/json": {
                "examples": {
                  "Duplicate URL": {
                    "value": {
                      "url": [
                        "This webhook destination already exists for the application."
                      ]
                    }
                  },
                  "Empty events": {
                    "value": {
                      "subscribed_events": [
                        "At least one subscribed event is required."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Destination with this UUID does not exist (or is deleted, or belongs to another application).",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Webhook destination not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete webhook destination",
        "description": "Delete a webhook destination. Future events stop being pushed to its URL. Past delivery records are not affected and stay queryable from the Business Console, so deleting a destination is not a way to remove your delivery history. Calling again returns 404.",
        "operationId": "delete_webhook_destination",
        "tags": [
          "Webhook"
        ],
        "parameters": [
          {
            "name": "destination_uuid",
            "in": "path",
            "required": true,
            "description": "UUID of the destination to delete.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "11111111-2222-3333-4444-555555555555"
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/webhook/destinations/11111111-2222-3333-4444-555555555555/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nuuid = '11111111-2222-3333-4444-555555555555'\nresp = requests.delete(\n    f'https://verification.didit.me/v3/webhook/destinations/{uuid}/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    timeout=10,\n)\nresp.raise_for_status()\nassert resp.status_code == 204"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const uuid = '11111111-2222-3333-4444-555555555555';\nconst resp = await fetch(`https://verification.didit.me/v3/webhook/destinations/${uuid}/`, {\n  method: 'DELETE',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n});\nif (resp.status !== 204) throw new Error(`Delete failed: ${resp.status}`);"
          }
        ],
        "responses": {
          "204": {
            "description": "Destination deleted. No response body."
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No destination with this UUID exists for the application (already deleted or never existed).",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Webhook destination not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/wallet-screening/": {
      "post": {
        "summary": "Screen a wallet address",
        "description": "Run on-demand AML screening for a single crypto wallet/address without creating a transaction. Resolves your application's configured blockchain analytics provider, screens the address synchronously, and returns the normalised risk result. LIGHTNING is available only with an Elliptic or Chainalysis BYOK connection added through Marketplace. Nothing is written to the transactions table. One AML monitoring usage is billed per successful screening (sandbox applications are not billed).",
        "operationId": "screenWallet",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "wallet_address",
                  "blockchain"
                ],
                "properties": {
                  "wallet_address": {
                    "type": "string",
                    "description": "The crypto address or network identifier to screen. Must match the selected network (e.g. a `0x`-prefixed 40-hex-char address for EVM chains). Alias: `address`.",
                    "example": "0x94f1b9b64e2932f6a2db338f616844400cd58e8a"
                  },
                  "blockchain": {
                    "type": "string",
                    "description": "Network identifier. Managed screening supports BTC, ETH, LTC, XRP, BCH, DOGE, TRX, SOL, MATIC, BNB, BASE (Base), OP (Optimism), and ARB (Arbitrum One). USDT and USDC are legacy Ethereum aliases, not multi-network searches. Connected-provider coverage varies. LIGHTNING requires a supported connected provider. Celo, Mode and Plume are not currently supported. Alias: `currency`.",
                    "enum": [
                      "BTC",
                      "LIGHTNING",
                      "ETH",
                      "LTC",
                      "XRP",
                      "BCH",
                      "DOGE",
                      "TRX",
                      "SOL",
                      "MATIC",
                      "BNB",
                      "USDT",
                      "USDC",
                      "BASE",
                      "OP",
                      "ARB"
                    ],
                    "example": "ETH"
                  },
                  "direction": {
                    "type": "string",
                    "description": "Optional. Whether the address is being screened as an inbound (deposit) or outbound (withdrawal) counterparty. Accepts `inbound`, `outbound`, `deposit`, or `withdrawal`. Defaults to a neutral pre-transfer screen when omitted. This is passed to the provider as context only; it does not change the returned `risk_score`, `severity`, or the `source_of_funds`/`destination_of_funds` breakdowns, which are always both returned regardless of `direction`. Changing or omitting `direction` therefore does not require re-screening an address.",
                    "enum": [
                      "inbound",
                      "outbound",
                      "deposit",
                      "withdrawal"
                    ]
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/wallet-screening/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"wallet_address\": \"0x94f1b9b64e2932f6a2db338f616844400cd58e8a\",\n    \"blockchain\": \"ETH\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/wallet-screening/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={\n        'wallet_address': '0x94f1b9b64e2932f6a2db338f616844400cd58e8a',\n        'blockchain': 'ETH',\n    },\n    timeout=20,\n)\nresp.raise_for_status()\nresult = resp.json()\nprint(result['risk_score'], result['severity'], result['sanctions_hit'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const result = await fetch('https://verification.didit.me/v3/wallet-screening/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    wallet_address: '0x94f1b9b64e2932f6a2db338f616844400cd58e8a',\n    blockchain: 'ETH',\n  }),\n}).then((r) => r.json());\nconsole.log(result.risk_score, result.severity, result.sanctions_hit);"
          }
        ],
        "responses": {
          "200": {
            "description": "The normalised wallet screening result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletScreeningResult"
                },
                "example": {
                  "provider": "merklescience",
                  "screening_type": "WALLET_SCREENING",
                  "risk_score": 95,
                  "severity": "CRITICAL",
                  "status": "SCREENED",
                  "summary": "Merkle Science risk: Critical (5/5). SANCTIONS HIT. Dominant risk: sanctioned. Driven by: the address is attributed to Sanctions / OFAC (Example Sanctions)",
                  "wallet_address": "0x94f1b9b64e2932f6a2db338f616844400cd58e8a",
                  "transaction_hash": null,
                  "blockchain": "ETH",
                  "block_timestamp": null,
                  "total_value_usd": null,
                  "fee_usd": null,
                  "sender_rows": [],
                  "receiver_rows": [],
                  "transaction_flows": [],
                  "transaction_flows_status": null,
                  "transaction_flows_error": null,
                  "source_of_funds": [
                    {
                      "category": "sanctioned",
                      "percentage": 100.0,
                      "amount_usd": 9813695.0,
                      "entity_name": "Example Sanctions",
                      "entity_type": "Sanctions",
                      "entity_subtype": "OFAC",
                      "hops": null,
                      "description": "Sanctions / OFAC",
                      "is_direct": true,
                      "exposure_direction": "incoming",
                      "exposure_type": "direct",
                      "provider_entity_id": "118885",
                      "provider_entity_type_id": "30",
                      "provider_entity_subtype_id": "125",
                      "country": "",
                      "raw_amount": null,
                      "raw_currency": null
                    }
                  ],
                  "destination_of_funds": [
                    {
                      "category": "defi",
                      "percentage": 84.824453,
                      "amount_usd": 7783414.38,
                      "entity_name": "Example DeFi 7",
                      "entity_type": "DeFi",
                      "entity_subtype": "Bridges",
                      "hops": null,
                      "description": "DeFi / Bridges",
                      "is_direct": false,
                      "exposure_direction": "outgoing",
                      "exposure_type": "indirect",
                      "provider_entity_id": "118459",
                      "provider_entity_type_id": "33",
                      "provider_entity_subtype_id": "143",
                      "country": "",
                      "raw_amount": null,
                      "raw_currency": null
                    },
                    {
                      "category": "defi",
                      "percentage": 15.175547,
                      "amount_usd": 1392494.37,
                      "entity_name": "Example DeFi 2",
                      "entity_type": "DeFi",
                      "entity_subtype": "Yield Aggregator",
                      "hops": null,
                      "description": "DeFi / Yield Aggregator",
                      "is_direct": false,
                      "exposure_direction": "outgoing",
                      "exposure_type": "indirect",
                      "provider_entity_id": "90192",
                      "provider_entity_type_id": "33",
                      "provider_entity_subtype_id": "142",
                      "country": "",
                      "raw_amount": null,
                      "raw_currency": null
                    }
                  ],
                  "counterparty_connections": [
                    {
                      "entity_name": "Example Sanctions",
                      "entity_type": "Sanctions",
                      "entity_subtype": "OFAC",
                      "risk_level": "critical",
                      "categories": [
                        "sanctioned"
                      ],
                      "received_usd": null,
                      "sent_usd": null,
                      "received_hops": null,
                      "sent_hops": null,
                      "percentage": 0.0,
                      "is_direct": true,
                      "country": null,
                      "provider_entity_id": null
                    },
                    {
                      "entity_name": "Example Sanctions",
                      "entity_type": "Sanctions",
                      "entity_subtype": "OFAC",
                      "risk_level": "critical",
                      "categories": [
                        "sanctioned"
                      ],
                      "received_usd": null,
                      "sent_usd": null,
                      "received_hops": null,
                      "sent_hops": null,
                      "percentage": 0.0,
                      "is_direct": true,
                      "country": null,
                      "provider_entity_id": null
                    }
                  ],
                  "network_nodes": [],
                  "network_edges": [],
                  "sanctions_hit": true,
                  "pep_counterparty": null,
                  "dominant_risk_category": "sanctioned",
                  "risk_factors": [
                    {
                      "source": "attribution",
                      "category": "sanctioned",
                      "label": "Sanctions / OFAC",
                      "entity_name": "Example Sanctions",
                      "direction": "attribution",
                      "exposure_type": "attribution",
                      "amount_usd": null,
                      "percentage": 0.0,
                      "is_high_risk": true,
                      "description": "the address is attributed to Sanctions / OFAC (Example Sanctions)"
                    },
                    {
                      "source": "exposure",
                      "category": "sanctioned",
                      "label": "Sanctions / OFAC",
                      "entity_name": "Example Sanctions",
                      "direction": "incoming",
                      "exposure_type": "direct",
                      "amount_usd": 9813695.0,
                      "percentage": 51.679304,
                      "is_high_risk": true,
                      "description": "51.6793% direct incoming exposure to Sanctions / OFAC (Example Sanctions)"
                    },
                    {
                      "source": "exposure",
                      "category": "defi",
                      "label": "DeFi / Bridges",
                      "entity_name": "Example DeFi 7",
                      "direction": "outgoing",
                      "exposure_type": "indirect",
                      "amount_usd": 7783414.38,
                      "percentage": 40.987766,
                      "is_high_risk": false,
                      "description": "40.9878% indirect outgoing exposure to DeFi / Bridges (Example DeFi 7)"
                    },
                    {
                      "source": "exposure",
                      "category": "defi",
                      "label": "DeFi / Yield Aggregator",
                      "entity_name": "Example DeFi 2",
                      "direction": "outgoing",
                      "exposure_type": "indirect",
                      "amount_usd": 1392494.37,
                      "percentage": 7.33293,
                      "is_high_risk": false,
                      "description": "7.33293% indirect outgoing exposure to DeFi / Yield Aggregator (Example DeFi 2)"
                    }
                  ],
                  "raw_response": {
                    "...": "provider-specific details"
                  },
                  "report_signature": "<hmac-sha256 over the result, scoped to your application>"
                }
              }
            }
          },
          "400": {
            "description": "Validation error — malformed wallet address, missing `wallet_address`, unsupported `blockchain`, or LIGHTNING without an Elliptic or Chainalysis BYOK Marketplace connection."
          },
          "401": {
            "description": "Missing or invalid `x-api-key`."
          },
          "409": {
            "description": "No AML provider is configured for the application, or the configured provider does not support wallet screening yet. Configure transaction monitoring first."
          },
          "502": {
            "description": "The AML provider could not complete the screening. Retry later."
          }
        }
      }
    },
    "/v3/wallet-screening/pdf/": {
      "post": {
        "summary": "Render a wallet-screening result as a PDF",
        "description": "Stateless companion to `POST /v3/wallet-screening/`: repost the exact JSON body that endpoint returned — including the `report_signature` it added — and get back a Didit-branded PDF of the same result. No provider is called and nothing is billed or persisted; this only re-renders a result Didit already produced. The signature ties the PDF to an unmodified result: editing `risk_score`, `severity`, `sanctions_hit`, or any other signed field before reposting fails with `400`.",
        "operationId": "screenWalletPdf",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The unmodified JSON object returned by `POST /v3/wallet-screening/`, including `report_signature`.",
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WalletScreeningResult"
                  }
                ],
                "required": [
                  "report_signature"
                ],
                "description": "Same shape as the `POST /v3/wallet-screening/` response — pass that response body back verbatim, including `report_signature`."
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "# $RESULT is the saved JSON body from POST /v3/wallet-screening/\ncurl -X POST 'https://verification.didit.me/v3/wallet-screening/pdf/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d \"$RESULT\" \\\n  -o wallet_screening_report.pdf"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\n# `result` is the dict returned by POST /v3/wallet-screening/, unmodified\nresponse = requests.post(\n    'https://verification.didit.me/v3/wallet-screening/pdf/',\n    headers={'x-api-key': 'YOUR_API_KEY'},\n    json=result,\n    timeout=30,\n)\nresponse.raise_for_status()\nwith open('wallet_screening_report.pdf', 'wb') as fh:\n    fh.write(response.content)"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "// `result` is the object returned by POST /v3/wallet-screening/, unmodified\nconst response = await fetch('https://verification.didit.me/v3/wallet-screening/pdf/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify(result),\n});\nif (!response.ok) throw new Error(`PDF generation failed: HTTP ${response.status}`);\nconst pdfBuffer = Buffer.from(await response.arrayBuffer());"
          }
        ],
        "responses": {
          "200": {
            "description": "The rendered PDF document, returned directly as binary `application/pdf` — there is no JSON wrapper.",
            "headers": {
              "Content-Disposition": {
                "description": "`attachment; filename=wallet_screening_{address}.pdf`, derived from the `wallet_address` (or `transaction_hash`) in the reposted result.",
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=wallet_screening_0x28c6c06298d514db0899.pdf"
                }
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "The body is not a JSON object matching the wallet-screening result shape, or `report_signature` is missing or does not match the reposted fields (edited or truncated before repost).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "Not an object": {
                    "value": {
                      "non_field_errors": [
                        "Expected a JSON object matching a wallet-screening result."
                      ]
                    }
                  },
                  "Missing or invalid signature": {
                    "value": {
                      "report_signature": [
                        "This wallet-screening result is missing or fails its report signature - repost the exact JSON returned by the wallet-screening endpoint, unmodified."
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid `x-api-key`."
          }
        }
      }
    },
    "/v3/transactions/": {
      "get": {
        "summary": "List transactions",
        "description": "Paginated list of monitored transactions, newest first (`txn_date` desc). `count` is capped at 100; use `total_transactions` for the true row count. This endpoint does not support filtering or search parameters.",
        "operationId": "listTransactions",
        "tags": [
          "Transactions"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size. Defaults to 50 when omitted. There is no enforced maximum, but keep pages small for latency."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset of the first record to return. Prefer following the `next` URL from the previous page."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/transactions/?limit=50' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/transactions/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    params={'limit': 50},\n    timeout=10,\n)\nresp.raise_for_status()\npage = resp.json()\nfor tx in page['results']:\n    print(\n        tx['transaction_number'],\n        tx['status'],\n        tx['severity'],\n        f\"{tx['amount']} {tx['currency']}\",\n        tx.get('subject_name') or tx.get('subject_vendor_data'),\n    )"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = new URL('https://verification.didit.me/v3/transactions/');\nurl.searchParams.set('limit', '50');\nconst page = await fetch(url, {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n}).then((r) => r.json());\nfor (const tx of page.results) {\n  console.log(tx.transaction_number, tx.status, tx.severity, tx.amount, tx.currency);\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of transaction summaries, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Capped count of matching transactions (exact up to 100, capped thereafter). Use `total_transactions` for the true count when paginating."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or `null` on the last page."
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or `null` on the first page."
                    },
                    "total_transactions": {
                      "type": "integer",
                      "description": "Exact total count of (non-deleted) transactions for the application. Present on paginated responses."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "uuid": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Stable Didit transaction identifier. Use as `{transaction_id}` in detail/notes/related calls."
                          },
                          "transaction_number": {
                            "type": "integer",
                            "description": "Application-scoped sequential transaction number shown in Console (e.g. `4123`)."
                          },
                          "txn_id": {
                            "type": "string",
                            "description": "Customer-provided identifier from the create call (max 128 chars). Unique per application."
                          },
                          "transaction_type": {
                            "type": "string",
                            "description": "Top-level category as stored: `finance`, `kyc`, `travelRule`, `userPlatformEvent`, `gamblingBet`, `gamblingLimitChange`, `gamblingBonusChange`, `auditTrailEvent`. Note multi-word values are echoed back in camelCase even when submitted in snake_case."
                          },
                          "action_type": {
                            "type": "string",
                            "description": "Sub-type within the category (e.g. `deposit`, `withdrawal`, `transfer`)."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "APPROVED",
                              "IN_REVIEW",
                              "DECLINED",
                              "AWAITING_USER"
                            ],
                            "description": "Current monitoring verdict."
                          },
                          "direction": {
                            "type": "string",
                            "enum": [
                              "INBOUND",
                              "OUTBOUND"
                            ],
                            "description": "Direction relative to the subject. Stored uppercase regardless of the casing submitted."
                          },
                          "amount": {
                            "type": "string",
                            "description": "Transaction amount as a decimal string with trailing zeros stripped (e.g. `\"1500\"`, `\"0.5\"`, `\"0.123456789012345678\"`). Up to 18 decimal places."
                          },
                          "currency": {
                            "type": "string",
                            "description": "Currency code of `amount`. Any ISO 4217 alphabetic code is accepted (e.g. `EUR`, `USD`, `NGN`), as is a crypto asset symbol (e.g. `BTC`). Prefer a currently-circulating code. Not every accepted code has an exchange rate: when none is available for the code (for example the ISO accounting unit `XSU`, or a crypto symbol Didit does not price), automatic conversion fails and `preferred_currency_amount` is returned null unless the request supplied a pre-converted `amount_in_default_currency`."
                          },
                          "preferred_currency_amount": {
                            "type": "string",
                            "nullable": true,
                            "description": "`amount` converted to the application's preferred currency, when available."
                          },
                          "preferred_currency_code": {
                            "type": "string",
                            "nullable": true,
                            "description": "Preferred currency code used for `preferred_currency_amount` - the application's base currency, any currently-circulating ISO 4217 code. A code with no available exchange rate leaves `preferred_currency_amount` null unless the request supplied a pre-converted `amount_in_default_currency`."
                          },
                          "payment_details": {
                            "type": "string",
                            "nullable": true,
                            "description": "Free-text payment reference or memo from the submission."
                          },
                          "score": {
                            "type": "integer",
                            "description": "Risk score (typically 0–100). Higher = riskier."
                          },
                          "severity": {
                            "type": "string",
                            "nullable": true,
                            "enum": [
                              "UNKNOWN",
                              "LOW",
                              "MEDIUM",
                              "HIGH",
                              "CRITICAL"
                            ],
                            "description": "Categorical risk severity set by rules/providers (`UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`). `null` until something sets it."
                          },
                          "subject_name": {
                            "type": "string",
                            "nullable": true,
                            "description": "Full name of the `APPLICANT` party."
                          },
                          "subject_vendor_data": {
                            "type": "string",
                            "nullable": true,
                            "description": "Your internal user/business identifier for the applicant."
                          },
                          "subject_country": {
                            "type": "string",
                            "nullable": true,
                            "description": "Country code of the applicant, from the submitted `address.country` (typically ISO 3166-1 alpha-3)."
                          },
                          "counterparty_name": {
                            "type": "string",
                            "nullable": true,
                            "description": "Full name of the `COUNTERPARTY` party, if any."
                          },
                          "counterparty_vendor_data": {
                            "type": "string",
                            "nullable": true,
                            "description": "Your internal identifier for the counterparty."
                          },
                          "counterparty_country": {
                            "type": "string",
                            "nullable": true,
                            "description": "Country code of the counterparty, from the submitted `address.country`."
                          },
                          "tags": {
                            "type": "array",
                            "description": "Tags attached to the transaction (manually or by rules).",
                            "items": {
                              "type": "object",
                              "properties": {
                                "uuid": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "color": {
                                  "type": "string"
                                },
                                "description": {
                                  "type": "string",
                                  "nullable": true
                                },
                                "source": {
                                  "type": "string",
                                  "enum": [
                                    "didit",
                                    "custom"
                                  ],
                                  "description": "Whether the tag is a Didit preset or a custom tag."
                                }
                              }
                            }
                          },
                          "txn_date": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the transaction occurred (from `transaction_at` at create time)."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When Didit recorded the submission."
                          },
                          "decision_reason_code": {
                            "type": "string",
                            "nullable": true,
                            "description": "Machine-readable reason for the current `status` (e.g. `WALLET_HIGH_RISK`)."
                          },
                          "decision_reason_label": {
                            "type": "string",
                            "nullable": true,
                            "description": "Human-readable label for `decision_reason_code`."
                          },
                          "assigned_to_name": {
                            "type": "string",
                            "nullable": true,
                            "description": "Display name of the Console reviewer assigned to this transaction."
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Single transaction": {
                    "value": {
                      "count": 1,
                      "next": null,
                      "previous": null,
                      "total_transactions": 1,
                      "results": [
                        {
                          "uuid": "abcdef12-3456-4890-abcd-ef1234567890",
                          "transaction_number": 4123,
                          "txn_id": "your-txn-2026-05-17-001",
                          "transaction_type": "finance",
                          "action_type": "withdrawal",
                          "status": "IN_REVIEW",
                          "direction": "OUTBOUND",
                          "amount": "1500",
                          "currency": "EUR",
                          "preferred_currency_amount": "1620.45",
                          "preferred_currency_code": "USD",
                          "payment_details": "Withdrawal to crypto wallet",
                          "txn_date": "2026-05-17T08:42:00Z",
                          "created_at": "2026-05-17T08:42:11Z",
                          "score": 78,
                          "severity": "HIGH",
                          "decision_reason_code": "WALLET_HIGH_RISK",
                          "decision_reason_label": "Destination wallet flagged as high risk",
                          "tags": [
                            {
                              "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                              "name": "Manual review",
                              "color": "#F59E0B",
                              "description": null,
                              "source": "custom"
                            }
                          ],
                          "subject_name": "Maria Garcia",
                          "subject_vendor_data": "user-12345",
                          "counterparty_name": null,
                          "counterparty_vendor_data": null,
                          "counterparty_country": null,
                          "subject_country": null,
                          "assigned_to_name": "Alex Reviewer"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot list transactions for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create transaction",
        "description": "Submit a transaction for synchronous AML/risk monitoring. The transaction is created `APPROVED`, then your rules (and crypto screening, when applicable) run inline and may flip the returned `status` to `IN_REVIEW` or `DECLINED`. **`transaction_id` is your idempotency key** (max 128 chars, unique per app); reusing it returns 400. A `transaction.created` webhook is dispatched on success (sandbox applications are not billed and do not emit webhooks).",
        "operationId": "createTransaction",
        "tags": [
          "Transactions"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/transactions/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"transaction_id\": \"your-txn-2026-05-17-001\",\n    \"transaction_category\": \"finance\",\n    \"transaction_details\": {\n      \"direction\": \"outbound\",\n      \"amount\": 1500,\n      \"currency\": \"EUR\",\n      \"action_type\": \"withdrawal\"\n    },\n    \"subject\": {\n      \"entity_type\": \"individual\",\n      \"vendor_data\": \"user-12345\",\n      \"full_name\": \"Maria Garcia\"\n    }\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/transactions/',\n    headers={\n        'x-api-key': os.environ['DIDIT_API_KEY'],\n        'Content-Type': 'application/json',\n    },\n    json={\n        'transaction_id': 'your-txn-2026-05-17-001',\n        'transaction_category': 'finance',\n        'transaction_details': {\n            'direction': 'outbound',\n            'amount': 1500,\n            'currency': 'EUR',\n            'action_type': 'withdrawal',\n        },\n        'subject': {\n            'entity_type': 'individual',\n            'vendor_data': 'user-12345',\n            'full_name': 'Maria Garcia',\n        },\n    },\n    timeout=15,\n)\nresp.raise_for_status()\ntx = resp.json()\nprint(tx['txn_id'], '->', tx['status'], tx['severity'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/transactions/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    transaction_id: 'your-txn-2026-05-17-001',\n    transaction_category: 'finance',\n    transaction_details: {\n      direction: 'outbound',\n      amount: 1500,\n      currency: 'EUR',\n      action_type: 'withdrawal',\n    },\n    subject: {\n      entity_type: 'individual',\n      vendor_data: 'user-12345',\n      full_name: 'Maria Garcia',\n    },\n  }),\n});\nif (!resp.ok) throw new Error(await resp.text());\nconst tx = await resp.json();\nconsole.log(tx.txn_id, tx.status, tx.severity);"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "transaction_id": {
                    "type": "string",
                    "description": "Your unique identifier for this transaction (max 128 characters).",
                    "example": "your-txn-2026-05-17-001"
                  },
                  "transaction_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the transaction occurred. Defaults to now if omitted."
                  },
                  "time_zone": {
                    "type": "string",
                    "description": "IANA time zone identifier, e.g. `Europe/Madrid`."
                  },
                  "transaction_category": {
                    "type": "string",
                    "description": "Category of the transaction. CamelCase aliases (`travelRule`, `userPlatformEvent`, `gamblingBet`, …) are also accepted; the stored/echoed value is camelCase for multi-word categories.",
                    "example": "finance",
                    "enum": [
                      "finance",
                      "kyc",
                      "travel_rule",
                      "user_event",
                      "audit_trail_event",
                      "gambling_bet",
                      "gambling_limit_change",
                      "gambling_bonus_change",
                      "travelRule"
                    ]
                  },
                  "transaction_details": {
                    "type": "object",
                    "description": "Core financial details of the transaction.",
                    "required": [
                      "direction",
                      "amount",
                      "currency"
                    ],
                    "properties": {
                      "direction": {
                        "type": "string",
                        "description": "Direction of the transaction relative to the subject. Case-insensitive; `in`/`out` are accepted as aliases. Echoed back uppercase (`INBOUND`/`OUTBOUND`).",
                        "example": "outbound",
                        "enum": [
                          "inbound",
                          "outbound",
                          "in",
                          "out"
                        ]
                      },
                      "amount": {
                        "type": "number",
                        "description": "Transaction amount (up to 18 decimal places). Send it as a decimal string (e.g. `\"0.123456789012345678\"`) when exact precision matters: a JSON number is parsed as a binary float first, so digits beyond about 15 significant digits are rounded before the amount is stored.",
                        "example": 1500
                      },
                      "currency": {
                        "type": "string",
                        "description": "Currency code. Any ISO 4217 alphabetic code is accepted (e.g. `EUR`, `USD`, `NGN`), as is a crypto asset symbol (e.g. `BTC`). Prefer a currently-circulating code. Not every accepted code has an exchange rate: when none is available for the code (for example the ISO accounting unit `XSU`, or a crypto symbol Didit does not price), automatic conversion fails and `preferred_currency_amount` is returned null unless the request supplied a pre-converted `amount_in_default_currency`.",
                        "example": "EUR"
                      },
                      "currency_kind": {
                        "type": "string",
                        "description": "Whether the currency is `fiat` or `crypto`."
                      },
                      "amount_in_default_currency": {
                        "type": "number",
                        "nullable": true,
                        "description": "Pre-converted amount in the default currency. If omitted, automatic FX conversion is attempted."
                      },
                      "default_currency": {
                        "type": "string",
                        "description": "The default currency code for the converted amount. Any currently-circulating ISO 4217 code."
                      },
                      "payment_details": {
                        "type": "string",
                        "nullable": true,
                        "description": "Free-text payment reference or memo."
                      },
                      "payment_reference_id": {
                        "type": "string",
                        "nullable": true,
                        "description": "External payment system reference. For crypto AML transaction-hash screening, send the blockchain transaction hash and also provide `subject.payment_method.account_id` with the related address."
                      },
                      "action_type": {
                        "type": "string",
                        "nullable": true,
                        "description": "Sub-type of the transaction, e.g. `deposit`, `withdrawal`, `transfer`."
                      },
                      "crypto_params": {
                        "type": "object",
                        "description": "Crypto network selection, separate from currency (the asset symbol). Recording a custom token symbol does not guarantee transaction-hash coverage for its contract.",
                        "properties": {
                          "crypto_chain": {
                            "type": "string",
                            "description": "Actual network used for screening. Managed screening supports BTC, ETH, LTC, XRP, BCH, DOGE, TRX, SOL, MATIC, BNB, BASE (Base), OP (Optimism) and ARB (Arbitrum One). Always specify this for multi-network tokens. Connected-provider coverage varies; LIGHTNING requires a supported connected provider.",
                            "example": "BASE"
                          }
                        }
                      }
                    }
                  },
                  "subject": {
                    "type": "object",
                    "description": "The subject (applicant) of the transaction.",
                    "required": [
                      "vendor_data",
                      "full_name"
                    ],
                    "properties": {
                      "entity_type": {
                        "type": "string",
                        "description": "Entity type: `individual` or `company`."
                      },
                      "vendor_data": {
                        "type": "string",
                        "description": "Your internal user/business identifier.",
                        "example": "user-12345"
                      },
                      "full_name": {
                        "type": "string",
                        "description": "Full name of the subject.",
                        "example": "Maria Garcia"
                      },
                      "first_name": {
                        "type": "string",
                        "description": "First name of the subject."
                      },
                      "last_name": {
                        "type": "string",
                        "description": "Last name of the subject."
                      },
                      "date_of_birth": {
                        "type": "string",
                        "format": "date",
                        "description": "Date of birth (YYYY-MM-DD)."
                      },
                      "address": {
                        "type": "object",
                        "description": "Address object.",
                        "properties": {
                          "country": {
                            "type": "string",
                            "description": "Country code (ISO 3166-1 alpha-3 recommended). Copied to the party's `country_code`."
                          },
                          "town": {
                            "type": "string"
                          },
                          "state": {
                            "type": "string"
                          },
                          "street": {
                            "type": "string"
                          },
                          "post_code": {
                            "type": "string"
                          }
                        }
                      },
                      "institution_details": {
                        "type": "object",
                        "description": "Institution details (for institutional subjects).",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "address": {
                            "type": "object"
                          }
                        }
                      },
                      "device_context": {
                        "type": "object",
                        "description": "Device context captured at transaction time. browser_family and platform must be sent as explicit top-level keys — they are not derived from user_agent. The camelCase alias device is also accepted on the request.",
                        "properties": {
                          "fingerprint": {
                            "type": "string",
                            "description": "Unique device fingerprint."
                          },
                          "persistent_device_id": {
                            "type": "string",
                            "description": "Stable cross-session device identifier (v2 fingerprint schema)."
                          },
                          "user_agent": {
                            "type": "string",
                            "description": "Browser or app user agent string. CamelCase alias: userAgent."
                          },
                          "browser_family": {
                            "type": "string",
                            "description": "Browser family (e.g. Chrome, Firefox, Safari). Must be sent explicitly — it is not derived from user_agent. CamelCase alias: browserFamily."
                          },
                          "browser_version": {
                            "type": "string",
                            "description": "Browser version string. Must be sent explicitly. CamelCase alias: browserVersion."
                          },
                          "platform": {
                            "type": "string",
                            "description": "Platform identifier (web, ios, android, macos, windows, linux). Must be sent explicitly — it is not derived from user_agent."
                          },
                          "os_family": {
                            "type": "string",
                            "description": "Operating system family (e.g. iOS, Android, Windows). CamelCase alias: osFamily."
                          },
                          "os_version": {
                            "type": "string",
                            "description": "Operating system version string. CamelCase alias: osVersion."
                          },
                          "accept_language": {
                            "type": "string",
                            "description": "Accept-Language header value. CamelCase alias: acceptLang."
                          },
                          "session_id": {
                            "type": "string",
                            "description": "Session identifier of the user current session. Stored in metadata. CamelCase alias: sessionId."
                          },
                          "session_age_ms": {
                            "type": "number",
                            "description": "Age of the user session in milliseconds at transaction time. CamelCase alias: sessionAgeMs."
                          },
                          "network_context": {
                            "type": "object",
                            "description": "Network context with IP address and geo-location. A top-level ipInfo block is also folded into this object.",
                            "properties": {
                              "ip_address": {
                                "type": "string",
                                "description": "Client IP address. CamelCase alias: ip."
                              },
                              "ip_country_code": {
                                "type": "string",
                                "description": "Geo-resolved country of the IP (ISO 3166-1 alpha-3). CamelCase alias: countryCode3."
                              },
                              "latitude": {
                                "type": "number",
                                "description": "Geographic latitude of the IP. CamelCase alias: lat."
                              },
                              "longitude": {
                                "type": "number",
                                "description": "Geographic longitude of the IP. CamelCase alias: lon."
                              }
                            }
                          }
                        }
                      },
                      "payment_method": {
                        "type": "object",
                        "description": "Payment method used by the subject.",
                        "properties": {
                          "method_type": {
                            "type": "string",
                            "description": "Type of payment method: `bank_card`, `bank_account`, `crypto_wallet`, `ewallet`, `unhosted_wallet`, `other`."
                          },
                          "account_id": {
                            "type": "string",
                            "description": "Account identifier (e.g. IBAN, wallet address). For crypto screening, this should contain the wallet address for this participant. Inbound transaction-hash screening requires the service/customer deposit address on the subject. Outbound screening uses the destination wallet on the counterparty."
                          },
                          "issuing_country": {
                            "type": "string",
                            "description": "ISO 3166-1 alpha-3 country code of the issuer."
                          }
                        }
                      }
                    }
                  },
                  "counterparty": {
                    "type": "object",
                    "description": "The counterparty of the transaction (optional).",
                    "properties": {
                      "entity_type": {
                        "type": "string",
                        "description": "Entity type: `individual` or `company`."
                      },
                      "vendor_data": {
                        "type": "string",
                        "description": "Your internal identifier for the counterparty."
                      },
                      "full_name": {
                        "type": "string",
                        "description": "Full name of the counterparty."
                      },
                      "first_name": {
                        "type": "string"
                      },
                      "last_name": {
                        "type": "string"
                      },
                      "date_of_birth": {
                        "type": "string",
                        "format": "date"
                      },
                      "address": {
                        "type": "object",
                        "description": "Address object with `country` (ISO 3166-1 alpha-3)."
                      },
                      "institution_details": {
                        "type": "object"
                      },
                      "device_context": {
                        "type": "object",
                        "description": "Device context for the counterparty. browser_family and platform must be sent as explicit top-level keys — they are not derived from user_agent.",
                        "properties": {
                          "fingerprint": {
                            "type": "string",
                            "description": "Unique device fingerprint."
                          },
                          "persistent_device_id": {
                            "type": "string",
                            "description": "Stable cross-session device identifier (v2 fingerprint schema)."
                          },
                          "user_agent": {
                            "type": "string",
                            "description": "Browser or app user agent string. CamelCase alias: userAgent."
                          },
                          "browser_family": {
                            "type": "string",
                            "description": "Browser family (e.g. Chrome, Firefox, Safari). Must be sent explicitly — it is not derived from user_agent. CamelCase alias: browserFamily."
                          },
                          "browser_version": {
                            "type": "string",
                            "description": "Browser version string. Must be sent explicitly. CamelCase alias: browserVersion."
                          },
                          "platform": {
                            "type": "string",
                            "description": "Platform identifier (web, ios, android, macos, windows, linux). Must be sent explicitly — it is not derived from user_agent."
                          },
                          "os_family": {
                            "type": "string",
                            "description": "Operating system family (e.g. iOS, Android, Windows). CamelCase alias: osFamily."
                          },
                          "os_version": {
                            "type": "string",
                            "description": "Operating system version string. CamelCase alias: osVersion."
                          },
                          "accept_language": {
                            "type": "string",
                            "description": "Accept-Language header value. CamelCase alias: acceptLang."
                          },
                          "session_id": {
                            "type": "string",
                            "description": "Session identifier for the counterparty session. Stored in metadata. CamelCase alias: sessionId."
                          },
                          "session_age_ms": {
                            "type": "number",
                            "description": "Age of the user session in milliseconds at transaction time. CamelCase alias: sessionAgeMs."
                          },
                          "network_context": {
                            "type": "object",
                            "description": "Network context with IP address and geo-location. A top-level ipInfo block is also folded into this object.",
                            "properties": {
                              "ip_address": {
                                "type": "string",
                                "description": "Client IP address. CamelCase alias: ip."
                              },
                              "ip_country_code": {
                                "type": "string",
                                "description": "Geo-resolved country of the IP (ISO 3166-1 alpha-3). CamelCase alias: countryCode3."
                              },
                              "latitude": {
                                "type": "number",
                                "description": "Geographic latitude of the IP. CamelCase alias: lat."
                              },
                              "longitude": {
                                "type": "number",
                                "description": "Geographic longitude of the IP. CamelCase alias: lon."
                              }
                            }
                          }
                        }
                      },
                      "payment_method": {
                        "type": "object",
                        "description": "Payment method used by the counterparty. On travelRule transactions, `method_type: \"unhosted_wallet\"` declares the counterparty wallet as self-hosted: the transfer skips counterparty-VASP routing, is created directly in `UNCONFIRMED_OWNERSHIP`, and (when `auto_wallet_verification` is enabled) a wallet-ownership widget session is auto-minted and returned in the transaction's `action_required` block.",
                        "properties": {
                          "method_type": {
                            "type": "string",
                            "description": "Type of payment method: `bank_card`, `bank_account`, `crypto_wallet`, `ewallet`, `unhosted_wallet`, `other`. Use `unhosted_wallet` to declare a self-hosted wallet for the Travel Rule."
                          },
                          "account_id": {
                            "type": "string",
                            "description": "Account identifier (e.g. IBAN or wallet address)."
                          },
                          "issuing_country": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "custom_properties": {
                    "type": "object",
                    "description": "Arbitrary key-value pairs attached to the transaction. Each key can be referenced in rule conditions with the field path `custom_values.<key>`.",
                    "additionalProperties": true,
                    "example": {
                      "merchant_id": "test",
                      "bank_name": "test_2"
                    }
                  },
                  "travel_rule_details": {
                    "type": "object",
                    "description": "Travel Rule compliance metadata.",
                    "required": [
                      "status"
                    ],
                    "properties": {
                      "status": {
                        "type": "string"
                      },
                      "protocol": {
                        "type": "string"
                      },
                      "required": {
                        "type": "boolean"
                      },
                      "obligations_count": {
                        "type": "integer"
                      },
                      "originator_data": {
                        "type": "object"
                      },
                      "beneficiary_data": {
                        "type": "object"
                      },
                      "metadata": {
                        "type": "object"
                      }
                    }
                  },
                  "network_snapshot": {
                    "type": "object",
                    "description": "Pre-computed network graph snapshot.",
                    "properties": {
                      "nodes": {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      },
                      "edges": {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      },
                      "metrics": {
                        "type": "object"
                      }
                    }
                  },
                  "include_crypto_screening": {
                    "type": "boolean",
                    "nullable": true,
                    "description": "Per-transaction override for crypto blockchain analytics screening. When `true`, crypto screening is performed regardless of the application default. When `false`, crypto screening is skipped even if enabled in the application settings. When omitted or `null`, the application-level default configured in the Console is used. Crypto screening requires `transaction_details.direction`, `currency_kind: \"crypto\"`, a chain/currency, and the wallet address selected by the direction: inbound pre-transfer screening uses `counterparty.payment_method.account_id`, inbound transaction-hash screening uses `subject.payment_method.account_id`, and outbound screening uses `counterparty.payment_method.account_id`. When `transaction_details.payment_reference_id` contains a blockchain transaction hash, Didit performs transaction screening and returns transaction summary enrichment when available."
                  }
                },
                "required": [
                  "transaction_id",
                  "transaction_category",
                  "transaction_details",
                  "subject"
                ]
              },
              "examples": {
                "Minimal fiat withdrawal": {
                  "summary": "Smallest acceptable payload for a fiat outbound transfer",
                  "value": {
                    "transaction_id": "your-txn-2026-05-17-001",
                    "transaction_category": "finance",
                    "transaction_details": {
                      "direction": "outbound",
                      "amount": 1500,
                      "currency": "EUR",
                      "action_type": "withdrawal"
                    },
                    "subject": {
                      "entity_type": "individual",
                      "vendor_data": "user-12345",
                      "full_name": "Maria Garcia"
                    }
                  }
                },
                "Crypto outbound with screening": {
                  "summary": "Outbound crypto withdrawal to an unhosted wallet, opt-in screening",
                  "value": {
                    "transaction_id": "your-txn-2026-05-17-002",
                    "transaction_category": "finance",
                    "include_crypto_screening": true,
                    "transaction_details": {
                      "direction": "outbound",
                      "amount": 0.5,
                      "currency": "BTC",
                      "currency_kind": "crypto",
                      "amount_in_default_currency": 32500,
                      "default_currency": "USD",
                      "action_type": "withdrawal"
                    },
                    "subject": {
                      "entity_type": "individual",
                      "vendor_data": "user-12345",
                      "full_name": "Maria Garcia",
                      "payment_method": {
                        "method_type": "crypto_wallet",
                        "account_id": "bc1qexampleexchangewalletaddressxyz",
                        "issuing_country": "ESP"
                      }
                    },
                    "counterparty": {
                      "entity_type": "individual",
                      "payment_method": {
                        "method_type": "unhosted_wallet",
                        "account_id": "bc1qexampleexternalwalletaddressabc"
                      }
                    }
                  }
                },
                "Travel Rule transfer": {
                  "summary": "Outbound crypto transfer with Travel Rule originator/beneficiary data",
                  "value": {
                    "transaction_id": "your-txn-2026-05-17-003",
                    "transaction_category": "travel_rule",
                    "transaction_details": {
                      "direction": "outbound",
                      "amount": 25000,
                      "currency": "USDT",
                      "currency_kind": "crypto",
                      "payment_reference_id": "0xabcdef1234567890",
                      "action_type": "transfer"
                    },
                    "subject": {
                      "entity_type": "individual",
                      "vendor_data": "user-12345",
                      "full_name": "Maria Garcia",
                      "date_of_birth": "1992-03-14",
                      "address": {
                        "country": "ESP",
                        "town": "Madrid",
                        "street": "Calle Mayor 1",
                        "post_code": "28013"
                      }
                    },
                    "counterparty": {
                      "entity_type": "individual",
                      "full_name": "John Beneficiary",
                      "institution_details": {
                        "name": "Beneficiary VASP, Inc.",
                        "code": "BVASP-US"
                      }
                    },
                    "travel_rule_details": {
                      "status": "PENDING",
                      "protocol": "IVMS101",
                      "required": true,
                      "originator_data": {
                        "name": "Maria Garcia"
                      },
                      "beneficiary_data": {
                        "name": "John Beneficiary"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Transaction submitted and monitored. The body is the full transaction detail (same shape as `GET /v3/transactions/{transaction_id}/`), reflecting any rule outcomes already applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                },
                "examples": {
                  "Approved with no rule hits": {
                    "value": {
                      "uuid": "abcdef12-3456-4890-abcd-ef1234567890",
                      "environment": "live",
                      "transaction_number": 4123,
                      "txn_id": "your-txn-2026-05-17-001",
                      "txn_date": "2026-05-17T08:42:00Z",
                      "zone_id": "Europe/Madrid",
                      "transaction_type": "finance",
                      "action_type": "withdrawal",
                      "direction": "OUTBOUND",
                      "status": "APPROVED",
                      "source": "LIVE",
                      "amount": "1500",
                      "currency": "EUR",
                      "currency_type": "fiat",
                      "amount_in_default_currency": "1620.45",
                      "default_currency_code": "USD",
                      "preferred_currency_amount": "1620.45",
                      "preferred_currency_code": "USD",
                      "payment_details": "Withdrawal to crypto wallet",
                      "payment_txn_id": null,
                      "score": 0,
                      "severity": null,
                      "decision_reason_code": null,
                      "decision_reason_label": null,
                      "vendor_data": "user-12345",
                      "metadata": {
                        "subject": {
                          "entity_type": "individual",
                          "vendor_data": "user-12345",
                          "full_name": "Maria Garcia",
                          "address": {},
                          "institution_details": {},
                          "device_context": {}
                        },
                        "counterparty": {}
                      },
                      "props": {},
                      "tags": [],
                      "parties": [
                        {
                          "uuid": "b1111111-2222-4333-8444-555555555555",
                          "role": "APPLICANT",
                          "entity_type": "individual",
                          "kind": "USER",
                          "vendor_data": "user-12345",
                          "full_name": "Maria Garcia",
                          "first_name": null,
                          "last_name": null,
                          "country_code": null,
                          "dob": null,
                          "address": {},
                          "institution_info": {},
                          "device": {},
                          "external_party_snapshot": null
                        }
                      ],
                      "payment_methods": [],
                      "documents": [],
                      "activities": [
                        {
                          "uuid": "d4e5f6a7-8901-4bcd-9ef0-123456789abc",
                          "activity_type": "TRANSACTION_CREATED",
                          "source": "TRANSACTION",
                          "status": "APPROVED",
                          "title": "withdrawal",
                          "description": "Transaction recorded.",
                          "metadata": {},
                          "occurred_at": "2026-05-17T08:42:11Z"
                        }
                      ],
                      "alerts": [],
                      "rule_runs": [],
                      "provider_results": [],
                      "travel_rule": null,
                      "network_snapshot": null,
                      "remediation": null,
                      "cost_breakdown": null
                    }
                  },
                  "Flagged for review": {
                    "value": {
                      "uuid": "abcdef12-3456-4890-abcd-ef1234567891",
                      "environment": "live",
                      "transaction_number": 4124,
                      "txn_id": "your-txn-2026-05-17-002",
                      "txn_date": "2026-05-17T08:42:00Z",
                      "zone_id": "Europe/Madrid",
                      "transaction_type": "finance",
                      "action_type": "withdrawal",
                      "direction": "OUTBOUND",
                      "status": "IN_REVIEW",
                      "source": "LIVE",
                      "amount": "0.5",
                      "currency": "BTC",
                      "currency_type": "crypto",
                      "amount_in_default_currency": "32500",
                      "default_currency_code": "USD",
                      "preferred_currency_amount": "32500",
                      "preferred_currency_code": "USD",
                      "payment_details": "Withdrawal to crypto wallet",
                      "payment_txn_id": null,
                      "score": 78,
                      "severity": "HIGH",
                      "decision_reason_code": "WALLET_HIGH_RISK",
                      "decision_reason_label": "Destination wallet flagged as high risk",
                      "vendor_data": "user-12345",
                      "metadata": {
                        "subject": {
                          "entity_type": "individual",
                          "vendor_data": "user-12345",
                          "full_name": "Maria Garcia",
                          "address": {},
                          "institution_details": {},
                          "device_context": {}
                        },
                        "counterparty": {}
                      },
                      "props": {
                        "order_id": "ord-9988"
                      },
                      "tags": [],
                      "parties": [
                        {
                          "uuid": "b1111111-2222-4333-8444-555555555555",
                          "role": "APPLICANT",
                          "entity_type": "individual",
                          "kind": "USER",
                          "vendor_data": "user-12345",
                          "full_name": "Maria Garcia",
                          "first_name": null,
                          "last_name": null,
                          "country_code": null,
                          "dob": null,
                          "address": {},
                          "institution_info": {},
                          "device": {},
                          "external_party_snapshot": null
                        }
                      ],
                      "payment_methods": [],
                      "documents": [],
                      "activities": [],
                      "alerts": [
                        {
                          "uuid": "a7b8c9d0-1234-4abc-9def-567890abcdef",
                          "title": "Destination wallet flagged as high risk",
                          "description": "Provider risk score exceeded the configured threshold.",
                          "severity": "HIGH",
                          "status": "OPEN",
                          "source": "RULE",
                          "metadata": {},
                          "created_at": "2026-05-17T08:42:12Z",
                          "due_at": null
                        }
                      ],
                      "rule_runs": [
                        {
                          "uuid": "e5f6a7b8-9012-4cde-af01-23456789abcd",
                          "rule": "f6a7b8c9-0123-4def-b012-3456789abcde",
                          "rule_title": "High-risk wallet screening",
                          "rule_description": null,
                          "rule_category": "crypto",
                          "matched": true,
                          "is_test": false,
                          "mode": "ACTIVE",
                          "severity": "HIGH",
                          "score_delta": 78,
                          "status_target": "IN_REVIEW",
                          "action_summary": "score +78; change_status:IN_REVIEW",
                          "metadata": {},
                          "created_at": "2026-05-17T08:42:12Z"
                        }
                      ],
                      "provider_results": [],
                      "travel_rule": null,
                      "network_snapshot": null,
                      "remediation": null,
                      "cost_breakdown": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (missing required fields, duplicate `transaction_id`, unknown enum value, invalid currency, etc.).",
            "content": {
              "application/json": {
                "examples": {
                  "Missing required field": {
                    "value": {
                      "transaction_details": {
                        "amount": [
                          "This field is required."
                        ]
                      }
                    }
                  },
                  "Duplicate transaction_id": {
                    "value": {
                      "transaction_id": [
                        "A transaction with this transaction_id already exists."
                      ]
                    }
                  },
                  "Invalid category": {
                    "value": {
                      "non_field_errors": [
                        "Unsupported transaction category."
                      ]
                    }
                  },
                  "Missing subject identity": {
                    "value": {
                      "subject": [
                        "subject.vendor_data and subject.full_name are required."
                      ]
                    }
                  },
                  "Blocklisted participant": {
                    "value": {
                      "vendor_data": [
                        "The individual 'user-12345' is in the blocklist and cannot participate in transactions."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot submit transactions for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/transactions/{transaction_id}/": {
      "get": {
        "summary": "Get transaction",
        "description": "Retrieve the full monitoring record for one transaction: parties, score/severity, rule runs, alerts, Travel Rule outcome, remediation session.",
        "operationId": "getTransaction",
        "tags": [
          "Transactions"
        ],
        "parameters": [
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "description": "Didit-stable transaction UUID (the `uuid` returned from create / list, **not** your `txn_id`).",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "abcdef12-3456-7890-abcd-ef1234567890"
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/transactions/abcdef12-3456-7890-abcd-ef1234567890/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nuuid = 'abcdef12-3456-7890-abcd-ef1234567890'\nresp = requests.get(\n    f'https://verification.didit.me/v3/transactions/{uuid}/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    timeout=10,\n)\nresp.raise_for_status()\ntx = resp.json()\nfor alert in tx['alerts']:\n    print(alert.get('code'), alert.get('severity'))"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const uuid = 'abcdef12-3456-7890-abcd-ef1234567890';\nconst resp = await fetch(`https://verification.didit.me/v3/transactions/${uuid}/`, {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n});\nif (!resp.ok) throw new Error(`Lookup failed: ${resp.status}`);\nconst tx = await resp.json();\nconsole.log(tx.status, tx.severity, tx.alerts.length, 'alerts');"
          }
        ],
        "responses": {
          "200": {
            "description": "Full transaction detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                },
                "examples": {
                  "In review with an alert": {
                    "value": {
                      "uuid": "abcdef12-3456-4890-abcd-ef1234567890",
                      "environment": "live",
                      "transaction_number": 4123,
                      "txn_id": "your-txn-2026-05-17-001",
                      "txn_date": "2026-05-17T08:42:00Z",
                      "zone_id": "Europe/Madrid",
                      "transaction_type": "finance",
                      "action_type": "withdrawal",
                      "direction": "OUTBOUND",
                      "status": "IN_REVIEW",
                      "source": "LIVE",
                      "amount": "1500",
                      "currency": "EUR",
                      "currency_type": "fiat",
                      "amount_in_default_currency": "1620.45",
                      "default_currency_code": "USD",
                      "preferred_currency_amount": "1620.45",
                      "preferred_currency_code": "USD",
                      "payment_details": "Withdrawal to crypto wallet",
                      "payment_txn_id": null,
                      "score": 78,
                      "severity": "HIGH",
                      "decision_reason_code": "WALLET_HIGH_RISK",
                      "decision_reason_label": "Destination wallet flagged as high risk",
                      "vendor_data": "user-12345",
                      "metadata": {
                        "subject": {
                          "entity_type": "individual",
                          "vendor_data": "user-12345",
                          "full_name": "Maria Garcia",
                          "address": {},
                          "institution_details": {},
                          "device_context": {}
                        },
                        "counterparty": {}
                      },
                      "props": {
                        "order_id": "ord-9988"
                      },
                      "tags": [],
                      "parties": [
                        {
                          "uuid": "b1111111-2222-4333-8444-555555555555",
                          "role": "APPLICANT",
                          "entity_type": "individual",
                          "kind": "USER",
                          "vendor_data": "user-12345",
                          "full_name": "Maria Garcia",
                          "first_name": null,
                          "last_name": null,
                          "country_code": null,
                          "dob": null,
                          "address": {},
                          "institution_info": {},
                          "device": {},
                          "external_party_snapshot": null
                        }
                      ],
                      "payment_methods": [],
                      "documents": [],
                      "activities": [],
                      "alerts": [
                        {
                          "uuid": "a7b8c9d0-1234-4abc-9def-567890abcdef",
                          "title": "Destination wallet flagged as high risk",
                          "description": "Provider risk score exceeded the configured threshold.",
                          "severity": "HIGH",
                          "status": "OPEN",
                          "source": "RULE",
                          "metadata": {},
                          "created_at": "2026-05-17T08:42:12Z",
                          "due_at": null
                        }
                      ],
                      "rule_runs": [],
                      "provider_results": [],
                      "travel_rule": null,
                      "network_snapshot": null,
                      "remediation": null,
                      "cost_breakdown": null
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot read this application's transactions. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No transaction with this UUID exists for the application (deleted, never created, belongs to another application, or the path segment is not a valid UUID).",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Throttled": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/transactions/sdk-token/": {
      "post": {
        "summary": "Mint an SDK transaction token",
        "description": "Mint a short-lived scoped token your app passes to the Didit SDKs so they can submit transactions directly from the end-user's device via `POST /v1/transactions/`. The token is bound to one `vendor_data` (your user id): every transaction submitted with it has its subject identity enforced server-side from that binding, so a tampered client cannot submit on behalf of another user. Mint tokens from your backend - never ship the API key itself in an app. camelCase aliases (`vendorData`, `ttlSeconds`, `maxUses`) are also accepted.",
        "operationId": "createTransactionSdkToken",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "vendor_data": {
                    "type": "string",
                    "description": "Your internal identifier for the end user this token is scoped to. Enforced as the subject identity of every transaction submitted with the token.",
                    "example": "user-042"
                  },
                  "ttl_seconds": {
                    "type": "integer",
                    "default": 900,
                    "maximum": 86400,
                    "description": "Token lifetime in seconds. Defaults to 900 (15 minutes); maximum 86400 (24 hours)."
                  },
                  "max_uses": {
                    "type": "integer",
                    "nullable": true,
                    "description": "Maximum number of successful submissions allowed with this token. Omit or null for unlimited uses within the TTL."
                  }
                },
                "required": [
                  "vendor_data"
                ]
              },
              "example": {
                "vendor_data": "user-042",
                "ttl_seconds": 900,
                "max_uses": 3
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/transactions/sdk-token/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"vendor_data\": \"user-042\", \"ttl_seconds\": 900, \"max_uses\": 3}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/transactions/sdk-token/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={'vendor_data': 'user-042', 'ttl_seconds': 900, 'max_uses': 3},\n    timeout=10,\n)\nresp.raise_for_status()\ntoken = resp.json()\nprint(token['sdk_token'], token['expires_at'])"
          }
        ],
        "responses": {
          "201": {
            "description": "The minted token. Hand `sdk_token` to your app; it authenticates the device-facing `/v1/transactions/` endpoints via the `X-Transaction-Token` header until `expires_at`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sdk_token": {
                      "type": "string",
                      "description": "The scoped transaction token to pass to the SDK."
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the token stops being accepted."
                    }
                  }
                },
                "example": {
                  "sdk_token": "q7Zt...urlsafe",
                  "expires_at": "2026-07-07T12:15:00Z"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed: missing `vendor_data`, or `ttl_seconds` outside the allowed range.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing vendor_data": {
                    "value": {
                      "vendor_data": [
                        "This field is required."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid API Key": {
                    "value": {
                      "detail": "Invalid API Key."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/": {
      "post": {
        "summary": "Submit a transaction from an SDK",
        "description": "Device-facing endpoint the Didit SDKs call to submit a transaction directly from the end-user's device. Authentication is a scoped token from `POST /v3/transactions/sdk-token/` sent in the `X-Transaction-Token` header instead of an API key, and the endpoint is CORS-enabled so browsers can call it cross-origin. The payload uses the camelCase wire aliases shown below (the SDK `submitTransaction` methods build it for you). Three server-side guarantees: the application is always taken from the token; the subject identity (`externalUserId`) is always enforced from the token's `vendor_data`, so spoofed payload values are ignored; and device intelligence (the SDK device fingerprint plus server-derived IP and user agent) is attached to the subject automatically.",
        "operationId": "submitTransactionFromSdk",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "TransactionTokenAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "txnId": {
                    "type": "string",
                    "description": "Your unique identifier for this transaction (maps to `transaction_id`, max 128 characters).",
                    "example": "wd-2026-07-07-0042"
                  },
                  "txnDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the transaction occurred (maps to `transaction_at`). Defaults to now if omitted."
                  },
                  "zoneId": {
                    "type": "string",
                    "description": "IANA time zone identifier (maps to `time_zone`), e.g. `Europe/Madrid`."
                  },
                  "type": {
                    "type": "string",
                    "description": "Transaction category (maps to `transaction_category`), e.g. `finance`, `kyc`, `travelRule`, `userPlatformEvent`, `gamblingBet`.",
                    "example": "travelRule"
                  },
                  "info": {
                    "type": "object",
                    "description": "Core financial details of the transaction (maps to `transaction_details`).",
                    "required": [
                      "direction",
                      "amount",
                      "currency"
                    ],
                    "properties": {
                      "direction": {
                        "type": "string",
                        "description": "Direction relative to the subject. Case-insensitive; `in`/`out` are accepted as aliases. Echoed back uppercase (`INBOUND`/`OUTBOUND`).",
                        "example": "out"
                      },
                      "amount": {
                        "type": "number",
                        "description": "Transaction amount (up to 18 decimal places). A decimal string is also accepted and is the only way to preserve more than about 15 significant digits: a JSON number is parsed as a binary float first, so `0.123456789012345678` is stored as `0.12345678901234568`.",
                        "example": 0.25
                      },
                      "currency": {
                        "type": "string",
                        "description": "Currency code. Any ISO 4217 alphabetic code is accepted (e.g. `EUR`, `USD`, `NGN`), as is a crypto asset symbol (e.g. `BTC`). Prefer a currently-circulating code. Not every accepted code has an exchange rate: when none is available for the code (for example the ISO accounting unit `XSU`, or a crypto symbol Didit does not price), automatic conversion fails and `preferred_currency_amount` is returned null unless the request supplied a pre-converted `amountInDefaultCurrency`.",
                        "example": "ETH"
                      },
                      "currencyType": {
                        "type": "string",
                        "description": "Whether the currency is `fiat` or `crypto` (maps to `currency_kind`)."
                      },
                      "amountInDefaultCurrency": {
                        "type": "number",
                        "nullable": true,
                        "description": "Pre-converted amount in the default currency (maps to `amount_in_default_currency`). If omitted, automatic FX conversion is attempted."
                      },
                      "defaultCurrencyCode": {
                        "type": "string",
                        "description": "The default currency code for the converted amount (maps to `default_currency`). Any currently-circulating ISO 4217 code."
                      },
                      "paymentDetails": {
                        "type": "string",
                        "nullable": true,
                        "description": "Free-text payment reference or memo (maps to `payment_details`)."
                      },
                      "paymentTxnId": {
                        "type": "string",
                        "nullable": true,
                        "description": "External payment reference (maps to `payment_reference_id`); the on-chain transaction hash for crypto transactions."
                      },
                      "type": {
                        "type": "string",
                        "nullable": true,
                        "description": "Sub-type of the transaction (maps to `action_type`), e.g. `deposit`, `withdrawal`, `transfer`."
                      },
                      "cryptoParams": {
                        "type": "object",
                        "description": "Crypto-specific parameters, e.g. `{\"crypto_chain\": \"ETH\"}`."
                      }
                    }
                  },
                  "subject": {
                    "type": "object",
                    "description": "The subject (applicant) of the transaction. `externalUserId` is ignored here: the subject identity is always enforced from the token's `vendor_data`.",
                    "required": [
                      "fullName"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Entity type (maps to `entity_type`): `individual` (default) or `company`."
                      },
                      "externalUserId": {
                        "type": "string",
                        "description": "Ignored on the subject - enforced server-side from the token's `vendor_data`."
                      },
                      "fullName": {
                        "type": "string",
                        "example": "Jane Doe"
                      },
                      "firstName": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "dob": {
                        "type": "string",
                        "format": "date",
                        "description": "Date of birth (YYYY-MM-DD; maps to `date_of_birth`)."
                      },
                      "address": {
                        "type": "object",
                        "description": "Address object with `country` (ISO 3166-1 alpha-3), `town`, `state`, `street`, `post_code`."
                      },
                      "institutionInfo": {
                        "type": "object",
                        "description": "Institution details for institutional participants (maps to `institution_details`)."
                      },
                      "device": {
                        "type": "object",
                        "description": "Optional explicit device context. Merged with the automatically captured device intelligence; server-derived fields win on conflict."
                      },
                      "paymentMethod": {
                        "type": "object",
                        "description": "Payment method used by the subject (maps to `payment_method`).",
                        "properties": {
                          "type": {
                            "type": "string",
                            "description": "Payment method kind (maps to `method_type`), e.g. `bank_card`, `bank_account`, `crypto_wallet`, `ewallet`, `unhosted_wallet`, `other`."
                          },
                          "accountId": {
                            "type": "string",
                            "description": "Account identifier (maps to `account_id`): IBAN, card fingerprint, or wallet address."
                          },
                          "issuingCountry": {
                            "type": "string",
                            "description": "ISO 3166-1 alpha-3 country code of the issuer (maps to `issuing_country`)."
                          }
                        }
                      }
                    }
                  },
                  "counterparty": {
                    "type": "object",
                    "description": "The counterparty of the transaction (optional). Same shape as `subject`; `externalUserId` is meaningful here.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "Entity type (maps to `entity_type`): `individual` or `company`."
                      },
                      "externalUserId": {
                        "type": "string",
                        "description": "Your internal identifier for the counterparty (maps to `vendor_data`)."
                      },
                      "fullName": {
                        "type": "string"
                      },
                      "firstName": {
                        "type": "string"
                      },
                      "lastName": {
                        "type": "string"
                      },
                      "dob": {
                        "type": "string",
                        "format": "date"
                      },
                      "address": {
                        "type": "object"
                      },
                      "institutionInfo": {
                        "type": "object"
                      },
                      "device": {
                        "type": "object"
                      },
                      "paymentMethod": {
                        "type": "object",
                        "description": "Payment method used by the counterparty (maps to `payment_method`). On travelRule transactions, `type: \"unhosted_wallet\"` declares the counterparty wallet as self-hosted: the transfer skips counterparty-VASP routing, is created directly in `UNCONFIRMED_OWNERSHIP`, and (when `auto_wallet_verification` is enabled) a wallet-ownership widget session is auto-minted and returned in `action_required` so the SDK can launch it.",
                        "properties": {
                          "type": {
                            "type": "string",
                            "description": "Payment method kind (maps to `method_type`), e.g. `bank_card`, `bank_account`, `crypto_wallet`, `ewallet`, `unhosted_wallet`, `other`. Use `unhosted_wallet` to declare a self-hosted wallet for the Travel Rule."
                          },
                          "accountId": {
                            "type": "string",
                            "description": "Account identifier (maps to `account_id`): IBAN, card fingerprint, or wallet address."
                          },
                          "issuingCountry": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "props": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Custom key-value pairs (maps to `custom_properties`). Each key can be referenced in rule conditions as `custom_values.<key>`."
                  },
                  "travelRule": {
                    "type": "object",
                    "description": "Travel Rule details (maps to `travel_rule_details`). When Travel Rule is enabled for the application, Didit ignores any `status` you send and drives the exchange itself.",
                    "required": [
                      "status"
                    ],
                    "properties": {
                      "status": {
                        "type": "string"
                      },
                      "protocol": {
                        "type": "string"
                      },
                      "required": {
                        "type": "boolean"
                      },
                      "obligationsCount": {
                        "type": "integer"
                      },
                      "originatorData": {
                        "type": "object"
                      },
                      "beneficiaryData": {
                        "type": "object"
                      },
                      "metadata": {
                        "type": "object"
                      }
                    }
                  },
                  "includeCryptoScreening": {
                    "type": "boolean",
                    "nullable": true,
                    "description": "Per-transaction override for crypto blockchain analytics screening (maps to `include_crypto_screening`)."
                  },
                  "fingerprint_v2": {
                    "type": "object",
                    "description": "The `didit-fp-v2` device fingerprint payload. Injected automatically by the SDKs; only relevant when calling the wire API directly."
                  }
                },
                "required": [
                  "txnId",
                  "type",
                  "info",
                  "subject"
                ]
              },
              "example": {
                "txnId": "wd-2026-07-07-0042",
                "type": "travelRule",
                "info": {
                  "direction": "out",
                  "amount": "0.25",
                  "currency": "ETH",
                  "currencyType": "crypto",
                  "cryptoParams": {
                    "crypto_chain": "ETH"
                  }
                },
                "subject": {
                  "fullName": "Jane Doe"
                },
                "counterparty": {
                  "fullName": "Ana Diaz",
                  "paymentMethod": {
                    "type": "unhosted_wallet",
                    "accountId": "0xBeneficiaryWallet01"
                  }
                },
                "travelRule": {
                  "status": "AWAITING_COUNTERPARTY",
                  "beneficiaryData": {
                    "wallet_address": "0xBeneficiaryWallet01",
                    "name": "Ana Diaz"
                  }
                },
                "includeCryptoScreening": true
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v1/transactions/ \\\n  -H 'X-Transaction-Token: SDK_TOKEN' -H 'Content-Type: application/json' \\\n  -d '{\"txnId\": \"wd-2026-07-07-0042\", \"type\": \"travelRule\", \"info\": {\"direction\": \"out\", \"amount\": \"0.25\", \"currency\": \"ETH\", \"currencyType\": \"crypto\"}, \"subject\": {\"fullName\": \"Jane Doe\"}, \"counterparty\": {\"fullName\": \"Ana Diaz\", \"paymentMethod\": {\"type\": \"unhosted_wallet\", \"accountId\": \"0xBeneficiaryWallet01\"}}, \"travelRule\": {\"status\": \"AWAITING_COUNTERPARTY\", \"beneficiaryData\": {\"wallet_address\": \"0xBeneficiaryWallet01\", \"name\": \"Ana Diaz\"}}, \"includeCryptoScreening\": true}'"
          },
          {
            "lang": "javascript",
            "label": "Web SDK",
            "source": "import { DiditSdk } from '@didit-protocol/sdk-web';\n\nconst result = await DiditSdk.shared.submitTransaction({\n  transactionToken: sdkToken,\n  transaction: {\n    txnId: 'wd-2026-07-07-0042',\n    category: 'travelRule',\n    details: { direction: 'out', amount: '0.25', currency: 'ETH', currencyType: 'crypto' },\n    subject: { fullName: 'Jane Doe' },\n    counterparty: { fullName: 'Ana Diaz', paymentMethod: { type: 'unhosted_wallet', accountId: '0xBeneficiaryWallet01' } },\n    travelRule: { status: 'AWAITING_COUNTERPARTY', beneficiaryData: { wallet_address: '0xBeneficiaryWallet01', name: 'Ana Diaz' } },\n    includeCryptoScreening: true\n  },\n  onActionCompleted: (refreshed) => console.log(refreshed.status)\n});"
          }
        ],
        "responses": {
          "201": {
            "description": "Transaction submitted and monitored. Same detail shape as `GET /v3/transactions/{transaction_id}/`, including the `action_required` block when the end user must complete a follow-up action (the SDKs auto-launch it by default).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                },
                "examples": {
                  "Wallet ownership required": {
                    "value": {
                      "uuid": "22222222-3333-4444-5555-666666666666",
                      "txn_id": "wd-2026-07-07-0042",
                      "transaction_type": "travelRule",
                      "direction": "OUTBOUND",
                      "status": "AWAITING_USER",
                      "amount": "0.25",
                      "currency": "ETH",
                      "travel_rule": {
                        "uuid": "33333333-4444-5555-6666-777777777777",
                        "status": "ON_HOLD",
                        "required": true
                      },
                      "action_required": {
                        "type": "wallet_ownership",
                        "url": "https://verification.didit.me/wallet-ownership/3s9x...urlsafe",
                        "widget_session_id": "77777777-8888-9999-aaaa-bbbbbbbbbbbb",
                        "expires_at": "2026-07-07T13:00:00Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed (missing required fields, duplicate `txnId`, unknown category).",
            "content": {
              "application/json": {
                "examples": {
                  "Missing fields": {
                    "value": {
                      "info": {
                        "currency": [
                          "This field is required."
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "The transaction token was rejected: missing, unknown, revoked, over its `max_uses`, or expired. Expired-token responses always contain the word `expired` in the detail, which is how the SDKs distinguish `expired_token` from `invalid_token` errors.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "Invalid transaction token."
                    }
                  },
                  "Expired token": {
                    "value": {
                      "detail": "Transaction token expired."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/transactions/{transaction_id}/": {
      "get": {
        "summary": "Get a transaction from an SDK",
        "description": "Device-facing read endpoint, authenticated with the same `X-Transaction-Token` used to submit. The SDKs poll it after an auto-launched action flow completes or its window closes, so the final state never depends on a single notification. Returns the same transaction detail as the submit response, including the current `action_required` block (`null` once the action is resolved).",
        "operationId": "getTransactionFromSdk",
        "tags": [
          "Transactions"
        ],
        "parameters": [
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "description": "Didit-stable transaction UUID (the `uuid` from the submit response, **not** your `txnId`).",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "22222222-3333-4444-5555-666666666666"
          }
        ],
        "security": [
          {
            "TransactionTokenAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v1/transactions/22222222-3333-4444-5555-666666666666/' \\\n  -H 'X-Transaction-Token: SDK_TOKEN'"
          }
        ],
        "responses": {
          "200": {
            "description": "The full transaction detail, including `action_required` (`null` once the pending action is resolved).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionDetail"
                }
              }
            }
          },
          "401": {
            "description": "The transaction token was rejected: missing, unknown, revoked, over its `max_uses`, or expired.",
            "content": {
              "application/json": {
                "examples": {
                  "Expired token": {
                    "value": {
                      "detail": "Transaction token expired."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No transaction with this UUID exists for the token's application, or the path segment is not a valid UUID.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/businesses/": {
      "get": {
        "summary": "List businesses",
        "description": "List [businesses](/entities/businesses) Didit assembles from KYB sessions sharing the same `vendor_data` (free-form string, NOT a UUID), plus businesses created via the API. Paginated, ordered by `last_session_at` desc. This endpoint does not support filtering or search parameters — fetch pages and filter client-side.",
        "operationId": "list_businesses",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size. Defaults to 50 when omitted. There is no enforced maximum, but keep pages small for latency."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset of the first record to return. Prefer following the `next` URL from the previous page over computing this by hand."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/businesses/?limit=50' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/businesses/',\n    headers={'x-api-key': 'YOUR_API_KEY'},\n    params={'limit': 50},\n)\nresp.raise_for_status()\npage = resp.json()\nfor biz in page['results']:\n    print(biz['vendor_data'], biz['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = new URL('https://verification.didit.me/v3/businesses/');\nurl.searchParams.set('limit', '50');\n\nconst page = await fetch(url, {\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY },\n}).then((r) => r.json());\nconsole.log(page.count, page.results.length);"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of businesses with status, session counts, and feature breakdown.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows — exact up to 100, capped at 100 beyond that for performance. Do not use it to detect the last page; rely on `next` being `null` instead."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or `null` on the last page."
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or `null` on the first page."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BusinessListItem"
                      }
                    }
                  }
                },
                "examples": {
                  "Example": {
                    "value": {
                      "count": 1,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "didit_internal_id": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
                          "vendor_data": "company-123",
                          "display_name": null,
                          "legal_name": "Acme Trading Ltd",
                          "registration_number": "12345678",
                          "country_code": "GB",
                          "effective_name": "Acme Trading Ltd",
                          "status": "ACTIVE",
                          "session_count": 2,
                          "approved_count": 1,
                          "declined_count": 0,
                          "in_review_count": 1,
                          "features": {
                            "KYB": "Approved"
                          },
                          "features_list": [
                            {
                              "feature": "KYB",
                              "status": "Approved"
                            }
                          ],
                          "last_session_at": "2026-03-15T10:30:00Z",
                          "last_activity_at": "2026-03-15T10:30:00Z",
                          "first_session_at": "2026-01-10T08:00:00Z",
                          "tags": [
                            {
                              "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                              "name": "VIP",
                              "color": "#2567FF"
                            }
                          ],
                          "created_at": "2026-01-10T08:00:00Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot list businesses for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/customization/": {
      "get": {
        "summary": "Get branding customization",
        "description": "Returns the white-label branding for the application resolved from the API key: colors, fonts, border radii, logo URLs and UI/UX options. Custom domain and white-label email settings are managed only in the Business Console and are not part of this response.",
        "operationId": "get_customization",
        "tags": [
          "Customization"
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/customization/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/customization/',\n    headers={'x-api-key': 'YOUR_API_KEY'},\n)\nresp.raise_for_status()\nbranding = resp.json()\nprint(branding['font_family'], branding['color_primary'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const branding = await fetch(\n  'https://verification.didit.me/v3/customization/',\n  { headers: { 'x-api-key': process.env.DIDIT_API_KEY } },\n).then((r) => r.json());\nconsole.log(branding.font_family, branding.color_primary);"
          }
        ],
        "responses": {
          "200": {
            "description": "Current branding customization for the application.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandingCustomization"
                },
                "examples": {
                  "Default branding": {
                    "value": {
                      "color_primary": "#000000",
                      "color_secondary": "#9DA1A1",
                      "color_background": "#FFFFFF",
                      "color_panel": "#2567FF",
                      "color_panel_10": "#1A1A1A",
                      "color_on_panel_1": "#9DA1A1",
                      "color_on_panel_2": "#F4F4F6",
                      "color_on_background": "#000000",
                      "color_button_1": "#2567FF",
                      "color_button_2": "#F8F8F8",
                      "color_button_text_1": "#FFFFFF",
                      "color_button_text_2": "#000000",
                      "color_pill_text": "#111827",
                      "border_radius_panel": 10,
                      "border_radius_buttons": 12,
                      "font_family": "Inter",
                      "font_weight": "regular",
                      "font_url": "https://fonts.googleapis.com/css2?family=Inter",
                      "logo_square": null,
                      "logo_rectangular": null,
                      "favicon": null,
                      "app_public_name": "Acme Verify",
                      "privacy_policy_url": "https://acme.com/privacy",
                      "skip_welcome_screen": false,
                      "disable_login_with_didit": false,
                      "hide_progress_bar": false,
                      "callback_seconds": 3
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update branding customization",
        "description": "Partial update of the application's white-label branding. Send `application/json` to change colors, fonts, radii and UI options, or `multipart/form-data` to upload logo images. Only the fields you include are changed. Custom domain and white-label email cannot be set through this endpoint — use the Business Console for those.",
        "operationId": "update_customization",
        "tags": [
          "Customization"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandingCustomizationUpdate"
              },
              "examples": {
                "Update colors and font": {
                  "summary": "Change branding colors and font",
                  "value": {
                    "color_primary": "#123456",
                    "color_button_1": "#2567FF",
                    "font_family": "AR One Sans",
                    "border_radius_buttons": 16
                  }
                },
                "Update UI options": {
                  "summary": "Change public name and flow options",
                  "value": {
                    "app_public_name": "Acme Verify",
                    "privacy_policy_url": "https://acme.com/privacy",
                    "skip_welcome_screen": true,
                    "hide_progress_bar": true,
                    "callback_seconds": 5
                  }
                },
                "Remove a logo": {
                  "summary": "Delete the current rectangular logo",
                  "value": {
                    "delete_logo_rectangular": true
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "description": "Use multipart/form-data only to upload logo images. Branding fields above may also be sent as form fields in the same request.",
                "properties": {
                  "image_square": {
                    "type": "string",
                    "format": "binary",
                    "description": "Square logo (1:1 aspect ratio). Max **1 MB**. Allowed: `png`, `jpg`, `jpeg`, `webp`."
                  },
                  "image_rectangular": {
                    "type": "string",
                    "format": "binary",
                    "description": "Rectangular logo (2:1 aspect ratio). Max **1 MB**. Allowed: `png`, `jpg`, `jpeg`, `webp`."
                  },
                  "image_favicon": {
                    "type": "string",
                    "format": "binary",
                    "description": "Favicon image. Max **500 KB**."
                  }
                }
              },
              "example": {
                "image_rectangular": "(binary PNG logo, 2:1)",
                "image_favicon": "(binary favicon)"
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/customization/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"color_primary\": \"#123456\", \"font_family\": \"AR One Sans\"}'"
          },
          {
            "lang": "curl",
            "label": "curl (logo upload)",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/customization/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'image_rectangular=@logo.png' \\\n  -F 'image_favicon=@favicon.ico'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.patch(\n    'https://verification.didit.me/v3/customization/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'color_primary': '#123456', 'font_family': 'AR One Sans'},\n)\nresp.raise_for_status()\nprint(resp.json()['color_primary'])\n\n# Upload a logo (multipart):\nwith open('logo.png', 'rb') as logo:\n    requests.patch(\n        'https://verification.didit.me/v3/customization/',\n        headers={'x-api-key': 'YOUR_API_KEY'},\n        files={'image_rectangular': logo},\n    )"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/customization/', {\n  method: 'PATCH',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ color_primary: '#123456', font_family: 'AR One Sans' }),\n});\nconst branding = await resp.json();\nconsole.log(branding.color_primary);"
          }
        ],
        "responses": {
          "200": {
            "description": "Branding updated. The FULL branding object is returned (all fields, not just the ones you changed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandingCustomization"
                },
                "examples": {
                  "Updated": {
                    "value": {
                      "color_primary": "#123456",
                      "color_secondary": "#9DA1A1",
                      "color_background": "#FFFFFF",
                      "color_panel": "#2567FF",
                      "color_panel_10": "#1A1A1A",
                      "color_on_panel_1": "#9DA1A1",
                      "color_on_panel_2": "#F4F4F6",
                      "color_on_background": "#000000",
                      "color_button_1": "#2567FF",
                      "color_button_2": "#F8F8F8",
                      "color_button_text_1": "#FFFFFF",
                      "color_button_text_2": "#000000",
                      "color_pill_text": "#111827",
                      "border_radius_panel": 10,
                      "border_radius_buttons": 16,
                      "font_family": "AR One Sans",
                      "font_weight": "400",
                      "font_url": "https://fonts.googleapis.com/css2?family=AR+One+Sans",
                      "logo_square": null,
                      "logo_rectangular": "https://cdn.didit.me/white_label/logo_rectangular/...",
                      "favicon": null,
                      "app_public_name": "Acme Verify",
                      "privacy_policy_url": "https://acme.com/privacy",
                      "skip_welcome_screen": true,
                      "disable_login_with_didit": false,
                      "hide_progress_bar": false,
                      "callback_seconds": 3
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body — e.g. malformed hex color, unknown font family or weight, a logo failing the size/aspect-ratio check, or a Business-Console-only field (`domain`, `from_email`, `verify_domain`, `force_remove_domain`, `verify_email_domain`, `force_remove_email_domain`, and their read-only companions). Also returned when setting `disable_login_with_didit` to `false` while a custom domain is configured.",
            "content": {
              "application/json": {
                "examples": {
                  "Bad color": {
                    "value": {
                      "color_primary": [
                        "Invalid color format. Use '#RRGGBB' or '#RRGGBBAA' format."
                      ]
                    }
                  },
                  "Bad logo": {
                    "value": {
                      "image_rectangular": [
                        "Image aspect ratio must be 2:1. Got 1024x1024 image dimensions"
                      ]
                    }
                  },
                  "Console-only field": {
                    "value": {
                      "domain": [
                        "Manage this field in the Business Console."
                      ]
                    }
                  },
                  "Bad font weight": {
                    "value": {
                      "font_weight": [
                        "Font weight 950 is not available for Inter. Available weights are: 100, 200, 300, 400, 500, 600, 700, 800, 900"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key missing, malformed, expired, or scoped to a different application. Didit returns 403 (never 401) for all authentication failures on this endpoint.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid token": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry with exponential backoff."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/businesses/{vendor_data}/": {
      "get": {
        "summary": "Get business",
        "description": "Fetch one [business](/entities/businesses) by `vendor_data` (exact match). Adds `metadata` and `updated_at` to the list view. Deleted businesses return 404.",
        "operationId": "get_business",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the business — a free-form string (NOT a UUID), matched exactly as sent.",
            "example": "company-123"
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/businesses/company-123/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/businesses/company-123/',\n    headers={'x-api-key': 'YOUR_API_KEY'},\n)\nresp.raise_for_status()\nbiz = resp.json()\nprint(biz['didit_internal_id'], biz['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const vendorData = encodeURIComponent('company-123');\nconst biz = await fetch(\n  `https://verification.didit.me/v3/businesses/${vendorData}/`,\n  { headers: { 'x-api-key': process.env.DIDIT_API_KEY } },\n).then((r) => r.json());\nconsole.log(biz.didit_internal_id, biz.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "Full business detail including metadata and aggregated session data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessDetailItem"
                },
                "examples": {
                  "Active business": {
                    "value": {
                      "didit_internal_id": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
                      "vendor_data": "company-123",
                      "display_name": null,
                      "legal_name": "Acme Trading Ltd",
                      "registration_number": "12345678",
                      "country_code": "GB",
                      "effective_name": "Acme Trading Ltd",
                      "status": "ACTIVE",
                      "session_count": 2,
                      "approved_count": 1,
                      "declined_count": 0,
                      "in_review_count": 1,
                      "features": {
                        "KYB": "Approved"
                      },
                      "features_list": [
                        {
                          "feature": "KYB",
                          "status": "Approved"
                        }
                      ],
                      "last_session_at": "2026-03-15T10:30:00Z",
                      "last_activity_at": "2026-03-15T10:30:00Z",
                      "first_session_at": "2026-01-10T08:00:00Z",
                      "tags": [
                        {
                          "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                          "name": "VIP",
                          "color": "#2567FF"
                        }
                      ],
                      "created_at": "2026-01-10T08:00:00Z",
                      "metadata": {
                        "industry": "fintech"
                      },
                      "updated_at": "2026-03-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot read this application's businesses. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No (non-deleted) business with the supplied `vendor_data` exists for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update business",
        "description": "Partial update of a business: `display_name`, `legal_name`, `registration_number`, `country_code`, `status`, `metadata`. `metadata` fully replaces. Setting `status` to `BLOCKED` adds the `vendor_data` to the system blocklist; moving away from `BLOCKED` removes that entry.",
        "operationId": "update_business",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the business (free-form string, NOT a UUID).",
            "example": "company-123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Partial-update body. Provide only the fields you want to change.",
                "properties": {
                  "display_name": {
                    "type": "string",
                    "nullable": true,
                    "description": "Friendly display name shown in the console (takes precedence over `legal_name` for UI display)."
                  },
                  "legal_name": {
                    "type": "string",
                    "nullable": true,
                    "description": "Official legal name from registry or manual entry."
                  },
                  "registration_number": {
                    "type": "string",
                    "nullable": true,
                    "description": "Company registration or incorporation number."
                  },
                  "country_code": {
                    "type": "string",
                    "nullable": true,
                    "description": "Country of incorporation (ISO 3166-1 alpha-2, e.g. `GB`, `US`)."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "FLAGGED",
                      "BLOCKED"
                    ],
                    "description": "Business lifecycle status. Setting `BLOCKED` automatically adds the `vendor_data` to the system blocklist; flipping away from `BLOCKED` removes that blocklist entry."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Arbitrary JSON object you attach to the business. **Fully replaces** the existing metadata on update — merge client-side if you only want to add keys."
                  }
                }
              },
              "examples": {
                "Update name": {
                  "summary": "Update display name",
                  "value": {
                    "display_name": "Acme Corp"
                  }
                },
                "Flag for review": {
                  "summary": "Flip status",
                  "value": {
                    "status": "FLAGGED"
                  }
                },
                "Add metadata": {
                  "summary": "Replace metadata JSON",
                  "value": {
                    "metadata": {
                      "industry": "fintech",
                      "risk_level": "low"
                    }
                  }
                },
                "Fix registry data": {
                  "summary": "Correct extracted fields",
                  "value": {
                    "legal_name": "Acme Trading International Ltd",
                    "registration_number": "12345678",
                    "country_code": "GB"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/businesses/company-123/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"display_name\": \"Acme Corp\", \"status\": \"FLAGGED\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.patch(\n    'https://verification.didit.me/v3/businesses/company-123/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'display_name': 'Acme Corp', 'status': 'FLAGGED'},\n)\nresp.raise_for_status()\nprint(resp.json()['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/businesses/company-123/', {\n  method: 'PATCH',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ display_name: 'Acme Corp', status: 'FLAGGED' }),\n});\nconst biz = await resp.json();\nconsole.log(biz.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "Business updated. The full updated business record is returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessDetailItem"
                },
                "examples": {
                  "Updated": {
                    "value": {
                      "didit_internal_id": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
                      "vendor_data": "company-123",
                      "display_name": "Acme Corp",
                      "legal_name": "Acme Trading Ltd",
                      "registration_number": "12345678",
                      "country_code": "GB",
                      "effective_name": "Acme Corp",
                      "status": "FLAGGED",
                      "session_count": 2,
                      "approved_count": 1,
                      "declined_count": 0,
                      "in_review_count": 1,
                      "features": {
                        "KYB": "Approved"
                      },
                      "features_list": [
                        {
                          "feature": "KYB",
                          "status": "Approved"
                        }
                      ],
                      "last_session_at": "2026-03-15T10:30:00Z",
                      "last_activity_at": "2026-03-15T10:30:00Z",
                      "first_session_at": "2026-01-10T08:00:00Z",
                      "tags": [
                        {
                          "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                          "name": "VIP",
                          "color": "#2567FF"
                        }
                      ],
                      "created_at": "2026-01-10T08:00:00Z",
                      "metadata": {
                        "industry": "fintech",
                        "risk_level": "low"
                      },
                      "updated_at": "2026-03-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body — typically an unknown `status` or malformed `metadata`.",
            "content": {
              "application/json": {
                "examples": {
                  "Bad status": {
                    "value": {
                      "status": [
                        "Invalid status. Valid options are: ACTIVE, FLAGGED, BLOCKED"
                      ]
                    }
                  },
                  "Bad metadata": {
                    "value": {
                      "metadata": [
                        "Metadata must be a JSON object."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot update businesses for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No (non-deleted) business with the supplied `vendor_data` exists for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/businesses/{vendor_data}/update-status/": {
      "patch": {
        "summary": "Update business status",
        "description": "Flip only the lifecycle `status` of a business — VendorBusinessStatusChoices (`ACTIVE`/`FLAGGED`/`BLOCKED`, NOT session statuses). `BLOCKED` adds `vendor_data` to the system blocklist.",
        "operationId": "update_business_status",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the business (free-form string, NOT a UUID).",
            "example": "company-123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "FLAGGED",
                      "BLOCKED"
                    ],
                    "description": "New lifecycle status. `BLOCKED` also adds the `vendor_data` to the system blocklist."
                  }
                }
              },
              "examples": {
                "Flag": {
                  "summary": "Flag the business for review",
                  "value": {
                    "status": "FLAGGED"
                  }
                },
                "Block": {
                  "summary": "Block the business (adds to system blocklist)",
                  "value": {
                    "status": "BLOCKED"
                  }
                },
                "Reactivate": {
                  "summary": "Reactivate the business",
                  "value": {
                    "status": "ACTIVE"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/businesses/company-123/update-status/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"status\": \"BLOCKED\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.patch(\n    'https://verification.didit.me/v3/businesses/company-123/update-status/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'status': 'BLOCKED'},\n)\nresp.raise_for_status()\nprint(resp.json()['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/businesses/company-123/update-status/', {\n  method: 'PATCH',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ status: 'BLOCKED' }),\n});\nconst biz = await resp.json();\nconsole.log(biz.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "Business status updated. Full business record returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessDetailItem"
                },
                "examples": {
                  "Blocked": {
                    "value": {
                      "didit_internal_id": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
                      "vendor_data": "company-123",
                      "display_name": null,
                      "legal_name": "Acme Trading Ltd",
                      "registration_number": "12345678",
                      "country_code": "GB",
                      "effective_name": "Acme Trading Ltd",
                      "status": "BLOCKED",
                      "session_count": 2,
                      "approved_count": 1,
                      "declined_count": 0,
                      "in_review_count": 1,
                      "features": {
                        "KYB": "Approved"
                      },
                      "features_list": [
                        {
                          "feature": "KYB",
                          "status": "Approved"
                        }
                      ],
                      "last_session_at": "2026-03-15T10:30:00Z",
                      "last_activity_at": "2026-03-15T10:30:00Z",
                      "first_session_at": "2026-01-10T08:00:00Z",
                      "tags": [
                        {
                          "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                          "name": "VIP",
                          "color": "#2567FF"
                        }
                      ],
                      "created_at": "2026-01-10T08:00:00Z",
                      "metadata": {
                        "industry": "fintech"
                      },
                      "updated_at": "2026-03-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid `status`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing status": {
                    "value": {
                      "status": [
                        "This field is required."
                      ]
                    }
                  },
                  "Bad status": {
                    "value": {
                      "status": [
                        "Invalid status. Valid options are: ACTIVE, FLAGGED, BLOCKED"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot update businesses for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No (non-deleted) business with the supplied `vendor_data` exists for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/businesses/delete/": {
      "post": {
        "summary": "Batch delete businesses",
        "description": "**Permanently delete** businesses — this cannot be undone. For blocking prefer [Update Business Status](#patch-/v3/businesses/-vendor_data-/update-status/) with `BLOCKED`.",
        "operationId": "batch_delete_businesses",
        "tags": [
          "Businesses"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Provide `vendor_data_list`, `didit_internal_id_list`, or `delete_all: true`. Precedence when several are sent: `delete_all` > `vendor_data_list` > `didit_internal_id_list` (only the highest-precedence selector is used).",
                "properties": {
                  "vendor_data_list": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Your own identifiers to delete, matched exactly as sent."
                  },
                  "didit_internal_id_list": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Didit's internal UUIDs (`didit_internal_id`) to delete."
                  },
                  "delete_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "If `true`, deletes every business in the application. Cannot be combined with the list selectors."
                  }
                }
              },
              "examples": {
                "Specific businesses": {
                  "summary": "Delete by vendor_data",
                  "value": {
                    "vendor_data_list": [
                      "company-123",
                      "company-456"
                    ]
                  }
                },
                "Specific internal IDs": {
                  "summary": "Delete by didit_internal_id",
                  "value": {
                    "didit_internal_id_list": [
                      "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                      "b2c3d4e5-f6a7-8901-bcde-f12345678901"
                    ]
                  }
                },
                "All businesses": {
                  "summary": "Wipe every business in this application",
                  "value": {
                    "delete_all": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/businesses/delete/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"vendor_data_list\": [\"company-123\", \"company-456\"]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/businesses/delete/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'vendor_data_list': ['company-123', 'company-456']},\n)\nresp.raise_for_status()\nprint('deleted', resp.json()['deleted'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/businesses/delete/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ vendor_data_list: ['company-123', 'company-456'] }),\n});\nconst body = await resp.json();\nconsole.log('deleted', body.deleted);"
          }
        ],
        "responses": {
          "200": {
            "description": "Businesses deleted. Returns the number of rows actually removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "integer",
                      "description": "Number of businesses deleted (excludes vendor_data values that didn't match anything)."
                    }
                  }
                },
                "examples": {
                  "Deleted some": {
                    "value": {
                      "deleted": 2
                    }
                  },
                  "Nothing matched": {
                    "value": {
                      "deleted": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No selector supplied (all of `vendor_data_list`, `didit_internal_id_list`, and `delete_all` missing or empty). The error body is a JSON array.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing selector": {
                    "value": [
                      "Provide vendor_data_list, didit_internal_id_list, or set delete_all=true."
                    ]
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot delete businesses for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/users/aml-monitoring/": {
      "post": {
        "summary": "Enable or disable AML ongoing monitoring for users",
        "description": "Turns AML ongoing monitoring on or off for the selected users, with the same semantics as the Business Console. Exactly one monitored AML screening is kept per user, so a profile that verified several times is monitored and billed once; disabling turns monitoring off across all of the profile's screenings. Users without any AML screening are screened first (billed as a regular AML screening) when they have the full name, date of birth and country needed; otherwise they are reported as `skipped_no_identity_data`.\n\nSet `estimate_only: true` to preview counts and costs without writing anything. Selections of 20 profiles or fewer resolve inline and return `200` with the completed job; larger selections return `202` and run in the background - poll [Get AML monitoring job](#get-/v3/aml-monitoring/jobs/-job_id-/) with the returned `job_id`. Enabling is refused with `403` when the organization balance does not cover the estimate. Identifiers that match nothing are listed in `unmatched` and never fail the request: a selection that matches nothing completes as an empty job (`total` 0), the same convention as the batch delete endpoints.",
        "operationId": "toggle_users_aml_monitoring",
        "tags": [
          "AML Ongoing Monitoring"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_enabled"
                ],
                "description": "Select users with `vendor_data_list`, `didit_internal_id_list`, or both (the two lists are OR'd). At most 1000 identifiers per request across both lists.",
                "properties": {
                  "is_enabled": {
                    "type": "boolean",
                    "description": "true to enable monitoring, false to disable it."
                  },
                  "estimate_only": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, returns the cost estimate and performs no writes - no screening, no billing, no job."
                  },
                  "vendor_data_list": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Your own identifiers of the users to toggle, matched exactly as sent."
                  },
                  "didit_internal_id_list": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Didit internal ids of the users to toggle - the `didit_internal_id` returned by the create, get and list endpoints."
                  }
                }
              },
              "examples": {
                "Estimate first": {
                  "summary": "Preview the cost without writing",
                  "value": {
                    "is_enabled": true,
                    "estimate_only": true,
                    "vendor_data_list": [
                      "user-123",
                      "user-456"
                    ]
                  }
                },
                "Enable": {
                  "summary": "Enable monitoring for two users",
                  "value": {
                    "is_enabled": true,
                    "vendor_data_list": [
                      "user-123",
                      "user-456"
                    ]
                  }
                },
                "Disable": {
                  "summary": "Disable monitoring by Didit internal id",
                  "value": {
                    "is_enabled": false,
                    "didit_internal_id_list": [
                      "3f1c0d3e-8f0a-4c2e-9a3d-9b1f5f4a2c11"
                    ]
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/users/aml-monitoring/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"is_enabled\": true, \"vendor_data_list\": [\"user-123\", \"user-456\"]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/users/aml-monitoring/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'is_enabled': True, 'vendor_data_list': ['user-123', 'user-456']},\n)\nresp.raise_for_status()\njob = resp.json()\nprint(job['status'], job['outcomes'])\nfor row in job['results']:\n    print(row['vendor_data'], row['outcome'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/users/aml-monitoring/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ is_enabled: true, vendor_data_list: ['user-123', 'user-456'] }),\n});\nconst job = await resp.json();\nconsole.log(job.status, job.outcomes);\nfor (const row of job.results) console.log(row.vendor_data, row.outcome);"
          }
        ],
        "responses": {
          "200": {
            "description": "The estimate (when `estimate_only` is true) or the completed job for a selection processed inline.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "required": [
                        "users_total",
                        "already_enabled",
                        "with_existing_aml",
                        "needing_screening",
                        "skipped_no_identity_data",
                        "skipped_blocked",
                        "estimated_screening_cost_usd",
                        "estimated_annual_monitoring_cost_usd",
                        "balance_sufficient",
                        "unmatched"
                      ],
                      "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Profiles matched by the selection."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Profiles that cannot be screened because identity data is missing."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Blocked users that will be skipped (always 0 for businesses)."
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2,
                          "description": "One-time cost of the new screenings."
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07,
                          "description": "Yearly monitoring cost of the profiles that will become monitored."
                        },
                        "balance_sufficient": {
                          "type": "boolean",
                          "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Identifiers of the request that matched no profile in this application, exactly as sent."
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "job_id",
                        "status",
                        "is_enabled",
                        "target_type",
                        "total",
                        "processed",
                        "outcomes",
                        "results",
                        "error",
                        "created_at",
                        "completed_at",
                        "estimate",
                        "unmatched"
                      ],
                      "properties": {
                        "job_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "PENDING",
                            "PROCESSING",
                            "COMPLETED",
                            "FAILED"
                          ]
                        },
                        "is_enabled": {
                          "type": "boolean",
                          "description": "true when the job enables monitoring, false when it disables it."
                        },
                        "target_type": {
                          "type": "string",
                          "enum": [
                            "user",
                            "business"
                          ],
                          "description": "Which profile family the job toggles."
                        },
                        "total": {
                          "type": "integer",
                          "description": "Profiles the job processes."
                        },
                        "processed": {
                          "type": "integer",
                          "description": "Profiles processed so far."
                        },
                        "outcomes": {
                          "type": "object",
                          "description": "Per-record outcome counters. Every selected profile resolves to exactly one counter; nothing is silently skipped.",
                          "properties": {
                            "enabled": {
                              "type": "integer",
                              "description": "Monitoring enabled on an existing AML screening."
                            },
                            "screened_and_enabled": {
                              "type": "integer",
                              "description": "A new AML screening was created (billed) and monitoring enabled on it."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Monitoring was already active; nothing changed and nothing was billed."
                            },
                            "disabled": {
                              "type": "integer",
                              "description": "Monitoring turned off across every AML screening of the profile."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Skipped: the profile lacks the full name, date of birth and country (users) or a name (businesses) needed to screen."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Skipped: the user is blocked."
                            },
                            "skipped_sandbox": {
                              "type": "integer",
                              "description": "Skipped: sandbox application, no screening is created."
                            },
                            "failed_provider": {
                              "type": "integer",
                              "description": "The screening could not be completed; retry later."
                            },
                            "failed_insufficient_balance": {
                              "type": "integer",
                              "description": "Balance ran out while the job was running."
                            }
                          }
                        },
                        "results": {
                          "type": "array",
                          "description": "One entry per processed profile, in processing order. Grows while the job runs; complete once status is COMPLETED. Recorded for jobs started through the API.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "didit_internal_id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Didit internal id of the profile."
                              },
                              "vendor_data": {
                                "type": "string",
                                "nullable": true,
                                "description": "Your own identifier for the profile."
                              },
                              "outcome": {
                                "type": "string",
                                "enum": [
                                  "enabled",
                                  "screened_and_enabled",
                                  "already_enabled",
                                  "disabled",
                                  "skipped_no_identity_data",
                                  "skipped_blocked",
                                  "skipped_sandbox",
                                  "failed_provider",
                                  "failed_insufficient_balance"
                                ]
                              }
                            }
                          }
                        },
                        "error": {
                          "type": "string",
                          "nullable": true,
                          "description": "Generic failure message when status is FAILED; the detailed cause is kept on the platform side."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "completed_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        },
                        "estimate": {
                          "type": "object",
                          "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                          "properties": {
                            "users_total": {
                              "type": "integer",
                              "description": "Profiles matched by the selection."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                            },
                            "with_existing_aml": {
                              "type": "integer",
                              "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                            },
                            "needing_screening": {
                              "type": "integer",
                              "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Profiles that cannot be screened because identity data is missing."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Blocked users that will be skipped (always 0 for businesses)."
                            },
                            "estimated_screening_cost_usd": {
                              "type": "number",
                              "example": 0.2,
                              "description": "One-time cost of the new screenings."
                            },
                            "estimated_annual_monitoring_cost_usd": {
                              "type": "number",
                              "example": 0.07,
                              "description": "Yearly monitoring cost of the profiles that will become monitored."
                            },
                            "balance_sufficient": {
                              "type": "boolean",
                              "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                            }
                          }
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Identifiers of the request that matched no profile in this application, exactly as sent. They are not part of the job."
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Larger selections run in the background. Poll the job endpoint with `job_id`; `results` fills in as profiles are processed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean",
                      "description": "true when the job enables monitoring, false when it disables it."
                    },
                    "target_type": {
                      "type": "string",
                      "enum": [
                        "user",
                        "business"
                      ],
                      "description": "Which profile family the job toggles."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Profiles the job processes."
                    },
                    "processed": {
                      "type": "integer",
                      "description": "Profiles processed so far."
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-record outcome counters. Every selected profile resolves to exactly one counter; nothing is silently skipped.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled on it."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active; nothing changed and nothing was billed."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring turned off across every AML screening of the profile."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: the profile lacks the full name, date of birth and country (users) or a name (businesses) needed to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application, no screening is created."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening could not be completed; retry later."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out while the job was running."
                        }
                      }
                    },
                    "results": {
                      "type": "array",
                      "description": "One entry per processed profile, in processing order. Grows while the job runs; complete once status is COMPLETED. Recorded for jobs started through the API.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "didit_internal_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Didit internal id of the profile."
                          },
                          "vendor_data": {
                            "type": "string",
                            "nullable": true,
                            "description": "Your own identifier for the profile."
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "enabled",
                              "screened_and_enabled",
                              "already_enabled",
                              "disabled",
                              "skipped_no_identity_data",
                              "skipped_blocked",
                              "skipped_sandbox",
                              "failed_provider",
                              "failed_insufficient_balance"
                            ]
                          }
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true,
                      "description": "Generic failure message when status is FAILED; the detailed cause is kept on the platform side."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "completed_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Profiles matched by the selection."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Profiles that cannot be screened because identity data is missing."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Blocked users that will be skipped (always 0 for businesses)."
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2,
                          "description": "One-time cost of the new screenings."
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07,
                          "description": "Yearly monitoring cost of the profiles that will become monitored."
                        },
                        "balance_sufficient": {
                          "type": "boolean",
                          "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                        }
                      }
                    },
                    "unmatched": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Identifiers of the request that matched no profile in this application, exactly as sent. They are not part of the job."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error: `is_enabled` missing, no selector, or more than 1000 identifiers across both lists."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Insufficient balance to enable monitoring for this selection. The response carries the `estimate` so you can top up the right amount.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Profiles matched by the selection."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Profiles that cannot be screened because identity data is missing."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Blocked users that will be skipped (always 0 for businesses)."
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2,
                          "description": "One-time cost of the new screenings."
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07,
                          "description": "Yearly monitoring cost of the profiles that will become monitored."
                        },
                        "balance_sufficient": {
                          "type": "boolean",
                          "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/businesses/aml-monitoring/": {
      "post": {
        "summary": "Enable or disable AML ongoing monitoring for businesses",
        "description": "Turns AML ongoing monitoring on or off for the selected businesses, with the same semantics as the Business Console. Exactly one monitored AML screening is kept per business, so a profile that verified several times is monitored and billed once; disabling turns monitoring off across all of the profile's screenings. Businesses without any AML screening are screened first (billed as a regular AML screening) when they have the legal or display name needed; otherwise they are reported as `skipped_no_identity_data`.\n\nSet `estimate_only: true` to preview counts and costs without writing anything. Selections of 20 profiles or fewer resolve inline and return `200` with the completed job; larger selections return `202` and run in the background - poll [Get AML monitoring job](#get-/v3/aml-monitoring/jobs/-job_id-/) with the returned `job_id`. Enabling is refused with `403` when the organization balance does not cover the estimate. Identifiers that match nothing are listed in `unmatched` and never fail the request: a selection that matches nothing completes as an empty job (`total` 0), the same convention as the batch delete endpoints.",
        "operationId": "toggle_businesses_aml_monitoring",
        "tags": [
          "AML Ongoing Monitoring"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_enabled"
                ],
                "description": "Select businesses with `vendor_data_list`, `didit_internal_id_list`, or both (the two lists are OR'd). At most 1000 identifiers per request across both lists.",
                "properties": {
                  "is_enabled": {
                    "type": "boolean",
                    "description": "true to enable monitoring, false to disable it."
                  },
                  "estimate_only": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, returns the cost estimate and performs no writes - no screening, no billing, no job."
                  },
                  "vendor_data_list": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Your own identifiers of the businesses to toggle, matched exactly as sent."
                  },
                  "didit_internal_id_list": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Didit internal ids of the businesses to toggle - the `didit_internal_id` returned by the create, get and list endpoints."
                  }
                }
              },
              "examples": {
                "Estimate first": {
                  "summary": "Preview the cost without writing",
                  "value": {
                    "is_enabled": true,
                    "estimate_only": true,
                    "vendor_data_list": [
                      "company-123",
                      "company-456"
                    ]
                  }
                },
                "Enable": {
                  "summary": "Enable monitoring for two businesses",
                  "value": {
                    "is_enabled": true,
                    "vendor_data_list": [
                      "company-123",
                      "company-456"
                    ]
                  }
                },
                "Disable": {
                  "summary": "Disable monitoring by Didit internal id",
                  "value": {
                    "is_enabled": false,
                    "didit_internal_id_list": [
                      "3f1c0d3e-8f0a-4c2e-9a3d-9b1f5f4a2c11"
                    ]
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/businesses/aml-monitoring/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"is_enabled\": true, \"vendor_data_list\": [\"company-123\", \"company-456\"]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/businesses/aml-monitoring/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'is_enabled': True, 'vendor_data_list': ['company-123', 'company-456']},\n)\nresp.raise_for_status()\njob = resp.json()\nprint(job['status'], job['outcomes'])\nfor row in job['results']:\n    print(row['vendor_data'], row['outcome'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/businesses/aml-monitoring/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ is_enabled: true, vendor_data_list: ['company-123', 'company-456'] }),\n});\nconst job = await resp.json();\nconsole.log(job.status, job.outcomes);\nfor (const row of job.results) console.log(row.vendor_data, row.outcome);"
          }
        ],
        "responses": {
          "200": {
            "description": "The estimate (when `estimate_only` is true) or the completed job for a selection processed inline.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "required": [
                        "users_total",
                        "already_enabled",
                        "with_existing_aml",
                        "needing_screening",
                        "skipped_no_identity_data",
                        "skipped_blocked",
                        "estimated_screening_cost_usd",
                        "estimated_annual_monitoring_cost_usd",
                        "balance_sufficient",
                        "unmatched"
                      ],
                      "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Profiles matched by the selection."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Profiles that cannot be screened because identity data is missing."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Blocked users that will be skipped (always 0 for businesses)."
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2,
                          "description": "One-time cost of the new screenings."
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07,
                          "description": "Yearly monitoring cost of the profiles that will become monitored."
                        },
                        "balance_sufficient": {
                          "type": "boolean",
                          "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Identifiers of the request that matched no profile in this application, exactly as sent."
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "job_id",
                        "status",
                        "is_enabled",
                        "target_type",
                        "total",
                        "processed",
                        "outcomes",
                        "results",
                        "error",
                        "created_at",
                        "completed_at",
                        "estimate",
                        "unmatched"
                      ],
                      "properties": {
                        "job_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "PENDING",
                            "PROCESSING",
                            "COMPLETED",
                            "FAILED"
                          ]
                        },
                        "is_enabled": {
                          "type": "boolean",
                          "description": "true when the job enables monitoring, false when it disables it."
                        },
                        "target_type": {
                          "type": "string",
                          "enum": [
                            "user",
                            "business"
                          ],
                          "description": "Which profile family the job toggles."
                        },
                        "total": {
                          "type": "integer",
                          "description": "Profiles the job processes."
                        },
                        "processed": {
                          "type": "integer",
                          "description": "Profiles processed so far."
                        },
                        "outcomes": {
                          "type": "object",
                          "description": "Per-record outcome counters. Every selected profile resolves to exactly one counter; nothing is silently skipped.",
                          "properties": {
                            "enabled": {
                              "type": "integer",
                              "description": "Monitoring enabled on an existing AML screening."
                            },
                            "screened_and_enabled": {
                              "type": "integer",
                              "description": "A new AML screening was created (billed) and monitoring enabled on it."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Monitoring was already active; nothing changed and nothing was billed."
                            },
                            "disabled": {
                              "type": "integer",
                              "description": "Monitoring turned off across every AML screening of the profile."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Skipped: the profile lacks the full name, date of birth and country (users) or a name (businesses) needed to screen."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Skipped: the user is blocked."
                            },
                            "skipped_sandbox": {
                              "type": "integer",
                              "description": "Skipped: sandbox application, no screening is created."
                            },
                            "failed_provider": {
                              "type": "integer",
                              "description": "The screening could not be completed; retry later."
                            },
                            "failed_insufficient_balance": {
                              "type": "integer",
                              "description": "Balance ran out while the job was running."
                            }
                          }
                        },
                        "results": {
                          "type": "array",
                          "description": "One entry per processed profile, in processing order. Grows while the job runs; complete once status is COMPLETED. Recorded for jobs started through the API.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "didit_internal_id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Didit internal id of the profile."
                              },
                              "vendor_data": {
                                "type": "string",
                                "nullable": true,
                                "description": "Your own identifier for the profile."
                              },
                              "outcome": {
                                "type": "string",
                                "enum": [
                                  "enabled",
                                  "screened_and_enabled",
                                  "already_enabled",
                                  "disabled",
                                  "skipped_no_identity_data",
                                  "skipped_blocked",
                                  "skipped_sandbox",
                                  "failed_provider",
                                  "failed_insufficient_balance"
                                ]
                              }
                            }
                          }
                        },
                        "error": {
                          "type": "string",
                          "nullable": true,
                          "description": "Generic failure message when status is FAILED; the detailed cause is kept on the platform side."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "completed_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true
                        },
                        "estimate": {
                          "type": "object",
                          "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                          "properties": {
                            "users_total": {
                              "type": "integer",
                              "description": "Profiles matched by the selection."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                            },
                            "with_existing_aml": {
                              "type": "integer",
                              "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                            },
                            "needing_screening": {
                              "type": "integer",
                              "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Profiles that cannot be screened because identity data is missing."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Blocked users that will be skipped (always 0 for businesses)."
                            },
                            "estimated_screening_cost_usd": {
                              "type": "number",
                              "example": 0.2,
                              "description": "One-time cost of the new screenings."
                            },
                            "estimated_annual_monitoring_cost_usd": {
                              "type": "number",
                              "example": 0.07,
                              "description": "Yearly monitoring cost of the profiles that will become monitored."
                            },
                            "balance_sufficient": {
                              "type": "boolean",
                              "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                            }
                          }
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Identifiers of the request that matched no profile in this application, exactly as sent. They are not part of the job."
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Larger selections run in the background. Poll the job endpoint with `job_id`; `results` fills in as profiles are processed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean",
                      "description": "true when the job enables monitoring, false when it disables it."
                    },
                    "target_type": {
                      "type": "string",
                      "enum": [
                        "user",
                        "business"
                      ],
                      "description": "Which profile family the job toggles."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Profiles the job processes."
                    },
                    "processed": {
                      "type": "integer",
                      "description": "Profiles processed so far."
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-record outcome counters. Every selected profile resolves to exactly one counter; nothing is silently skipped.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled on it."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active; nothing changed and nothing was billed."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring turned off across every AML screening of the profile."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: the profile lacks the full name, date of birth and country (users) or a name (businesses) needed to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application, no screening is created."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening could not be completed; retry later."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out while the job was running."
                        }
                      }
                    },
                    "results": {
                      "type": "array",
                      "description": "One entry per processed profile, in processing order. Grows while the job runs; complete once status is COMPLETED. Recorded for jobs started through the API.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "didit_internal_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Didit internal id of the profile."
                          },
                          "vendor_data": {
                            "type": "string",
                            "nullable": true,
                            "description": "Your own identifier for the profile."
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "enabled",
                              "screened_and_enabled",
                              "already_enabled",
                              "disabled",
                              "skipped_no_identity_data",
                              "skipped_blocked",
                              "skipped_sandbox",
                              "failed_provider",
                              "failed_insufficient_balance"
                            ]
                          }
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true,
                      "description": "Generic failure message when status is FAILED; the detailed cause is kept on the platform side."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "completed_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Profiles matched by the selection."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Profiles that cannot be screened because identity data is missing."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Blocked users that will be skipped (always 0 for businesses)."
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2,
                          "description": "One-time cost of the new screenings."
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07,
                          "description": "Yearly monitoring cost of the profiles that will become monitored."
                        },
                        "balance_sufficient": {
                          "type": "boolean",
                          "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                        }
                      }
                    },
                    "unmatched": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Identifiers of the request that matched no profile in this application, exactly as sent. They are not part of the job."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error: `is_enabled` missing, no selector, or more than 1000 identifiers across both lists."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Insufficient balance to enable monitoring for this selection. The response carries the `estimate` so you can top up the right amount.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (nothing is written).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Profiles matched by the selection."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Profiles already monitored (nothing to do when enabling; these are what disabling turns off)."
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Profiles whose existing AML screening will be switched to monitored (no new screening)."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Profiles without any AML screening that will be screened first (billed as a regular AML screening)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Profiles that cannot be screened because identity data is missing."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Blocked users that will be skipped (always 0 for businesses)."
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2,
                          "description": "One-time cost of the new screenings."
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07,
                          "description": "Yearly monitoring cost of the profiles that will become monitored."
                        },
                        "balance_sufficient": {
                          "type": "boolean",
                          "description": "Whether the organization balance covers the screening plus the first year of monitoring."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/aml-monitoring/jobs/{job_id}/": {
      "get": {
        "summary": "Get AML ongoing monitoring job",
        "description": "Status, outcome counters and per-record results of a monitoring toggle job started from `POST /v3/users/aml-monitoring/` or `POST /v3/businesses/aml-monitoring/`. Poll every couple of seconds while `status` is `PENDING` or `PROCESSING`; `results` is complete once it is `COMPLETED`.",
        "operationId": "get_aml_monitoring_job",
        "tags": [
          "AML Ongoing Monitoring"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The `job_id` returned by the toggle endpoint."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl 'https://verification.didit.me/v3/aml-monitoring/jobs/JOB_ID/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import time\nimport requests\n\nurl = 'https://verification.didit.me/v3/aml-monitoring/jobs/JOB_ID/'\nwhile True:\n    job = requests.get(url, headers={'x-api-key': 'YOUR_API_KEY'}).json()\n    if job['status'] in ('COMPLETED', 'FAILED'):\n        break\n    time.sleep(2)\nprint(job['outcomes'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = 'https://verification.didit.me/v3/aml-monitoring/jobs/JOB_ID/';\nlet job;\ndo {\n  await new Promise((r) => setTimeout(r, 2000));\n  job = await (await fetch(url, { headers: { 'x-api-key': process.env.DIDIT_API_KEY } })).json();\n} while (job.status === 'PENDING' || job.status === 'PROCESSING');\nconsole.log(job.outcomes);"
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean",
                      "description": "true when the job enables monitoring, false when it disables it."
                    },
                    "target_type": {
                      "type": "string",
                      "enum": [
                        "user",
                        "business"
                      ],
                      "description": "Which profile family the job toggles."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Profiles the job processes."
                    },
                    "processed": {
                      "type": "integer",
                      "description": "Profiles processed so far."
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-record outcome counters. Every selected profile resolves to exactly one counter; nothing is silently skipped.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled on it."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active; nothing changed and nothing was billed."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring turned off across every AML screening of the profile."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: the profile lacks the full name, date of birth and country (users) or a name (businesses) needed to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application, no screening is created."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening could not be completed; retry later."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out while the job was running."
                        }
                      }
                    },
                    "results": {
                      "type": "array",
                      "description": "One entry per processed profile, in processing order. Grows while the job runs; complete once status is COMPLETED. Recorded for jobs started through the API; a job started from the Business Console reports counters only.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "didit_internal_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Didit internal id of the profile."
                          },
                          "vendor_data": {
                            "type": "string",
                            "nullable": true,
                            "description": "Your own identifier for the profile."
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "enabled",
                              "screened_and_enabled",
                              "already_enabled",
                              "disabled",
                              "skipped_no_identity_data",
                              "skipped_blocked",
                              "skipped_sandbox",
                              "failed_provider",
                              "failed_insufficient_balance"
                            ]
                          }
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true,
                      "description": "Generic failure message when status is FAILED; the detailed cause is kept on the platform side."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "completed_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "404": {
            "description": "No such job for this application."
          }
        }
      }
    },
    "/v3/users/{vendor_data}/update-status/": {
      "patch": {
        "summary": "Update user status",
        "description": "Flip only the lifecycle `status` of a user — `ACTIVE`/`FLAGGED`/`BLOCKED` (NOT session statuses). `BLOCKED` adds the `vendor_data` to the system blocklist; moving away from `BLOCKED` removes that entry. Each change is recorded as a `STATUS_CHANGED` activity on the user.",
        "operationId": "update_user_status",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "vendor_data",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your unique identifier for the user."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "FLAGGED",
                      "BLOCKED"
                    ],
                    "description": "New lifecycle status. `BLOCKED` also adds the `vendor_data` to the system blocklist."
                  }
                }
              },
              "examples": {
                "Activate": {
                  "summary": "Reactivate the user",
                  "value": {
                    "status": "ACTIVE"
                  }
                },
                "Flag": {
                  "summary": "Flag the user for review",
                  "value": {
                    "status": "FLAGGED"
                  }
                },
                "Block": {
                  "summary": "Block the user (adds to system blocklist)",
                  "value": {
                    "status": "BLOCKED"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/users/user-abc-123/update-status/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"status\": \"BLOCKED\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.patch(\n    'https://verification.didit.me/v3/users/user-abc-123/update-status/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'status': 'BLOCKED'},\n)\nresp.raise_for_status()\nprint(resp.json()['status'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/users/user-abc-123/update-status/', {\n  method: 'PATCH',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ status: 'BLOCKED' }),\n});\nconst user = await resp.json();\nconsole.log(user.status);"
          }
        ],
        "responses": {
          "200": {
            "description": "User status updated. Full user record returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserDetailItem"
                },
                "examples": {
                  "Blocked": {
                    "value": {
                      "didit_internal_id": "f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418",
                      "vendor_data": "user-abc-123",
                      "display_name": null,
                      "full_name": "John Michael Doe",
                      "date_of_birth": "1990-05-15",
                      "effective_name": "John Michael Doe",
                      "status": "BLOCKED",
                      "metadata": {
                        "tier": "premium",
                        "source": "website"
                      },
                      "portrait_image_url": "https://<media-host>/...",
                      "session_count": 3,
                      "approved_count": 2,
                      "declined_count": 0,
                      "in_review_count": 1,
                      "issuing_states": [
                        "USA"
                      ],
                      "approved_emails": [
                        "john@example.com"
                      ],
                      "approved_phones": [
                        "+14155551234"
                      ],
                      "features": {
                        "ID_VERIFICATION": "Approved",
                        "LIVENESS": "Approved",
                        "FACE_MATCH": "Approved",
                        "AML": "Approved"
                      },
                      "features_list": [
                        {
                          "feature": "ID_VERIFICATION",
                          "status": "Approved"
                        },
                        {
                          "feature": "LIVENESS",
                          "status": "Approved"
                        },
                        {
                          "feature": "FACE_MATCH",
                          "status": "Approved"
                        },
                        {
                          "feature": "AML",
                          "status": "Approved"
                        }
                      ],
                      "last_session_at": "2025-06-15T10:30:00Z",
                      "last_activity_at": "2025-06-15T10:30:00Z",
                      "first_session_at": "2025-06-01T08:00:00Z",
                      "tags": [
                        {
                          "uuid": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                          "tag": {
                            "uuid": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
                            "name": "VIP",
                            "color": "#2567FF",
                            "description": null,
                            "source": "custom",
                            "created_at": "2025-05-01T09:00:00Z",
                            "updated_at": "2025-05-01T09:00:00Z"
                          },
                          "added_by_email": "analyst@acme.com",
                          "added_by_name": "Jane Analyst",
                          "created_at": "2025-06-02T11:00:00Z"
                        }
                      ],
                      "comments": [
                        {
                          "uuid": "c1111111-2222-4333-8444-555555555555",
                          "comment_type": "STATUS_CHANGED",
                          "comment": null,
                          "actor_email": null,
                          "actor_name": null,
                          "previous_status": "ACTIVE",
                          "new_status": "BLOCKED",
                          "previous_value": null,
                          "new_value": null,
                          "changed_fields": [],
                          "metadata": null,
                          "mentioned_emails": [],
                          "created_at": "2025-06-15T10:30:00Z"
                        }
                      ],
                      "created_at": "2025-06-01T08:00:00Z",
                      "updated_at": "2025-06-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid `status`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing status": {
                    "value": {
                      "status": [
                        "This field is required."
                      ]
                    }
                  },
                  "Bad status": {
                    "value": {
                      "status": [
                        "Invalid status. Valid options are: ACTIVE, FLAGGED, BLOCKED"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Invalid or revoked API key, or the key cannot update users for this application. Note: on this endpoint an *invalid* key returns `403` (not `401`).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No (non-deleted) user with the supplied `vendor_data` exists for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/businesses/create/": {
      "post": {
        "summary": "Create business",
        "description": "Pre-create a [business](/entities/businesses) *without* a KYB session. All fields are optional, but you should always send `vendor_data` — without it the record cannot be linked to sessions or transactions. When provided, `vendor_data` must be unique among non-deleted businesses (exact match; conflicts return 400). Not idempotent.",
        "operationId": "create_business",
        "tags": [
          "Businesses"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "vendor_data": {
                    "type": "string",
                    "nullable": true,
                    "description": "Your unique identifier for this business (free-form string, NOT a UUID). Optional but strongly recommended. When provided, must be unique among non-deleted businesses for the application; matched exactly as sent."
                  },
                  "display_name": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 255,
                    "description": "Friendly display name shown in the console (takes precedence over `legal_name` for UI display)."
                  },
                  "legal_name": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 255,
                    "description": "Official legal name of the company."
                  },
                  "registration_number": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 100,
                    "description": "Company registration or incorporation number."
                  },
                  "country_code": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 10,
                    "description": "Country of incorporation (ISO 3166-1 alpha-2, e.g. `GB`, `US`)."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "FLAGGED",
                      "BLOCKED"
                    ],
                    "default": "ACTIVE",
                    "description": "Initial lifecycle status. Defaults to `ACTIVE`."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Arbitrary JSON object you attach to the business. Defaults to `{}`."
                  }
                }
              },
              "examples": {
                "Basic": {
                  "summary": "Recommended minimum",
                  "value": {
                    "vendor_data": "company-456",
                    "legal_name": "New Corp Ltd",
                    "country_code": "US"
                  }
                },
                "Full": {
                  "summary": "All fields",
                  "value": {
                    "vendor_data": "company-789",
                    "display_name": "New Corp",
                    "legal_name": "New Corp International Ltd",
                    "registration_number": "98765432",
                    "country_code": "DE",
                    "status": "ACTIVE",
                    "metadata": {
                      "industry": "fintech",
                      "tier": "enterprise"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/businesses/create/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"vendor_data\": \"company-456\", \"legal_name\": \"New Corp Ltd\", \"country_code\": \"US\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/businesses/create/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={\n        'vendor_data': 'company-456',\n        'legal_name': 'New Corp Ltd',\n        'country_code': 'US',\n    },\n)\nresp.raise_for_status()\nbiz = resp.json()\nprint(biz['didit_internal_id'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/businesses/create/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    vendor_data: 'company-456',\n    legal_name: 'New Corp Ltd',\n    country_code: 'US',\n  }),\n});\nconst biz = await resp.json();\nconsole.log(biz.didit_internal_id);"
          }
        ],
        "responses": {
          "201": {
            "description": "Business created. Full business record returned (same shape as Get Business).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessDetailItem"
                },
                "examples": {
                  "Created": {
                    "value": {
                      "didit_internal_id": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
                      "vendor_data": "company-456",
                      "display_name": null,
                      "legal_name": "New Corp Ltd",
                      "registration_number": null,
                      "country_code": "US",
                      "effective_name": "New Corp Ltd",
                      "status": "ACTIVE",
                      "session_count": 0,
                      "approved_count": 0,
                      "declined_count": 0,
                      "in_review_count": 0,
                      "features": {},
                      "features_list": [],
                      "last_session_at": null,
                      "last_activity_at": "2026-03-15T10:30:00Z",
                      "first_session_at": null,
                      "tags": [],
                      "created_at": "2026-03-15T10:30:00Z",
                      "metadata": {},
                      "updated_at": "2026-03-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body — typically a duplicate `vendor_data`, an unknown `status`, or malformed `metadata`.",
            "content": {
              "application/json": {
                "examples": {
                  "Duplicate": {
                    "value": {
                      "vendor_data": [
                        "A business with this vendor_data already exists."
                      ]
                    }
                  },
                  "Bad status": {
                    "value": {
                      "status": [
                        "Invalid status. Valid options are: ACTIVE, FLAGGED, BLOCKED"
                      ]
                    }
                  },
                  "Bad metadata": {
                    "value": {
                      "metadata": [
                        "Metadata must be a JSON object."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing, invalid, or revoked API key, or the key cannot create businesses for this application. This endpoint returns `403` (never `401`) for authentication failures, including requests with no credentials at all.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/users/create/": {
      "post": {
        "summary": "Create user",
        "description": "Pre-create a [user](/entities/users) by `vendor_data` *without* a verification session. `vendor_data` must be unique among non-deleted users for the application (exact match; conflicts return 400). Not idempotent.",
        "operationId": "create_user",
        "tags": [
          "Users"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "vendor_data"
                ],
                "properties": {
                  "vendor_data": {
                    "type": "string",
                    "description": "Your unique identifier for this user (free-form string, NOT a UUID). Must be unique among non-deleted users for the application; matched exactly as sent."
                  },
                  "full_name": {
                    "type": "string",
                    "nullable": true,
                    "maxLength": 512,
                    "description": "Full legal name of the user."
                  },
                  "display_name": {
                    "type": "string",
                    "nullable": true,
                    "description": "Friendly display name shown in the console (takes precedence over `full_name` for UI display).",
                    "maxLength": 255
                  },
                  "date_of_birth": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Date of birth in `YYYY-MM-DD` format."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "FLAGGED",
                      "BLOCKED"
                    ],
                    "default": "ACTIVE",
                    "description": "Initial lifecycle status. Defaults to `ACTIVE`."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Arbitrary JSON object you attach to the user. Defaults to `{}`."
                  },
                  "approved_emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Pre-trusted email addresses for this user, e.g. `[\"john@example.com\"]`."
                  },
                  "approved_phones": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Pre-trusted phone numbers for this user, e.g. `[\"+14155551234\"]`."
                  },
                  "issuing_states": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Pre-recorded issuing countries (ISO 3166-1 alpha-3), e.g. `[\"USA\"]`."
                  }
                }
              },
              "examples": {
                "Basic": {
                  "summary": "Create with basic info",
                  "value": {
                    "vendor_data": "user-abc-123",
                    "full_name": "John Doe"
                  }
                },
                "Full": {
                  "summary": "All fields",
                  "value": {
                    "vendor_data": "user-abc-456",
                    "full_name": "Jane Smith",
                    "display_name": "Jane S.",
                    "date_of_birth": "1990-05-15",
                    "status": "ACTIVE",
                    "metadata": {
                      "tier": "premium",
                      "source": "api"
                    },
                    "approved_emails": [
                      "jane@example.com"
                    ]
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/users/create/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"vendor_data\": \"user-abc-123\", \"full_name\": \"John Doe\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/users/create/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={'vendor_data': 'user-abc-123', 'full_name': 'John Doe'},\n)\nresp.raise_for_status()\nuser = resp.json()\nprint(user['didit_internal_id'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/users/create/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({ vendor_data: 'user-abc-123', full_name: 'John Doe' }),\n});\nconst user = await resp.json();\nconsole.log(user.didit_internal_id);"
          }
        ],
        "responses": {
          "201": {
            "description": "User created. Full user record returned (same shape as Get User).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserDetailItem"
                },
                "examples": {
                  "Created": {
                    "value": {
                      "didit_internal_id": "f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418",
                      "vendor_data": "user-abc-123",
                      "display_name": null,
                      "full_name": "John Doe",
                      "date_of_birth": null,
                      "effective_name": "John Doe",
                      "status": "ACTIVE",
                      "metadata": {},
                      "portrait_image_url": null,
                      "session_count": 0,
                      "approved_count": 0,
                      "declined_count": 0,
                      "in_review_count": 0,
                      "issuing_states": [],
                      "approved_emails": [],
                      "approved_phones": [],
                      "features": {},
                      "features_list": [],
                      "last_session_at": null,
                      "last_activity_at": "2025-06-15T10:30:00Z",
                      "first_session_at": null,
                      "tags": [],
                      "comments": [],
                      "created_at": "2025-06-15T10:30:00Z",
                      "updated_at": "2025-06-15T10:30:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body — typically a duplicate `vendor_data`, a missing required field, or a malformed value.",
            "content": {
              "application/json": {
                "examples": {
                  "Duplicate": {
                    "value": {
                      "vendor_data": [
                        "A user with this vendor_data already exists."
                      ]
                    }
                  },
                  "Missing vendor_data": {
                    "value": {
                      "vendor_data": [
                        "This field is required."
                      ]
                    }
                  },
                  "Bad metadata": {
                    "value": {
                      "metadata": [
                        "Metadata must be a JSON object."
                      ]
                    }
                  },
                  "Bad status": {
                    "value": {
                      "status": [
                        "Invalid status. Valid options are: ACTIVE, FLAGGED, BLOCKED"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No credentials supplied. Requests to `/v3/users/*` paths without an `x-api-key` header (or `Authorization: Bearer` token) are rejected by the authentication middleware before reaching the API.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing credentials": {
                    "value": {
                      "detail": "You must be authenticated with a valid access token to access this endpoint."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Invalid or revoked API key, or the key cannot create users for this application. Note: on this endpoint an *invalid* key returns `403` (not `401`).",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry after the interval indicated in `Retry-After`.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/": {
      "post": {
        "summary": "Upload user face",
        "description": "Attach a trusted imported face image to an existing User profile. Use this after creating or retrieving a User by `vendor_data` and reading its `didit_internal_id`. The uploaded face is stored on the User profile and indexed for duplicate detection and face search. It is not added to a face blocklist.",
        "operationId": "upload_user_face",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID that owns the application."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID that owns the User profile."
          },
          {
            "name": "didit_internal_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Didit's internal User UUID, returned as `didit_internal_id` by `GET /v3/users/{vendor_data}/` and `POST /v3/users/create/`."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "image"
                ],
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "byte",
                    "description": "Raw base64-encoded JPG or PNG face image. Do not include a `data:image/...;base64,` prefix. Max decoded size: 2 MB."
                  },
                  "comment": {
                    "type": "string",
                    "description": "Optional operator-visible note for the uploaded face.",
                    "default": ""
                  }
                }
              },
              "examples": {
                "Imported face": {
                  "summary": "Attach a face imported from a previous provider",
                  "value": {
                    "image": "/9j/4AAQSkZJRgABAQEA...",
                    "comment": "Imported from previous KYC provider"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"image\": \"/9j/4AAQSkZJRgABAQEA...\", \"comment\": \"Imported from previous KYC provider\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/',\n    headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},\n    json={\n        'image': '/9j/4AAQSkZJRgABAQEA...',\n        'comment': 'Imported from previous KYC provider',\n    },\n)\nresp.raise_for_status()\nface = resp.json()\nprint(face['uuid'], face['image_url'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const resp = await fetch('https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/', {\n  method: 'POST',\n  headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    image: '/9j/4AAQSkZJRgABAQEA...',\n    comment: 'Imported from previous KYC provider',\n  }),\n});\nconst face = await resp.json();\nconsole.log(face.uuid, face.image_url);"
          }
        ],
        "responses": {
          "201": {
            "description": "Face uploaded and attached to the User profile.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "uuid",
                    "image_url",
                    "comment",
                    "uploaded_by",
                    "created_at"
                  ],
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "UUID of the uploaded User face record."
                    },
                    "image_url": {
                      "type": "string",
                      "format": "uri",
                      "nullable": true,
                      "description": "Signed URL for the uploaded face image."
                    },
                    "comment": {
                      "type": "string",
                      "nullable": true,
                      "description": "Comment supplied when the face was uploaded."
                    },
                    "uploaded_by": {
                      "type": "string",
                      "nullable": true,
                      "description": "Email or actor identifier of the uploader when available."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Upload timestamp."
                    }
                  }
                },
                "examples": {
                  "Uploaded": {
                    "value": {
                      "uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
                      "image_url": "https://signed-url.example/face.jpg",
                      "comment": "Imported from previous KYC provider",
                      "uploaded_by": "api",
                      "created_at": "2026-05-18T12:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or image. Common causes: invalid base64, invalid image, no detectable face, image over 2 MB, missing embedding, or the User already has 5 uploaded faces.",
            "content": {
              "application/json": {
                "examples": {
                  "No face": {
                    "value": {
                      "image": "No face detected in the image. Please upload a clear photo with a visible face."
                    }
                  },
                  "Too many faces": {
                    "value": {
                      "detail": "Maximum of 5 faces per user reached."
                    }
                  },
                  "Too large": {
                    "value": {
                      "image": "Image exceeds maximum size of 2 MB."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing key": {
                    "value": {
                      "detail": "Authentication credentials were not provided."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The credential is valid but cannot write User profiles for this application.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No User exists for that `didit_internal_id` in the application.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Not found."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; back off and retry.",
            "content": {
              "application/json": {
                "examples": {
                  "Rate limited": {
                    "value": {
                      "detail": "Request was throttled. Expected available in 30 seconds."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/{sessionId}/update-data/": {
      "patch": {
        "summary": "Update KYC data extracted from the ID document on a verification session",
        "description": "Correct the identity fields that were extracted (OCR / NFC) from the user's ID document — misread names, dates, document numbers, and so on — after the verification has finished. Typical callers are a compliance analyst working from your own back office, or an automated reconciliation job. Every field in the body is optional: only the keys you send are written, everything else is left untouched (`PATCH` semantics).\n\nThe session must belong to your application and be in `Approved`, `Declined`, `In Review`, or `Kyc Expired` status. Sessions in any other state (e.g. still `In Progress`) return `404` with `\"No Session matches the given query.\"` — distinct from the `\"Not found.\"` returned for an unknown or deleted `sessionId`. The session must also carry an ID-verification (KYC) record: sessions whose workflow never ran an ID-verification step return `404` (`\"The session does not have a KYC.\"`). For graph workflows with multiple ID-verification steps, target a specific step with `node_id` (query parameter or body field); when omitted, the most recent KYC record is patched.\n\nTwo derived fields are recomputed on every call: `full_name` (from `first_name` + `last_name`) and `issuing_state_name` (from `issuing_state`). If the free-text `address` changes, the server may also re-geocode it and refresh `parsed_address` (skipped for sandbox sessions). `extra_fields` and `parsed_address` are merged key-by-key rather than replaced — see the per-field descriptions for the `null`-to-delete semantics.\n\nSubmitting at least one valid field fires the `data.updated` [webhook](/integration/webhooks) (trigger `manual_review`) — even when the submitted values equal the stored ones. When values actually change, a `KYC_DATA_UPDATED` activity entry recording the changed fields with previous and new values is appended to the session's `reviews`, visible in [Get Decision](#get-/v3/session/-sessionId-/decision/) and the console activity timeline. The session's status and decision are **not** re-evaluated — use [Update Status](#patch-/v3/session/-sessionId-/update-status/) to change the outcome. An empty JSON body (`{}`) is accepted and simply returns the current KYC data without firing the webhook.\n\nAccepts an API key or a console user token; either way the credential needs the `write:sessions` permission. Authentication and permission failures both return `403` — this API never responds `401`. Note that the session lookup runs before credential checks, so an unknown `sessionId` returns `404` even with missing credentials. This endpoint has a dedicated rate limit of 10 requests per minute per API key (invalid requests count too); the shared write budget of 300 requests per minute also applies.",
        "operationId": "patch_v3_session_update_data",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "UUID of the User Verification (KYC) session whose extracted document data you are correcting. Business (KYB) session IDs are not valid here — for company data use [Update KYB Company Data](#patch-/v3/session/-sessionId-/kyb/-companyUuid-/update-data/).",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          },
          {
            "name": "node_id",
            "in": "query",
            "required": false,
            "description": "Workflow graph node whose KYC record to patch, for graph workflows with multiple ID-verification steps (also accepted as a `node_id` body field). When omitted, the most recent KYC record on the session is patched. If no KYC exists for the given node, the call returns `404` (`\"The session does not have a KYC for node '<node_id>'.\"`).",
            "schema": {
              "type": "string",
              "example": "feature_ocr"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "All fields optional — send only what you want to change.",
                "properties": {
                  "document_type": {
                    "type": "string",
                    "description": "Document type code. Accepts the short codes listed in the enum, plus six long-form aliases normalized server-side before validation: `Passport` → `P`, `Identity Card` → `ID`, `Driver's License` → `DL`, `Residence Permit` → `RP`, `Health Insurance Card` → `HIC`, `Tax Card` → `TC`. Any other value (including `PASSPORT` in caps) returns `400`.",
                    "enum": [
                      "P",
                      "DL",
                      "ID",
                      "RP",
                      "SSC",
                      "HIC",
                      "WP",
                      "TC",
                      "VISA",
                      "PSC",
                      "BC",
                      "OTHER"
                    ],
                    "nullable": true,
                    "example": "P"
                  },
                  "document_subtype": {
                    "type": "string",
                    "maxLength": 128,
                    "nullable": true,
                    "description": "Document subtype from the document registry, including the region prefix when the registry distinguishes regional variants."
                  },
                  "document_number": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Document number as printed on the ID.",
                    "example": "PAB123456"
                  },
                  "personal_number": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Personal / national identification number where the document carries one (e.g. Spanish DNI on a passport).",
                    "example": "99999999R"
                  },
                  "date_of_birth": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Date of birth in `YYYY-MM-DD`. Any other format returns `400`.",
                    "example": "1980-01-01"
                  },
                  "date_of_issue": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Issue date of the document in `YYYY-MM-DD`."
                  },
                  "expiration_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Expiration date of the document in `YYYY-MM-DD`."
                  },
                  "issuing_state": {
                    "type": "string",
                    "nullable": true,
                    "description": "Issuing country as an ISO 3166-1 alpha-3 code. Case-insensitive (`esp` is stored as `ESP`); the human-readable `issuing_state_name` shown in [Get Decision](#get-/v3/session/-sessionId-/decision/) is recomputed from this value. Invalid codes return `400`.",
                    "example": "ESP"
                  },
                  "first_name": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Given name(s). The stored `full_name` is recomputed as `first_name + ' ' + last_name` on every call to this endpoint.",
                    "example": "Carmen"
                  },
                  "last_name": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Family name(s). Also feeds the recomputed `full_name`.",
                    "example": "Espanola Espanola"
                  },
                  "gender": {
                    "type": "string",
                    "enum": [
                      "M",
                      "F",
                      "U"
                    ],
                    "nullable": true,
                    "description": "Sex as printed on the document: `M` (male), `F` (female), or `U` (unknown). Any other value — including `X` — returns `400`."
                  },
                  "address": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Free-text address as printed on the document. When this value changes (non-sandbox sessions only) and the structured address is still missing or incomplete, the server re-geocodes it synchronously before responding — the 200 body already reflects the refreshed `parsed_address`. The re-geocode also requires `issuing_state` to be present on the KYC record."
                  },
                  "place_of_birth": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Place of birth as printed on the document."
                  },
                  "nationality": {
                    "type": "string",
                    "maxLength": 32,
                    "nullable": true,
                    "description": "Nationality as printed on the document. Free text up to 32 characters — typically an ISO 3166-1 alpha-3 code (e.g. `ESP`), but not validated as one."
                  },
                  "marital_status": {
                    "type": "string",
                    "enum": [
                      "SINGLE",
                      "MARRIED",
                      "DIVORCED",
                      "WIDOWED",
                      "UNKNOWN"
                    ],
                    "description": "Marital status where the document carries it. Any other value returns `400`."
                  },
                  "extra_fields": {
                    "type": "object",
                    "additionalProperties": true,
                    "nullable": true,
                    "description": "Per-key overrides for document-specific extra fields (e.g. `blood_group`, `dl_categories`, `mrz_string`). Keys are merged into the existing override map: send a key with a value to set it, or with `null` / `\"\"` to remove that key from the merged view. Send the whole field as `null` to clear all previously applied overrides. Must be a JSON object, otherwise `400`. The response always returns the merged view (OCR-extracted values with your overrides applied)."
                  },
                  "parsed_address": {
                    "type": "object",
                    "nullable": true,
                    "description": "Structured address. Only these nested keys are accepted: `address_type`, `city`, `region`, `street_1`, `street_2`, `postal_code`, `country` — any other key returns `400`. Per-key semantics: a value sets the key, `null` removes it. `formatted_address` is recomputed server-side by joining `street_1`, `street_2`, `city`, `region`, `postal_code`, and `country` and is returned in the response — you cannot set it directly.",
                    "properties": {
                      "address_type": {
                        "type": "string",
                        "nullable": true,
                        "description": "Free-form address classification (e.g. `home`)."
                      },
                      "city": {
                        "type": "string",
                        "nullable": true,
                        "example": "Madrid"
                      },
                      "region": {
                        "type": "string",
                        "nullable": true,
                        "description": "State / province / autonomous community."
                      },
                      "street_1": {
                        "type": "string",
                        "nullable": true,
                        "example": "Avda de Madrid 34"
                      },
                      "street_2": {
                        "type": "string",
                        "nullable": true
                      },
                      "postal_code": {
                        "type": "string",
                        "nullable": true,
                        "example": "28013"
                      },
                      "country": {
                        "type": "string",
                        "nullable": true,
                        "description": "ISO 3166-1 alpha-2 country code. Lowercase input is normalized to uppercase; alpha-3 codes are rejected with `400`.",
                        "example": "ES"
                      }
                    }
                  }
                }
              },
              "examples": {
                "Correct name and DOB": {
                  "summary": "Fix OCR-misread name, date of birth, and structured address",
                  "value": {
                    "first_name": "Carmen",
                    "last_name": "Espanola Espanola",
                    "date_of_birth": "1980-01-01",
                    "issuing_state": "ESP",
                    "marital_status": "MARRIED",
                    "extra_fields": {
                      "blood_group": "O+"
                    },
                    "parsed_address": {
                      "street_1": "Avda de Madrid 34",
                      "city": "Madrid",
                      "postal_code": "28013",
                      "country": "ES"
                    }
                  }
                },
                "Remove an extra field": {
                  "summary": "Delete one extra-field key, keep the rest",
                  "value": {
                    "extra_fields": {
                      "blood_group": null
                    }
                  }
                },
                "Long-form document type": {
                  "summary": "Long-form alias is normalized to the short code (here P)",
                  "value": {
                    "document_type": "Passport"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "KYC data updated. Returns the **full current KYC record** (every updatable field with its stored value, plus the merged `extra_fields` and the current `parsed_address`) — not just the fields you submitted. The `data.updated` webhook fires when at least one valid field was in the payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "document_type": {
                      "type": "string",
                      "description": "Document type code. Accepts the short codes listed in the enum, plus six long-form aliases normalized server-side before validation: `Passport` → `P`, `Identity Card` → `ID`, `Driver's License` → `DL`, `Residence Permit` → `RP`, `Health Insurance Card` → `HIC`, `Tax Card` → `TC`. Any other value (including `PASSPORT` in caps) returns `400`.",
                      "enum": [
                        "P",
                        "DL",
                        "ID",
                        "RP",
                        "SSC",
                        "HIC",
                        "WP",
                        "TC",
                        "VISA",
                        "PSC",
                        "BC",
                        "OTHER"
                      ],
                      "nullable": true,
                      "example": "P"
                    },
                    "document_subtype": {
                      "type": "string",
                      "maxLength": 128,
                      "nullable": true,
                      "description": "Document subtype from the document registry, including the region prefix when the registry distinguishes regional variants."
                    },
                    "document_number": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Document number as printed on the ID.",
                      "example": "PAB123456"
                    },
                    "personal_number": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Personal / national identification number where the document carries one (e.g. Spanish DNI on a passport).",
                      "example": "99999999R"
                    },
                    "date_of_birth": {
                      "type": "string",
                      "format": "date",
                      "nullable": true,
                      "description": "Date of birth in `YYYY-MM-DD`. Any other format returns `400`.",
                      "example": "1980-01-01"
                    },
                    "date_of_issue": {
                      "type": "string",
                      "format": "date",
                      "nullable": true,
                      "description": "Issue date of the document in `YYYY-MM-DD`."
                    },
                    "expiration_date": {
                      "type": "string",
                      "format": "date",
                      "nullable": true,
                      "description": "Expiration date of the document in `YYYY-MM-DD`."
                    },
                    "issuing_state": {
                      "type": "string",
                      "nullable": true,
                      "description": "Issuing country as an ISO 3166-1 alpha-3 code. Case-insensitive (`esp` is stored as `ESP`); the human-readable `issuing_state_name` shown in [Get Decision](#get-/v3/session/-sessionId-/decision/) is recomputed from this value. Invalid codes return `400`.",
                      "example": "ESP"
                    },
                    "first_name": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Given name(s). The stored `full_name` is recomputed as `first_name + ' ' + last_name` on every call to this endpoint.",
                      "example": "Carmen"
                    },
                    "last_name": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Family name(s). Also feeds the recomputed `full_name`.",
                      "example": "Espanola Espanola"
                    },
                    "gender": {
                      "type": "string",
                      "enum": [
                        "M",
                        "F",
                        "U"
                      ],
                      "nullable": true,
                      "description": "Sex as printed on the document: `M` (male), `F` (female), or `U` (unknown). Any other value — including `X` — returns `400`."
                    },
                    "address": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Free-text address as printed on the document. When this value changes (non-sandbox sessions only) and the structured address is still missing or incomplete, the server re-geocodes it in the background of the same request and may overwrite `parsed_address` with the geocoder result."
                    },
                    "place_of_birth": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Place of birth as printed on the document."
                    },
                    "nationality": {
                      "type": "string",
                      "maxLength": 32,
                      "nullable": true,
                      "description": "Nationality as printed on the document. Free text up to 32 characters — typically an ISO 3166-1 alpha-3 code (e.g. `ESP`), but not validated as one."
                    },
                    "marital_status": {
                      "type": "string",
                      "enum": [
                        "SINGLE",
                        "MARRIED",
                        "DIVORCED",
                        "WIDOWED",
                        "UNKNOWN"
                      ],
                      "description": "Marital status where the document carries it. Any other value returns `400`."
                    },
                    "extra_fields": {
                      "type": "object",
                      "additionalProperties": true,
                      "nullable": true,
                      "description": "Merged view of the document's extra fields: the OCR-extracted values with all operator overrides applied. Keys removed via a `null` override are absent from this map."
                    },
                    "parsed_address": {
                      "type": "object",
                      "nullable": true,
                      "description": "Current structured address (with internal bookkeeping keys stripped), or `null` when none exists. Includes the recomputed `formatted_address` alongside the seven editable keys.",
                      "properties": {
                        "address_type": {
                          "type": "string",
                          "nullable": true,
                          "description": "Free-form address classification (e.g. `home`)."
                        },
                        "city": {
                          "type": "string",
                          "nullable": true,
                          "example": "Madrid"
                        },
                        "region": {
                          "type": "string",
                          "nullable": true,
                          "description": "State / province / autonomous community."
                        },
                        "street_1": {
                          "type": "string",
                          "nullable": true,
                          "example": "Avda de Madrid 34"
                        },
                        "street_2": {
                          "type": "string",
                          "nullable": true
                        },
                        "postal_code": {
                          "type": "string",
                          "nullable": true,
                          "example": "28013"
                        },
                        "country": {
                          "type": "string",
                          "nullable": true,
                          "description": "ISO 3166-1 alpha-2 country code. Lowercase input is normalized to uppercase; alpha-3 codes are rejected with `400`.",
                          "example": "ES"
                        },
                        "formatted_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Joined, human-readable form of the structured address. Recomputed server-side after every `parsed_address` edit.",
                          "example": "Avda de Madrid 34, Madrid, 28013, ES"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Updated KYC": {
                    "summary": "Full KYC record after the correction",
                    "value": {
                      "document_type": "P",
                      "document_subtype": null,
                      "document_number": "PAB123456",
                      "personal_number": "99999999R",
                      "date_of_birth": "1980-01-01",
                      "date_of_issue": "2021-02-09",
                      "expiration_date": "2031-02-08",
                      "issuing_state": "ESP",
                      "first_name": "Carmen",
                      "last_name": "Espanola Espanola",
                      "gender": "F",
                      "address": "AVDA DE MADRID 34, MADRID, MADRID 28013",
                      "place_of_birth": "MADRID",
                      "nationality": "ESP",
                      "marital_status": "MARRIED",
                      "extra_fields": {
                        "mrz_string": "P<ESPESPANOLA<<CARMEN<<<<<",
                        "blood_group": "O+"
                      },
                      "parsed_address": {
                        "city": "Madrid",
                        "street_1": "Avda de Madrid 34",
                        "postal_code": "28013",
                        "country": "ES",
                        "formatted_address": "Avda de Madrid 34, Madrid, 28013, ES"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field errors arrive as `{\"<field>\": [\"<message>\"]}`; errors on nested `parsed_address` / `extra_fields` keys use an object value: `{\"parsed_address\": {\"<key>\": \"<message>\"}}`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid gender": {
                    "summary": "gender must be M, F, or U",
                    "value": {
                      "gender": [
                        "\"X\" is not a valid choice."
                      ]
                    }
                  },
                  "Invalid document type": {
                    "summary": "Not a short code or long-form alias",
                    "value": {
                      "document_type": [
                        "\"PASSPORT\" is not a valid choice."
                      ]
                    }
                  },
                  "Invalid issuing state": {
                    "summary": "issuing_state is not ISO 3166-1 alpha-3",
                    "value": {
                      "issuing_state": [
                        "Invalid ISO 3166-1 alpha-3 country code for issuing_state."
                      ]
                    }
                  },
                  "Invalid marital status": {
                    "summary": "marital_status not in the enum",
                    "value": {
                      "marital_status": [
                        "\"ENGAGED\" is not a valid choice."
                      ]
                    }
                  },
                  "Bad date format": {
                    "summary": "Dates must be YYYY-MM-DD",
                    "value": {
                      "date_of_birth": [
                        "Date has wrong format. Use one of these formats instead: YYYY-MM-DD."
                      ]
                    }
                  },
                  "Unsupported parsed_address key": {
                    "summary": "Only the seven documented keys are allowed",
                    "value": {
                      "parsed_address": {
                        "zipcode": "Unsupported key. Allowed keys: address_type, city, region, street_1, street_2, postal_code, country"
                      }
                    }
                  },
                  "Invalid parsed_address country": {
                    "summary": "Nested country must be alpha-2, not alpha-3",
                    "value": {
                      "parsed_address": {
                        "country": "Invalid ISO 3166-1 alpha-2 country code."
                      }
                    }
                  },
                  "extra_fields not an object": {
                    "summary": "extra_fields must be a JSON object",
                    "value": {
                      "extra_fields": [
                        "This field must be a JSON object."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "Credential lacks write:sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown session, session in a non-editable state, or no KYC record to patch. Each case has a distinct `detail` message (see examples). The unknown-session lookup runs before credential checks.",
            "content": {
              "application/json": {
                "examples": {
                  "Unknown session": {
                    "summary": "No session with this ID in your application (or it was deleted)",
                    "value": {
                      "detail": "Not found."
                    }
                  },
                  "Wrong session state": {
                    "summary": "Session exists but is not Approved / Declined / In Review / Kyc Expired",
                    "value": {
                      "detail": "No Session matches the given query."
                    }
                  },
                  "No KYC record": {
                    "summary": "The workflow never ran an ID-verification step",
                    "value": {
                      "detail": "The session does not have a KYC."
                    }
                  },
                  "No KYC for node": {
                    "summary": "node_id given but no KYC exists for it",
                    "value": {
                      "detail": "The session does not have a KYC for node 'feature_missing'."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Dedicated rate limit exceeded — 10 KYC data updates per minute per API key (rejected requests count toward the budget). The shared 300/min write budget can also trigger with its own message. Inspect `Retry-After` and the `X-RateLimit-*` response headers before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Rate limited": {
                    "summary": "KYC update budget exhausted",
                    "value": {
                      "detail": "Session KYC data update rate limit exceeded. You can make up to 10 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-data/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"first_name\": \"Carmen\",\n    \"last_name\": \"Espanola Espanola\",\n    \"date_of_birth\": \"1980-01-01\",\n    \"issuing_state\": \"ESP\",\n    \"parsed_address\": {\n      \"street_1\": \"Avda de Madrid 34\",\n      \"city\": \"Madrid\",\n      \"postal_code\": \"28013\",\n      \"country\": \"ES\"\n    }\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-data/\",\n    headers={\n        \"x-api-key\": \"YOUR_API_KEY\",\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"first_name\": \"Carmen\",\n        \"last_name\": \"Espanola Espanola\",\n        \"date_of_birth\": \"1980-01-01\",\n        \"issuing_state\": \"ESP\",\n        \"extra_fields\": {\"blood_group\": \"O+\"},\n        \"parsed_address\": {\"city\": \"Madrid\", \"postal_code\": \"28013\", \"country\": \"ES\"},\n    },\n)\nresponse.raise_for_status()\nkyc = response.json()  # full current KYC record\nprint(kyc[\"first_name\"], kyc[\"parsed_address\"][\"formatted_address\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-data/',\n  {\n    method: 'PATCH',\n    headers: {\n      'x-api-key': process.env.DIDIT_API_KEY,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      first_name: 'Carmen',\n      last_name: 'Espanola Espanola',\n      date_of_birth: '1980-01-01',\n      issuing_state: 'ESP',\n      parsed_address: { city: 'Madrid', postal_code: '28013', country: 'ES' },\n    }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst kyc = await response.json(); // full current KYC record"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/features/{nodeId}/update-status/": {
      "patch": {
        "summary": "Update an individual feature (step) status",
        "description": "Set the status of a single verification feature (step) within a session **without changing the overall session decision**. Target the feature by its workflow graph `nodeId` (use `default` for non-graph workflows where the step has no node).\n\nWorks for both User Verification (KYC) and Business Verification (KYB) sessions and every step type — ID/OCR, Liveness, Face Match, NFC, AML, Proof of Address, Phone, Email, Database Validation, Questionnaire, and the KYB registry / documents / key-people checks.\n\n`new_status` must be one of `Approved`, `Declined`, or `In Review`, and must differ from the feature's current status. A successful call fires a `data.updated` webhook and appends an activity entry (with actor attribution) to the session's review trail. This endpoint is **not** available for standalone API sessions (`session_type = API`).\n\nAuthenticate with your API key (`x-api-key`) or a user authorization header — either must carry the `write:sessions` privilege.",
        "operationId": "patch_v3_session_update_feature_status",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the verification session. Accepts both user (KYC) and business (KYB) session IDs — the service resolves the ID across both session types.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          },
          {
            "in": "path",
            "name": "nodeId",
            "required": true,
            "description": "Workflow graph node ID of the feature to update (for example `feature_ocr_1`). Use the literal value `default` for non-graph (single-step) workflows where the feature has no node ID.",
            "schema": {
              "type": "string",
              "example": "feature_ocr_1"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "new_status"
                ],
                "properties": {
                  "new_status": {
                    "type": "string",
                    "description": "Target status for this feature. Must differ from the current value.",
                    "enum": [
                      "Approved",
                      "Declined",
                      "In Review"
                    ],
                    "example": "Approved"
                  },
                  "comment": {
                    "type": "string",
                    "description": "Optional free-text note recorded on the session's review trail for this feature change.",
                    "example": "Document manually verified by compliance."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feature status updated. Returns the targeted feature, its node ID, and the new status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "node_id": {
                      "type": "string",
                      "example": "feature_ocr_1"
                    },
                    "feature_type": {
                      "type": "string",
                      "description": "Model name of the updated feature (e.g. `KYC`, `Face`, `FaceMatch`, `AML`, `POA`).",
                      "example": "KYC"
                    },
                    "new_status": {
                      "type": "string",
                      "example": "Approved"
                    }
                  }
                },
                "example": {
                  "session_id": "11111111-2222-3333-4444-555555555555",
                  "node_id": "feature_ocr_1",
                  "feature_type": "KYC",
                  "new_status": "Approved"
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Returned when `new_status` is invalid or unchanged, or when the session is a standalone API session.",
            "content": {
              "application/json": {
                "examples": {
                  "Same Status": {
                    "summary": "new_status equals the current status",
                    "value": {
                      "new_status": "The new status is the same as the current status."
                    }
                  },
                  "API Session": {
                    "summary": "Feature status cannot be changed on standalone API sessions",
                    "value": {
                      "detail": "Cannot change feature status for API sessions."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "API key lacks write:sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "The session was not found, or it has no feature with the given `nodeId`.",
            "content": {
              "application/json": {
                "examples": {
                  "Session Not Found": {
                    "summary": "Unknown session_id",
                    "value": {
                      "detail": "Session not found."
                    }
                  },
                  "Feature Not Found": {
                    "summary": "No feature for this node_id",
                    "value": {
                      "detail": "No feature found with node_id 'feature_ocr_1' in this session."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/features/feature_ocr_1/update-status/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"new_status\": \"Approved\",\n    \"comment\": \"Document manually verified by compliance.\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/features/feature_ocr_1/update-status/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\", \"Content-Type\": \"application/json\"},\n    json={\"new_status\": \"Approved\", \"comment\": \"Document manually verified by compliance.\"},\n)\nprint(response.json())"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/update-aml-hit-status/": {
      "patch": {
        "summary": "Update an AML hit review status",
        "description": "Set the review status of a **single AML hit** (a potential sanction / PEP / watchlist / adverse-media match) returned by AML screening, without changing the overall session decision. Identify the hit by its `hit_id` (the `id` of an entry in the AML check's `hits` array — see the session decision).\n\n`review_status` is one of `Unreviewed`, `Confirmed Match`, `False Positive`, or `Inconclusive`. Reviewer decisions are preserved across ongoing-monitoring updates, so a hit you mark `False Positive` stays that way when the provider re-screens.\n\nA successful call fires a `data.updated` webhook and appends an activity entry (with actor attribution) to the session's review trail. For graph workflows with multiple AML checks, pass `node_id` to target a specific check.\n\nAuthenticate with your API key (`x-api-key`) or a user authorization header — either must carry the `write:sessions` privilege.",
        "operationId": "patch_v3_session_update_aml_hit_status",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the verification session. Accepts both user (KYC) and business (KYB) session IDs — the service resolves the ID across both session types.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          },
          {
            "in": "query",
            "name": "node_id",
            "required": false,
            "description": "Workflow graph node ID. Required only when the session has multiple AML checks (one per node); omit it for single-AML sessions.",
            "schema": {
              "type": "string",
              "example": "feature_aml_1"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "hit_id",
                  "review_status"
                ],
                "properties": {
                  "hit_id": {
                    "type": "string",
                    "description": "The `id` of the hit in the AML check's `hits` array.",
                    "example": "abc123"
                  },
                  "review_status": {
                    "type": "string",
                    "description": "The new review status for the hit.",
                    "enum": [
                      "Unreviewed",
                      "Confirmed Match",
                      "False Positive",
                      "Inconclusive"
                    ],
                    "example": "False Positive"
                  },
                  "node_id": {
                    "type": "string",
                    "description": "Optional graph node ID. Use it (here or as a query parameter) when the session has multiple AML checks.",
                    "example": "feature_aml_1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hit review status updated.",
            "content": {
              "application/json": {
                "example": {
                  "message": "Hit status updated successfully",
                  "hit_id": "abc123",
                  "review_status": "False Positive"
                }
              }
            }
          },
          "400": {
            "description": "Validation error — `hit_id` empty or `review_status` not one of the allowed values.",
            "content": {
              "application/json": {
                "example": {
                  "review_status": [
                    "\"Maybe\" is not a valid choice."
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "API key lacks write:sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "The session was not found, the session has no AML check (optionally for the given `node_id`), or no hit matches `hit_id`.",
            "content": {
              "application/json": {
                "examples": {
                  "No AML Check": {
                    "summary": "Session has no AML check",
                    "value": {
                      "detail": "The session does not have an AML check."
                    }
                  },
                  "Hit Not Found": {
                    "summary": "Unknown hit_id",
                    "value": {
                      "detail": "Hit with ID 'abc123' not found in the AML check."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-aml-hit-status/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"hit_id\": \"abc123\",\n    \"review_status\": \"False Positive\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-aml-hit-status/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\", \"Content-Type\": \"application/json\"},\n    json={\"hit_id\": \"abc123\", \"review_status\": \"False Positive\"},\n)\nprint(response.json())"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/bulk-update-aml-hit-status/": {
      "patch": {
        "summary": "Bulk update AML hit review statuses",
        "description": "Update the review status of **multiple AML hits** in one call. Provide `hit_updates`, a list of `{ hit_id, review_status }` pairs. `review_status` is one of `Unreviewed`, `Confirmed Match`, `False Positive`, or `Inconclusive`.\n\nThe update is all-or-nothing: if any `hit_id` is not found in the AML check, the request returns `404` and no hit is changed. A successful call fires a single `data.updated` webhook and records one activity entry covering all changes. For graph workflows with multiple AML checks, pass `node_id` to target a specific check.\n\nAuthenticate with your API key (`x-api-key`) or a user authorization header — either must carry the `write:sessions` privilege.",
        "operationId": "patch_v3_session_bulk_update_aml_hit_status",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the verification session. Accepts both user (KYC) and business (KYB) session IDs — the service resolves the ID across both session types.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          },
          {
            "in": "query",
            "name": "node_id",
            "required": false,
            "description": "Workflow graph node ID. Required only when the session has multiple AML checks (one per node); omit it for single-AML sessions.",
            "schema": {
              "type": "string",
              "example": "feature_aml_1"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "hit_updates"
                ],
                "properties": {
                  "hit_updates": {
                    "type": "array",
                    "description": "Non-empty list of hit updates.",
                    "items": {
                      "type": "object",
                      "required": [
                        "hit_id",
                        "review_status"
                      ],
                      "properties": {
                        "hit_id": {
                          "type": "string",
                          "example": "abc123"
                        },
                        "review_status": {
                          "type": "string",
                          "enum": [
                            "Unreviewed",
                            "Confirmed Match",
                            "False Positive",
                            "Inconclusive"
                          ],
                          "example": "Confirmed Match"
                        }
                      }
                    }
                  },
                  "node_id": {
                    "type": "string",
                    "description": "Optional graph node ID. Use it (here or as a query parameter) when the session has multiple AML checks.",
                    "example": "feature_aml_1"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "All hits updated.",
            "content": {
              "application/json": {
                "example": {
                  "message": "Updated 2 hit(s) successfully",
                  "updated_hits": [
                    "abc123",
                    "def456"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validation error — `hit_updates` empty, or an entry is missing `hit_id` / `review_status` or carries an invalid value.",
            "content": {
              "application/json": {
                "example": {
                  "hit_updates": [
                    "hit_updates cannot be empty"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "API key lacks write:sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "The session was not found, the session has no AML check, or one or more `hit_id`s do not exist (no hit is changed in that case).",
            "content": {
              "application/json": {
                "example": {
                  "detail": "Hits not found: zzz999"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/bulk-update-aml-hit-status/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"hit_updates\": [\n      { \"hit_id\": \"abc123\", \"review_status\": \"Confirmed Match\" },\n      { \"hit_id\": \"def456\", \"review_status\": \"False Positive\" }\n    ]\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/bulk-update-aml-hit-status/\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\", \"Content-Type\": \"application/json\"},\n    json={\n        \"hit_updates\": [\n            {\"hit_id\": \"abc123\", \"review_status\": \"Confirmed Match\"},\n            {\"hit_id\": \"def456\", \"review_status\": \"False Positive\"},\n        ]\n    },\n)\nprint(response.json())"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/update-poa-data/": {
      "patch": {
        "summary": "Update Proof of Address data extracted from the POA document on a verification session",
        "description": "Correct the fields extracted from the user's Proof of Address document — utility bill, bank statement, or other address evidence — after the verification has finished: issuer, dates, the printed name, the address itself, and banking details. Every field in the body is optional: only the keys you send are written, everything else is left untouched (`PATCH` semantics).\n\nThe session must belong to your application and be in `Approved`, `Declined`, `In Review`, or `Kyc Expired` status. Sessions in any other state (e.g. still `In Progress`) return `404` with `\"No Session matches the given query.\"` — distinct from the `\"Not found.\"` returned for an unknown or deleted `sessionId`. The session must also carry a POA record: sessions whose workflow never ran a Proof of Address step return `404` (`\"The session does not have a POA.\"`). For graph workflows with multiple POA steps, target a specific step with `node_id` (query parameter or body field); when omitted, the most recent POA record is patched.\n\n`extra_fields` is merged key-by-key: nine known keys (`bank_iban`, `additional_names`, …) write through to dedicated POA columns, any other key is kept as a custom extra, and `null` / `\"\"` deletes a key. `poa_parsed_address` accepts only the seven documented keys and recomputes `formatted_address` / `poa_formatted_address` after every edit. If the free-text `poa_address` changes, the server may also re-geocode it and refresh the structured address (skipped for sandbox sessions).\n\nUnlike the KYC variant of this endpoint, the `data.updated` [webhook](/integration/webhooks) (trigger `manual_review`) fires only when at least one stored value **actually changed** — re-sending identical values is a silent no-op. When values change, a `POA_DATA_UPDATED` activity entry recording the changed fields with previous and new values is appended to the session's `reviews`, visible in [Get Decision](#get-/v3/session/-sessionId-/decision/) and the console activity timeline. The session's status and decision are **not** re-evaluated — use [Update Status](#patch-/v3/session/-sessionId-/update-status/) to change the outcome.\n\nAccepts an API key or a console user token; either way the credential needs the `write:sessions` permission. Authentication and permission failures both return `403` — this API never responds `401`. Note that the session lookup runs before credential checks, so an unknown `sessionId` returns `404` even with missing credentials. This endpoint has a dedicated rate limit of 10 requests per minute per API key (invalid requests count too); the shared write budget of 300 requests per minute also applies.\n\nAn empty JSON body `{}` is a no-op: it returns `200` echoing the current POA record without firing the webhook (`has_changes` stays false).",
        "operationId": "patch_v3_session_update_poa_data",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "UUID of the User Verification (KYC) session whose attached POA record you are correcting.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          },
          {
            "name": "node_id",
            "in": "query",
            "required": false,
            "description": "Workflow graph node whose POA record to patch, for graph workflows with multiple Proof of Address steps (also accepted as a `node_id` body field). When omitted, the most recent POA record on the session is patched. If no POA exists for the given node, the call returns `404` (`\"The session does not have a POA for node '<node_id>'.\"`).",
            "schema": {
              "type": "string",
              "example": "feature_poa"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "All fields optional — send only what you want to change.",
                "properties": {
                  "issuing_state": {
                    "type": "string",
                    "nullable": true,
                    "description": "Country that issued the POA document, ISO 3166-1 alpha-3. Case-insensitive (normalized to uppercase); invalid codes return `400`.",
                    "example": "ESP"
                  },
                  "document_type": {
                    "type": "string",
                    "enum": [
                      "UTILITY_BILL",
                      "BANK_STATEMENT",
                      "GOVERNMENT_ISSUED_DOCUMENT",
                      "OTHER_POA_DOCUMENT",
                      "UNKNOWN"
                    ],
                    "description": "POA document category. Values are uppercase — lowercase variants like `utility_bill` return `400`.",
                    "example": "UTILITY_BILL"
                  },
                  "document_language": {
                    "type": "string",
                    "maxLength": 50,
                    "nullable": true,
                    "description": "Language of the document, typically an ISO 639-1 code (e.g. `es`). Free text — not validated as a language code.",
                    "example": "es"
                  },
                  "issuer": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Organization that issued the document (utility company, bank, government agency).",
                    "example": "Energy Provider S.A."
                  },
                  "issue_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Issue date of the POA document in `YYYY-MM-DD`. Any other format returns `400`.",
                    "example": "2026-04-12"
                  },
                  "poa_address": {
                    "type": "string",
                    "nullable": true,
                    "description": "Free-text address as printed on the document. When this value changes (non-sandbox sessions only) and the structured address is still missing or incomplete, the server re-geocodes it in the background of the same request and may overwrite `poa_parsed_address` / `poa_formatted_address` with the geocoder result. The re-geocode also requires `issuing_state` to be present on the POA record.",
                    "example": "Avda de Madrid 34, 28013 Madrid"
                  },
                  "name_on_document": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Recipient name as printed on the document.",
                    "example": "Carmen Espanola"
                  },
                  "extra_fields": {
                    "type": "object",
                    "additionalProperties": true,
                    "nullable": true,
                    "description": "Document-specific extras, merged key-by-key. Nine keys map to dedicated POA columns: `bank_account_number`, `bank_iban`, `bank_sort_code`, `bank_routing_number`, `bank_swift_bic`, `bank_branch_name`, `bank_branch_address`, `document_phone_number`, and `additional_names` (must be a list of strings or `null`, otherwise `400`). Any other key is stored as a custom extra field. Per-key semantics: a value sets the key; `null` or `\"\"` deletes it. Must be a JSON object, otherwise `400`."
                  },
                  "poa_parsed_address": {
                    "type": "object",
                    "nullable": true,
                    "description": "Structured address. Only these nested keys are accepted: `address_type`, `city`, `region`, `street_1`, `street_2`, `postal_code`, `country` — any other key returns `400`. Per-key semantics: a value sets the key, `null` removes it. `formatted_address` (and the top-level `poa_formatted_address`) is recomputed server-side by joining `street_1`, `street_2`, `city`, `region`, `postal_code`, and `country` — you cannot set it directly.",
                    "properties": {
                      "address_type": {
                        "type": "string",
                        "nullable": true,
                        "description": "Free-form address classification (e.g. `home`)."
                      },
                      "city": {
                        "type": "string",
                        "nullable": true,
                        "example": "Madrid"
                      },
                      "region": {
                        "type": "string",
                        "nullable": true,
                        "description": "State / province / autonomous community."
                      },
                      "street_1": {
                        "type": "string",
                        "nullable": true,
                        "example": "Avda de Madrid 34"
                      },
                      "street_2": {
                        "type": "string",
                        "nullable": true
                      },
                      "postal_code": {
                        "type": "string",
                        "nullable": true,
                        "example": "28013"
                      },
                      "country": {
                        "type": "string",
                        "nullable": true,
                        "description": "ISO 3166-1 alpha-2 country code. Lowercase input is normalized to uppercase; alpha-3 codes are rejected with `400`.",
                        "example": "ES"
                      }
                    }
                  }
                }
              },
              "examples": {
                "Correct issuer and address": {
                  "summary": "Fix document classification, issuer, and the structured address",
                  "value": {
                    "issuing_state": "ESP",
                    "document_type": "BANK_STATEMENT",
                    "issuer": "Banco Example S.A.",
                    "issue_date": "2026-05-02",
                    "name_on_document": "Carmen Espanola",
                    "poa_address": "Avda de Madrid 34, 28013 Madrid",
                    "extra_fields": {
                      "bank_iban": "ES9121000418450200051332",
                      "additional_names": [
                        "Carmen E. Espanola"
                      ]
                    },
                    "poa_parsed_address": {
                      "street_1": "Avda de Madrid 34",
                      "city": "Madrid",
                      "postal_code": "28013",
                      "country": "ES"
                    }
                  }
                },
                "Remove a banking detail": {
                  "summary": "Delete one extra-field key, keep the rest",
                  "value": {
                    "extra_fields": {
                      "bank_iban": null
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "POA data updated. Returns the **full current POA record** (every updatable field with its stored value, plus the complete `extra_fields` map, `poa_parsed_address`, and `poa_formatted_address`) — not just the fields you submitted. The `data.updated` webhook fires only when at least one value actually changed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "issuing_state": {
                      "type": "string",
                      "nullable": true,
                      "description": "Country that issued the POA document, ISO 3166-1 alpha-3. Case-insensitive (normalized to uppercase); invalid codes return `400`.",
                      "example": "ESP"
                    },
                    "document_type": {
                      "type": "string",
                      "enum": [
                        "UTILITY_BILL",
                        "BANK_STATEMENT",
                        "GOVERNMENT_ISSUED_DOCUMENT",
                        "OTHER_POA_DOCUMENT",
                        "UNKNOWN"
                      ],
                      "description": "POA document category. Values are uppercase — lowercase variants like `utility_bill` return `400`.",
                      "example": "UTILITY_BILL"
                    },
                    "document_language": {
                      "type": "string",
                      "maxLength": 50,
                      "nullable": true,
                      "description": "Language of the document, typically an ISO 639-1 code (e.g. `es`). Free text — not validated as a language code.",
                      "example": "es"
                    },
                    "issuer": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Organization that issued the document (utility company, bank, government agency).",
                      "example": "Energy Provider S.A."
                    },
                    "issue_date": {
                      "type": "string",
                      "format": "date",
                      "nullable": true,
                      "description": "Issue date of the POA document in `YYYY-MM-DD`. Any other format returns `400`.",
                      "example": "2026-04-12"
                    },
                    "poa_address": {
                      "type": "string",
                      "nullable": true,
                      "description": "Free-text address as printed on the document. When this value changes (non-sandbox sessions only) and the structured address is still missing or incomplete, the server re-geocodes it in the background of the same request and may overwrite `poa_parsed_address` / `poa_formatted_address` with the geocoder result.",
                      "example": "Avda de Madrid 34, 28013 Madrid"
                    },
                    "name_on_document": {
                      "type": "string",
                      "maxLength": 255,
                      "nullable": true,
                      "description": "Recipient name as printed on the document.",
                      "example": "Carmen Espanola"
                    },
                    "extra_fields": {
                      "type": "object",
                      "additionalProperties": true,
                      "nullable": true,
                      "description": "Always present in the response: the nine known keys (with `null` for unset ones, `additional_names` defaulting to `[]`) plus any custom keys previously stored."
                    },
                    "poa_parsed_address": {
                      "type": "object",
                      "nullable": true,
                      "description": "Current structured address, or `null` when none exists. Includes the recomputed `formatted_address` alongside the seven editable keys. Returned as stored — after a server-side geocode it can contain bookkeeping keys (e.g. `raw_results`) alongside the editable keys.",
                      "properties": {
                        "address_type": {
                          "type": "string",
                          "nullable": true,
                          "description": "Free-form address classification (e.g. `home`)."
                        },
                        "city": {
                          "type": "string",
                          "nullable": true,
                          "example": "Madrid"
                        },
                        "region": {
                          "type": "string",
                          "nullable": true,
                          "description": "State / province / autonomous community."
                        },
                        "street_1": {
                          "type": "string",
                          "nullable": true,
                          "example": "Avda de Madrid 34"
                        },
                        "street_2": {
                          "type": "string",
                          "nullable": true
                        },
                        "postal_code": {
                          "type": "string",
                          "nullable": true,
                          "example": "28013"
                        },
                        "country": {
                          "type": "string",
                          "nullable": true,
                          "description": "ISO 3166-1 alpha-2 country code. Lowercase input is normalized to uppercase; alpha-3 codes are rejected with `400`.",
                          "example": "ES"
                        },
                        "formatted_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Joined, human-readable form of the structured address. Recomputed server-side after every `poa_parsed_address` edit.",
                          "example": "Avda de Madrid 34, Madrid, 28013, ES"
                        }
                      }
                    },
                    "poa_formatted_address": {
                      "type": "string",
                      "nullable": true,
                      "description": "Top-level copy of the recomputed `formatted_address`, kept in sync when the structured address changes.",
                      "example": "Avda de Madrid 34, Madrid, 28013, ES"
                    }
                  }
                },
                "examples": {
                  "Updated POA": {
                    "summary": "Full POA record after the correction",
                    "value": {
                      "issuing_state": "ESP",
                      "document_type": "BANK_STATEMENT",
                      "document_language": "es",
                      "issuer": "Banco Example S.A.",
                      "issue_date": "2026-05-02",
                      "poa_address": "Avda de Madrid 34, 28013 Madrid",
                      "name_on_document": "Carmen Espanola",
                      "extra_fields": {
                        "bank_account_number": null,
                        "bank_iban": "ES9121000418450200051332",
                        "bank_sort_code": null,
                        "bank_routing_number": null,
                        "bank_swift_bic": null,
                        "bank_branch_name": null,
                        "bank_branch_address": null,
                        "document_phone_number": null,
                        "additional_names": [
                          "Carmen E. Espanola"
                        ]
                      },
                      "poa_parsed_address": {
                        "city": "Madrid",
                        "street_1": "Avda de Madrid 34",
                        "postal_code": "28013",
                        "country": "ES",
                        "formatted_address": "Avda de Madrid 34, Madrid, 28013, ES"
                      },
                      "poa_formatted_address": "Avda de Madrid 34, Madrid, 28013, ES"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field errors arrive as `{\"<field>\": [\"<message>\"]}`; errors on nested `poa_parsed_address` / `extra_fields` keys use an object value: `{\"extra_fields\": {\"<key>\": \"<message>\"}}`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid document type": {
                    "summary": "Enum is uppercase — lowercase variants are rejected",
                    "value": {
                      "document_type": [
                        "\"utility_bill\" is not a valid choice."
                      ]
                    }
                  },
                  "Invalid issuing state": {
                    "summary": "issuing_state is not ISO 3166-1 alpha-3",
                    "value": {
                      "issuing_state": [
                        "Invalid ISO 3166-1 alpha-3 country code for issuing_state."
                      ]
                    }
                  },
                  "additional_names not a list": {
                    "summary": "additional_names accepts a list of strings or null",
                    "value": {
                      "extra_fields": {
                        "additional_names": "Must be a list or null."
                      }
                    }
                  },
                  "Unsupported poa_parsed_address key": {
                    "summary": "Only the seven documented keys are allowed",
                    "value": {
                      "poa_parsed_address": {
                        "zipcode": "Unsupported key. Allowed keys: address_type, city, region, street_1, street_2, postal_code, country"
                      }
                    }
                  },
                  "Bad date format": {
                    "summary": "Dates must be YYYY-MM-DD",
                    "value": {
                      "issue_date": [
                        "Date has wrong format. Use one of these formats instead: YYYY-MM-DD."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "Credential lacks write:sessions",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown session, session in a non-editable state, or no POA record to patch. Each case has a distinct `detail` message (see examples). The unknown-session lookup runs before credential checks.",
            "content": {
              "application/json": {
                "examples": {
                  "Unknown session": {
                    "summary": "No session with this ID in your application (or it was deleted)",
                    "value": {
                      "detail": "Not found."
                    }
                  },
                  "Wrong session state": {
                    "summary": "Session exists but is not Approved / Declined / In Review / Kyc Expired",
                    "value": {
                      "detail": "No Session matches the given query."
                    }
                  },
                  "No POA record": {
                    "summary": "The workflow never ran a Proof of Address step",
                    "value": {
                      "detail": "The session does not have a POA."
                    }
                  },
                  "No POA for node": {
                    "summary": "node_id given but no POA exists for it",
                    "value": {
                      "detail": "The session does not have a POA for node 'feature_missing'."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Dedicated rate limit exceeded — 10 POA data updates per minute per API key (rejected requests count toward the budget). The shared 300/min write budget can also trigger with its own message. Inspect `Retry-After` and the `X-RateLimit-*` response headers before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Rate limited": {
                    "summary": "POA update budget exhausted",
                    "value": {
                      "detail": "Session POA data update rate limit exceeded. You can make up to 10 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-poa-data/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"issuing_state\": \"ESP\",\n    \"document_type\": \"BANK_STATEMENT\",\n    \"issuer\": \"Banco Example S.A.\",\n    \"issue_date\": \"2026-05-02\",\n    \"name_on_document\": \"Carmen Espanola\",\n    \"poa_address\": \"Avda de Madrid 34, 28013 Madrid\",\n    \"extra_fields\": {\n      \"bank_iban\": \"ES9121000418450200051332\"\n    },\n    \"poa_parsed_address\": {\n      \"city\": \"Madrid\",\n      \"postal_code\": \"28013\",\n      \"country\": \"ES\"\n    }\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-poa-data/\",\n    headers={\n        \"x-api-key\": \"YOUR_API_KEY\",\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"issuing_state\": \"ESP\",\n        \"document_type\": \"BANK_STATEMENT\",\n        \"issuer\": \"Banco Example S.A.\",\n        \"issue_date\": \"2026-05-02\",\n        \"name_on_document\": \"Carmen Espanola\",\n        \"poa_address\": \"Avda de Madrid 34, 28013 Madrid\",\n        \"extra_fields\": {\"bank_iban\": \"ES9121000418450200051332\"},\n        \"poa_parsed_address\": {\"city\": \"Madrid\", \"postal_code\": \"28013\", \"country\": \"ES\"},\n    },\n)\nresponse.raise_for_status()\npoa = response.json()  # full current POA record\nprint(poa[\"issuer\"], poa[\"poa_formatted_address\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/update-poa-data/',\n  {\n    method: 'PATCH',\n    headers: {\n      'x-api-key': process.env.DIDIT_API_KEY,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      issuing_state: 'ESP',\n      document_type: 'BANK_STATEMENT',\n      issuer: 'Banco Example S.A.',\n      issue_date: '2026-05-02',\n      name_on_document: 'Carmen Espanola',\n      poa_address: 'Avda de Madrid 34, 28013 Madrid',\n      poa_parsed_address: { city: 'Madrid', postal_code: '28013', country: 'ES' },\n    }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst poa = await response.json(); // full current POA record"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/kyb/{companyUuid}/update-data/": {
      "patch": {
        "summary": "Update registry-extracted company data on a Business Verification (KYB) session",
        "description": "Correct the registry-extracted company data on a Business Verification (KYB) session — company name, registration number, addresses, status, contact details — identified by `companyUuid`. Typical callers are a compliance analyst fixing a registry misread, or your back office syncing corrected company data. Every field in the body is optional (`PATCH` semantics); an empty JSON body (`{}`) is a no-op that simply echoes the current company record.\n\nEdits are written in two places at once: fields with a canonical company column (name, registration number, country, incorporation date, tax number, type, statuses, capital fields (`registered_capital`, `registered_capital_amount`, `registered_capital_currency`), alternative names, nature of business, website, email, phone, LEI, location, and `legal_address` → `registered_address`) update that column, and **every** submitted key is also merged into the `registry_data` snapshot (dates as ISO strings) so the \"extracted from registry\" view reflects the correction. Fields without a column — `region`, `registration_date`, `dissolution_date`, `control_scheme` — land in `registry_data` only. `user_provided_data` (what the end user confirmed in the hosted flow) is never touched, and `last_console_edit_at` is stamped on every non-empty PATCH.\n\nUnlike the KYC/POA update endpoints, there is **no session-status gate**: the company can be edited at any point in the business session's lifecycle. The company must belong to the session in the path (`404` with `\"KYB company does not belong to the given session.\"` otherwise) and to your application. Every non-empty PATCH fires the `data.updated` [webhook](/integration/webhooks) on the business session (trigger `console_registry_edit`) — even when the submitted values equal the stored ones. The session's status and decision are **not** re-evaluated, and no review/audit entry is recorded.\n\nAccepts an API key or a console user token; either way the credential needs the `write:businesses` permission. Authentication and permission failures both return `403` — this API never responds `401`. Note that the session lookup runs before credential checks, so an unknown `sessionId` returns `404` even with missing credentials. The shared write budget of 300 requests per minute per API key applies.\n\nFor User Verification sessions, the KYC counterpart is `PATCH /v3/session/{sessionId}/update-data/`; to change the session decision itself use `PATCH /v3/session/{sessionId}/update-status/`.",
        "operationId": "patch_v3_session_kyb_company_update_data",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "UUID of the parent Business Verification (KYB) session.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "33333333-4444-5555-6666-777777777777"
            }
          },
          {
            "name": "companyUuid",
            "in": "path",
            "required": true,
            "description": "UUID of the company record to update (`registry_checks[].company.uuid` on the business session decision). Must belong to the session referenced by `sessionId`.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "88888888-9999-aaaa-bbbb-cccccccccccc"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "All fields optional — send only what you want to change. Provided fields update the canonical company columns (where one exists) and are merged into the `registry_data` snapshot.",
                "properties": {
                  "company_name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Legal name of the company. Written to the canonical column and the registry snapshot.",
                    "example": "Docs Probe Corp"
                  },
                  "registration_number": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Official registration number with the company registry.",
                    "example": "DPC-001"
                  },
                  "country_code": {
                    "type": "string",
                    "maxLength": 2,
                    "description": "Country of incorporation, ISO 3166-1 alpha-2. Case-insensitive (`us` is stored as `US`). Alpha-3 codes fail the 2-character limit with `400`.",
                    "example": "US"
                  },
                  "region": {
                    "type": "string",
                    "maxLength": 10,
                    "nullable": true,
                    "description": "Subdivision / region tag where the registry has one (e.g. US state). Stored in the registry snapshot only — it has no canonical column."
                  },
                  "incorporation_date": {
                    "type": "string",
                    "format": "date",
                    "description": "Incorporation date in `YYYY-MM-DD`. Optional like every other field — the `PATCH` is partial. Any other date format returns `400`.",
                    "example": "2015-04-12"
                  },
                  "registration_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Registration date where the registry distinguishes it from incorporation. Stored in the registry snapshot only."
                  },
                  "dissolution_date": {
                    "type": "string",
                    "format": "date",
                    "nullable": true,
                    "description": "Dissolution date for companies that are no longer active. Stored in the registry snapshot only."
                  },
                  "tax_number": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Tax identification number."
                  },
                  "legal_address": {
                    "type": "string",
                    "description": "Legal / registered address. Aliased server-side to the canonical `registered_address` column — the response returns it under `registered_address`, while the registry snapshot keeps the `legal_address` key you sent.",
                    "example": "1 Example Plaza, Wilmington, DE 19801"
                  },
                  "company_type": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Legal entity type (e.g. `Limited Liability Company`, `PLC`, `GmbH`).",
                    "example": "Limited Liability Company"
                  },
                  "registry_status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "dissolved",
                      "deregistered",
                      "see full details",
                      "authorised",
                      "appointed representative",
                      "unauthorised",
                      "inactive",
                      "no longer authorised",
                      "closed",
                      "struck off"
                    ],
                    "nullable": true,
                    "description": "Registry-reported company status. Lowercase, some values contain spaces (e.g. `struck off`, `no longer authorised`). Any other value returns `400`.",
                    "example": "active"
                  },
                  "verification_status": {
                    "type": "string",
                    "enum": [
                      "verified",
                      "failed",
                      "unknown"
                    ],
                    "nullable": true,
                    "description": "Outcome of the registry verification. Any other value returns `400`.",
                    "example": "verified"
                  },
                  "alternative_names": {
                    "type": "string",
                    "description": "Trade names, former legal names, DBA names (free text)."
                  },
                  "nature_of_business": {
                    "type": "string",
                    "description": "Short description of the company's activity.",
                    "example": "Software development"
                  },
                  "registered_capital": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "Human-readable registered capital (e.g. `USD 50000`). Use `registered_capital_amount` + `registered_capital_currency` for structured values, or this field for free-form text.",
                    "example": "USD 50000"
                  },
                  "registered_capital_amount": {
                    "type": "number",
                    "format": "double",
                    "nullable": true,
                    "description": "Numeric registered-capital amount (up to 20 digits, 2 decimal places). Sets the `registered_capital_amount` column and is mirrored into `registry_data` as a decimal string; the response echoes it as a decimal string (e.g. `\"1500000.50\"`)."
                  },
                  "registered_capital_currency": {
                    "type": "string",
                    "maxLength": 3,
                    "nullable": true,
                    "description": "ISO 4217 currency code for `registered_capital_amount`. Case-insensitive (`usd` is stored as `USD`); values that are not exactly 3 letters return `400` with the ISO 4217 message. Sets the canonical `registered_capital_currency` column and is mirrored into `registry_data`.",
                    "example": "USD"
                  },
                  "website": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Company website. Bare domains are accepted and normalized with an `https://` prefix (`docsprobe.example.com` is stored as `https://docsprobe.example.com`); values that still fail URL validation return `400`.",
                    "example": "https://docsprobe.example.com"
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Contact email on file with the registry.",
                    "example": "legal@docsprobe.example.com"
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 50,
                    "description": "Contact phone. Must match `+`, digits, spaces, dashes, dots, or parentheses, with 7-15 digits total — otherwise `400`.",
                    "example": "+1 302 555 0143"
                  },
                  "legal_entity_identifier": {
                    "type": "string",
                    "maxLength": 50,
                    "description": "LEI, where the company has one."
                  },
                  "location_of_registration": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "City / subdivision of the registry of record."
                  },
                  "vat_number": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "EU VAT number. Merged into the `registry_data` snapshot only — editing it here does not re-run VAT and tax ID validation, so `vat_validation_status` and the other `vat_*` result fields are unchanged."
                  },
                  "control_scheme": {
                    "type": "string",
                    "description": "Control / governance scheme when the registry exposes it. Stored in the registry snapshot only."
                  }
                }
              },
              "examples": {
                "Correct registry data": {
                  "summary": "Fix the company's registry-extracted fields",
                  "value": {
                    "company_name": "Docs Probe Corp",
                    "registration_number": "DPC-001",
                    "country_code": "US",
                    "incorporation_date": "2015-04-12",
                    "company_type": "Limited Liability Company",
                    "legal_address": "1 Example Plaza, Wilmington, DE 19801",
                    "registry_status": "active",
                    "verification_status": "verified",
                    "website": "docsprobe.example.com",
                    "email": "legal@docsprobe.example.com",
                    "phone": "+1 302 555 0143",
                    "registered_capital": "USD 50000",
                    "nature_of_business": "Software development"
                  }
                },
                "Single field": {
                  "summary": "Only the keys you send are written",
                  "value": {
                    "registry_status": "dissolved"
                  }
                },
                "No-op": {
                  "summary": "Empty body echoes the current record without firing the webhook",
                  "value": {}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Company data updated (or echoed unchanged for an empty body). Returns the full KYB company record — the same shape as `registry_checks[].company` on the business session decision. Note how `legal_address` comes back as `registered_address`. `registered_capital_amount`/`registered_capital_currency` populate their canonical columns and are mirrored into `registry_data`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Full KYB company record — the same shape as the `company` object inside `registry_checks[]` on the business session decision.",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Company record identifier (the `companyUuid` path parameter)."
                    },
                    "node_id": {
                      "type": "string",
                      "nullable": true,
                      "description": "Workflow graph node this company record belongs to, when the workflow is graph-based."
                    },
                    "status": {
                      "type": "string",
                      "description": "Feature lifecycle status of the registry check (e.g. `Not Finished`, `Approved`, `Declined`, `In Review`)."
                    },
                    "registry_status": {
                      "type": "string",
                      "nullable": true,
                      "description": "Registry-reported company status (e.g. `active`, `dissolved`, `struck off`)."
                    },
                    "data_resolved": {
                      "type": "boolean",
                      "description": "`true` when the company data is complete — always `true` for manual-entry companies; for registry-sourced companies, `true` once the registry fetch resolved."
                    },
                    "company_name": {
                      "type": "string",
                      "nullable": true
                    },
                    "registration_number": {
                      "type": "string",
                      "nullable": true
                    },
                    "country_code": {
                      "type": "string",
                      "nullable": true,
                      "description": "ISO 3166-1 alpha-2 country of incorporation."
                    },
                    "region": {
                      "type": "string",
                      "nullable": true
                    },
                    "company_type": {
                      "type": "string",
                      "nullable": true
                    },
                    "incorporation_date": {
                      "type": "string",
                      "format": "date",
                      "nullable": true
                    },
                    "registered_address": {
                      "type": "string",
                      "nullable": true,
                      "description": "Canonical registered address — updated when you send `legal_address`."
                    },
                    "tax_number": {
                      "type": "string",
                      "nullable": true
                    },
                    "risk_level": {
                      "type": "string",
                      "nullable": true
                    },
                    "verification_status": {
                      "type": "string",
                      "nullable": true,
                      "description": "`verified`, `failed`, or `unknown`."
                    },
                    "is_from_registry": {
                      "type": "boolean",
                      "description": "`true` when the company was pre-filled from a registry search rather than entered manually."
                    },
                    "fetch_status": {
                      "type": "string",
                      "nullable": true,
                      "description": "Registry fetch lifecycle for registry-sourced companies (`pending` / `resolved`); `null` for manual entries."
                    },
                    "alternative_names": {
                      "type": "string",
                      "nullable": true,
                      "description": "Alternative, trading, former or original-language company names as text, when reported."
                    },
                    "nature_of_business": {
                      "type": "string",
                      "nullable": true
                    },
                    "registered_capital": {
                      "type": "string",
                      "nullable": true
                    },
                    "registered_capital_amount": {
                      "type": "string",
                      "nullable": true,
                      "description": "Canonical column. Returned as a decimal string (e.g. `\"2750000.00\"`)."
                    },
                    "registered_capital_currency": {
                      "type": "string",
                      "nullable": true,
                      "description": "Canonical column. Set by the registry flow or by console/API edits via this endpoint."
                    },
                    "website": {
                      "type": "string",
                      "nullable": true
                    },
                    "email": {
                      "type": "string",
                      "nullable": true
                    },
                    "phone": {
                      "type": "string",
                      "nullable": true
                    },
                    "legal_entity_identifier": {
                      "type": "string",
                      "nullable": true
                    },
                    "location_of_registration": {
                      "type": "string",
                      "nullable": true
                    },
                    "vat_number": {
                      "type": "string",
                      "nullable": true,
                      "description": "EU VAT number, when collected during the hosted registry step or edited afterwards."
                    },
                    "vat_validation_status": {
                      "type": "string",
                      "enum": [
                        "valid",
                        "invalid",
                        "format_valid",
                        "invalid_format",
                        "could_not_validate",
                        "not_applicable"
                      ],
                      "description": "Result of validating the VAT number or, when there is none, the `tax_number`, at registry submit. `valid` / `invalid`: decided by the official registry of the country (EU VIES, Norway, Switzerland, Brazil, Colombia, Costa Rica, Ecuador, Paraguay; Poland also by its domestic VAT register). `format_valid` / `invalid_format`: decided by the country's format and check-digit rules where no registry can be queried. `could_not_validate`: the registry was unavailable. `not_applicable`: no number, a country without registry or rules, or a sandbox session."
                    },
                    "vat_validated_number": {
                      "type": "string",
                      "nullable": true,
                      "description": "The number that was checked, as the source knows it (for example the VAT number derived from a French SIREN or a Dutch RSIN). `null` when no check ran."
                    },
                    "vat_validation_source": {
                      "type": "string",
                      "nullable": true,
                      "enum": [
                        "eu_vies",
                        "pl_vat_white_list",
                        "no_brreg",
                        "ch_uid_register",
                        "br_receita_federal",
                        "co_rues",
                        "cr_hacienda",
                        "ec_sri",
                        "py_dnit",
                        "format_rules",
                        null
                      ],
                      "description": "The source that decided `vat_validation_status`: an official registry, or `format_rules`. `null` when no check ran."
                    },
                    "vat_validated_name": {
                      "type": "string",
                      "nullable": true,
                      "description": "Name registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                    },
                    "vat_validated_address": {
                      "type": "string",
                      "nullable": true,
                      "description": "Address registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                    },
                    "vat_checked_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "Timestamp of the check. `null` when no check ran."
                    },
                    "financial_summary": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true
                    },
                    "officers": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Directors / officers attached to the company, including per-person KYC progress."
                    },
                    "beneficial_owners": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Beneficial owners attached to the company, including per-person KYC progress."
                    },
                    "addresses": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Registry address detail, when the registry returned any."
                    },
                    "industries": {
                      "type": "array",
                      "nullable": true,
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "Registry industry classification, when available."
                    },
                    "accounts": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Registry filing dates, when available. Annual returns and general meetings use last_annual_return_date and last_agm_date; they are distinct from financial accounts."
                    },
                    "registry_data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "Raw registry payload snapshot. Every key you PATCH is merged into this map (dates serialized as ISO strings), so the \"extracted from registry\" view reflects operator corrections."
                    },
                    "user_provided_data": {
                      "type": "object",
                      "nullable": true,
                      "additionalProperties": true,
                      "description": "What the end user typed during the hosted registry-confirmation step. Never modified by this endpoint."
                    },
                    "confirmed_by_user_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "When the end user confirmed the company data in the hosted flow."
                    },
                    "last_console_edit_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "Stamped on every successful non-empty PATCH, so UIs can surface \"edited by operator\" context."
                    },
                    "is_editable": {
                      "type": "boolean",
                      "description": "`true` while the end user can still edit the registry-sourced data in the hosted flow (registry-sourced and not yet confirmed)."
                    }
                  }
                },
                "examples": {
                  "Updated company": {
                    "summary": "Full company record after the correction",
                    "value": {
                      "uuid": "6b9479f5-6769-46c8-baf1-df63bbbc5f8c",
                      "node_id": null,
                      "status": "Not Finished",
                      "registry_status": "active",
                      "data_resolved": true,
                      "company_name": "Docs Probe Corp",
                      "registration_number": "DPC-001",
                      "country_code": "US",
                      "region": null,
                      "company_type": "Limited Liability Company",
                      "incorporation_date": "2015-04-12",
                      "registered_address": "1 Example Plaza, Wilmington, DE 19801",
                      "tax_number": null,
                      "risk_level": null,
                      "verification_status": "verified",
                      "is_from_registry": false,
                      "fetch_status": null,
                      "alternative_names": null,
                      "nature_of_business": "Software development",
                      "registered_capital": "USD 50000",
                      "registered_capital_amount": null,
                      "registered_capital_currency": "USD",
                      "website": "https://docsprobe.example.com",
                      "email": "legal@docsprobe.example.com",
                      "phone": "+1 302 555 0143",
                      "legal_entity_identifier": null,
                      "location_of_registration": null,
                      "financial_summary": null,
                      "officers": [],
                      "beneficial_owners": [],
                      "addresses": null,
                      "industries": null,
                      "accounts": null,
                      "registry_data": {
                        "company_name": "Docs Probe Corp",
                        "registration_number": "DPC-001",
                        "country_code": "US",
                        "incorporation_date": "2015-04-12",
                        "legal_address": "1 Example Plaza, Wilmington, DE 19801",
                        "company_type": "Limited Liability Company",
                        "registry_status": "active",
                        "verification_status": "verified",
                        "nature_of_business": "Software development",
                        "registered_capital": "USD 50000",
                        "registered_capital_currency": "USD",
                        "website": "https://docsprobe.example.com",
                        "email": "legal@docsprobe.example.com",
                        "phone": "+1 302 555 0143"
                      },
                      "user_provided_data": null,
                      "confirmed_by_user_at": null,
                      "last_console_edit_at": "2026-06-12T00:02:34.276061Z",
                      "is_editable": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field errors arrive as `{\"<field>\": [\"<message>\"]}`. Max-length checks run before format checks, so `country_code: \"USA\"` reports the 2-character limit rather than the ISO message.",
            "content": {
              "application/json": {
                "examples": {
                  "Alpha-3 country code": {
                    "summary": "country_code must be alpha-2 — length check fires first",
                    "value": {
                      "country_code": [
                        "Ensure this field has no more than 2 characters."
                      ]
                    }
                  },
                  "Non-alphabetic country code": {
                    "summary": "2 characters but not letters",
                    "value": {
                      "country_code": [
                        "country_code must be a 2-letter ISO 3166-1 alpha-2 code."
                      ]
                    }
                  },
                  "Invalid currency": {
                    "summary": "3 characters but not an ISO 4217 code",
                    "value": {
                      "registered_capital_currency": [
                        "Currency must be a 3-letter ISO 4217 code (e.g. USD, EUR, GBP)."
                      ]
                    }
                  },
                  "Invalid phone": {
                    "summary": "Phone fails the format / digit-count check",
                    "value": {
                      "phone": [
                        "Invalid phone number format."
                      ]
                    }
                  },
                  "Invalid registry status": {
                    "summary": "registry_status not in the enum",
                    "value": {
                      "registry_status": [
                        "\"liquidated\" is not a valid choice."
                      ]
                    }
                  },
                  "Invalid email": {
                    "summary": "Malformed email address",
                    "value": {
                      "email": [
                        "Enter a valid email address."
                      ]
                    }
                  },
                  "Invalid website": {
                    "summary": "Value fails URL validation even after https:// normalization",
                    "value": {
                      "website": [
                        "Enter a valid URL."
                      ]
                    }
                  },
                  "Bad date format": {
                    "summary": "Dates must be YYYY-MM-DD",
                    "value": {
                      "incorporation_date": [
                        "Date has wrong format. Use one of these formats instead: YYYY-MM-DD."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "Credential lacks write:businesses",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown session, unknown company, or a company that belongs to a different session. Each case has a distinct `detail` message (see examples). The unknown-session lookup runs before credential checks.",
            "content": {
              "application/json": {
                "examples": {
                  "Unknown session": {
                    "summary": "No session with this ID in your application (or it was deleted)",
                    "value": {
                      "detail": "Not found."
                    }
                  },
                  "Unknown company": {
                    "summary": "No company with this UUID in your application",
                    "value": {
                      "detail": "No KYBCompany matches the given query."
                    }
                  },
                  "Company / session mismatch": {
                    "summary": "companyUuid exists but belongs to another session",
                    "value": {
                      "detail": "KYB company does not belong to the given session."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared write rate limit exceeded (300 POST/PATCH/DELETE requests per minute per API key). Inspect `Retry-After` and the `X-RateLimit-*` response headers before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Rate limited": {
                    "summary": "Write budget exhausted",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH \\\n  https://verification.didit.me/v3/session/33333333-4444-5555-6666-777777777777/kyb/88888888-9999-aaaa-bbbb-cccccccccccc/update-data/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"company_name\": \"Docs Probe Corp\",\n    \"registration_number\": \"DPC-001\",\n    \"country_code\": \"US\",\n    \"incorporation_date\": \"2015-04-12\",\n    \"company_type\": \"Limited Liability Company\",\n    \"legal_address\": \"1 Example Plaza, Wilmington, DE 19801\",\n    \"registry_status\": \"active\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nresponse = requests.patch(\n    \"https://verification.didit.me/v3/session/33333333-4444-5555-6666-777777777777/kyb/\"\n    \"88888888-9999-aaaa-bbbb-cccccccccccc/update-data/\",\n    headers={\n        \"x-api-key\": \"YOUR_API_KEY\",\n        \"Content-Type\": \"application/json\",\n    },\n    json={\n        \"company_name\": \"Docs Probe Corp\",\n        \"registration_number\": \"DPC-001\",\n        \"country_code\": \"US\",\n        \"incorporation_date\": \"2015-04-12\",\n        \"legal_address\": \"1 Example Plaza, Wilmington, DE 19801\",\n        \"registry_status\": \"active\",\n    },\n)\nresponse.raise_for_status()\ncompany = response.json()  # full company record\nprint(company[\"company_name\"], company[\"registered_address\"])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const response = await fetch(\n  'https://verification.didit.me/v3/session/33333333-4444-5555-6666-777777777777/kyb/' +\n    '88888888-9999-aaaa-bbbb-cccccccccccc/update-data/',\n  {\n    method: 'PATCH',\n    headers: {\n      'x-api-key': process.env.DIDIT_API_KEY,\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      company_name: 'Docs Probe Corp',\n      registration_number: 'DPC-001',\n      country_code: 'US',\n      incorporation_date: '2015-04-12',\n      legal_address: '1 Example Plaza, Wilmington, DE 19801',\n      registry_status: 'active',\n    }),\n  },\n);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst company = await response.json(); // full company record"
          }
        ]
      }
    },
    "/v3/session/{sessionId}/kyb/parties/{partyUuid}/": {
      "patch": {
        "summary": "Skip (or re-require) a Key People party on a Business Verification (KYB) session",
        "description": "Exempt a Key People party from verification, or put it back in scope. This is the operator escape hatch for a party that can never finish its own check - most often because the individual KYC session handed to a UBO or director was deleted, which freezes that child's status and leaves the KYB parked in `Awaiting User` with nothing left that could move it.\n\nSetting `is_skipped: true` drops the party out of the Key People aggregation and immediately recomputes the `KYBKeyPeopleCheck` and the parent session status, so the business session can settle and then be approved or declined. Sending `is_skipped: false` puts the party back in scope and the check goes back to waiting on it.\n\nUnlike the applicant-facing skip in the hosted Key People screen, this endpoint is **not** gated by the role's `allow_skip` setting - that flag limits what the applicant may decide, not what your analyst may override. `requires_verification` is deliberately left untouched, so an overridden party reads as `requires_verification: true` **and** `is_skipped: true` and the record still shows what the rules asked for.\n\nThe party must belong to the session in the path (`404` with `\"Party does not belong to the given session.\"` otherwise) and to your application. A PATCH that actually changes the flag fires the `data.updated` [webhook](/integration/webhooks) on the business session with trigger `console_key_people_skip`; a PATCH that sets the flag to its current value is a no-op that echoes the party back.\n\nAccepts an API key or a console user token; either way the credential needs the `write:businesses` permission.",
        "operationId": "patch_v3_session_kyb_party_update",
        "tags": [
          "Sessions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "UUID of the parent Business Verification (KYB) session.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "33333333-4444-5555-6666-777777777777"
            }
          },
          {
            "name": "partyUuid",
            "in": "path",
            "required": true,
            "description": "UUID of the Key People party to update (`key_people_checks[].submitted.parties[].uuid` on the business session decision). Must belong to the session referenced by `sessionId`.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "0a3f1e2c-7c2f-4a1b-9d55-2f8d2a5d6b41"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_skipped"
                ],
                "properties": {
                  "is_skipped": {
                    "type": "boolean",
                    "description": "`true` exempts the party from verification so the Key People check can settle without it; `false` puts it back in scope.",
                    "example": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Party updated (or echoed unchanged when the flag already had this value). Returns the party - the same shape as an entry of `key_people_checks[].submitted.parties[]` on the business session decision.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Key People party record - the same shape as an entry of `key_people_checks[].submitted.parties[]` on the business session decision.",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Party identifier."
                    },
                    "entity_type": {
                      "type": "string",
                      "enum": [
                        "person",
                        "company"
                      ],
                      "description": "Whether the party is an individual or a company."
                    },
                    "name": {
                      "type": "string",
                      "description": "Display name of the party."
                    },
                    "is_skipped": {
                      "type": "boolean",
                      "description": "Whether the party is exempt from verification."
                    },
                    "requires_verification": {
                      "type": "boolean",
                      "description": "What the role and threshold rules asked for. Left untouched by this endpoint."
                    },
                    "kyc_session_status": {
                      "type": "string",
                      "nullable": true,
                      "description": "Status of the linked individual KYC session, frozen at deletion time when the session was deleted."
                    },
                    "kyc_session_url": {
                      "type": "string",
                      "nullable": true,
                      "description": "Link to the linked individual KYC session. `null` when there is none or when it was deleted."
                    },
                    "kyc_session_deleted": {
                      "type": "boolean",
                      "description": "The linked individual KYC session was deleted, so it can never settle."
                    },
                    "kyb_sub_session_deleted": {
                      "type": "boolean",
                      "description": "Corporate-party counterpart of `kyc_session_deleted`."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error on the request body. `is_skipped` is the only field this endpoint reads, and it is required. Field errors arrive as `{\"<field>\": [\"<message>\"]}`. Body validation runs *after* the party lookup, so a malformed `is_skipped` sent to a party that does not exist reports `404`, not `400`.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing is_skipped": {
                    "summary": "Empty body, or a body that omits `is_skipped`",
                    "value": {
                      "is_skipped": [
                        "This field is required."
                      ]
                    }
                  },
                  "Non-boolean is_skipped": {
                    "summary": "Value is not a boolean — `\"maybe\"`, `2`, `[]`. Booleans plus `\"true\"`/`\"false\"`, `1`/`0` and `\"yes\"`/`\"no\"` are all accepted",
                    "value": {
                      "is_skipped": [
                        "Must be a valid boolean."
                      ]
                    }
                  },
                  "Null is_skipped": {
                    "summary": "`is_skipped` is present but `null`",
                    "value": {
                      "is_skipped": [
                        "This field may not be null."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing/invalid credentials or insufficient permissions. This API returns `403` for authentication failures — never `401`.",
            "content": {
              "application/json": {
                "examples": {
                  "Invalid Credentials": {
                    "summary": "Missing or invalid x-api-key",
                    "value": {
                      "detail": "Authentication credentials were not provided or are invalid."
                    }
                  },
                  "Missing Privilege": {
                    "summary": "Credential lacks write:businesses",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown party, or a party that belongs to a different session. Each case has a distinct `detail` message (see examples). Credential and permission checks run before the party lookup, so an unauthorised call reports `403` rather than `404`. There is no separate session lookup: an unknown `sessionId` paired with a party of yours reports the mismatch message.",
            "content": {
              "application/json": {
                "examples": {
                  "Unknown party": {
                    "summary": "No party with this UUID in your application",
                    "value": {
                      "detail": "Not found."
                    }
                  },
                  "Party / session mismatch": {
                    "summary": "partyUuid exists but hangs off another session",
                    "value": {
                      "detail": "Party does not belong to the given session."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared write rate limit exceeded (300 POST/PATCH/DELETE requests per minute per API key). Inspect `Retry-After` and the `X-RateLimit-*` response headers before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Rate limited": {
                    "summary": "Write budget exhausted",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/travel-rule/settings/": {
      "get": {
        "summary": "Get Travel Rule settings",
        "description": "Read the application's Travel Rule settings and VASP profile. Auto-creates a default (disabled) settings row and an empty profile on first read.",
        "operationId": "getTravelRuleSettings",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET https://verification.didit.me/v3/travel-rule/settings/ \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Current Travel Rule settings and VASP profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleSettingsDetail"
                },
                "examples": {
                  "Disabled (default)": {
                    "value": {
                      "is_enabled": false,
                      "jurisdiction": "EU",
                      "name_matching_strictness": "DEFAULT",
                      "confirmation_timeout_hours": 48,
                      "timeout_outcome": "HOLD",
                      "threshold_amount": "0.00",
                      "legal_name": "",
                      "lei": "",
                      "compliance_email": "",
                      "is_discoverable": true,
                      "disabled_networks": [],
                      "networks": {
                        "gtr": {
                          "rail": "GTR",
                          "mode": "unavailable",
                          "platform_available": false,
                          "connected": false
                        },
                        "trust": {
                          "rail": "TRUST",
                          "mode": "unavailable",
                          "platform_available": false,
                          "connected": false
                        },
                        "verifyvasp": {
                          "rail": "VERIFYVASP",
                          "mode": "unavailable",
                          "platform_available": false,
                          "connected": false
                        },
                        "sygna": {
                          "rail": "SYGNA",
                          "mode": "unavailable",
                          "platform_available": false,
                          "connected": false
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Update Travel Rule settings",
        "description": "Upsert the application's Travel Rule settings and VASP profile. Partial update — only send the fields you want to change. Setting `is_enabled: true` requires a non-blank `legal_name` (already stored or included in the same request), otherwise returns 400.",
        "operationId": "updateTravelRuleSettings",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelRuleSettingsUpdate"
              },
              "example": {
                "is_enabled": true,
                "legal_name": "Origin CASP SL",
                "jurisdiction": "EU",
                "name_matching_strictness": "DEFAULT",
                "confirmation_timeout_hours": 48,
                "timeout_outcome": "HOLD",
                "is_discoverable": true
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PUT https://verification.didit.me/v3/travel-rule/settings/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"is_enabled\": true, \"legal_name\": \"Origin CASP SL\", \"jurisdiction\": \"EU\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated settings and profile, in the same shape as GET.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleSettingsDetail"
                }
              }
            }
          },
          "400": {
            "description": "Validation error, e.g. enabling without a legal_name.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "legal_name": [
                    "legal_name is required to enable travel rule."
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v3/travel-rule/wallet-addresses/": {
      "get": {
        "summary": "List wallet address book entries",
        "description": "Paginated list of your application's Travel Rule wallet address book, newest first.",
        "operationId": "listTravelRuleWalletAddresses",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET https://verification.didit.me/v3/travel-rule/wallet-addresses/ \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated wallet address book entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WalletAddressEntry"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Register a wallet address",
        "description": "Add an entry to your Travel Rule wallet address book so inbound INTERNAL-rail transfers can resolve against it.",
        "operationId": "createTravelRuleWalletAddress",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletAddressEntryCreate"
              },
              "example": {
                "address": "0xBeneficiaryWallet01",
                "chain": "ethereum",
                "holder_name": "Ana Diaz",
                "holder_vendor_data": "user-042",
                "self_declared": true
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/travel-rule/wallet-addresses/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"address\": \"0xBeneficiaryWallet01\", \"chain\": \"ethereum\", \"holder_name\": \"Ana Diaz\", \"self_declared\": true}'"
          }
        ],
        "responses": {
          "201": {
            "description": "The created entry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletAddressEntry"
                }
              }
            }
          },
          "400": {
            "description": "Duplicate address for this application and chain.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "address": [
                    "A wallet address entry with this address and chain already exists."
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v3/travel-rule/wallet-addresses/{entry_uuid}/": {
      "patch": {
        "summary": "Update wallet address holder metadata",
        "description": "Partial update of holder_name, holder_vendor_data, entity_type, and travel_address. Setting travel_address attaches a TRP routing address to the entry; invalid values are rejected with 400. The response echoes only these four fields.",
        "operationId": "updateTravelRuleWalletAddress",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "entry_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletAddressEntryUpdate"
              },
              "example": {
                "holder_name": "Ana Updated",
                "travel_address": "ta..."
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH https://verification.didit.me/v3/travel-rule/wallet-addresses/{entry_uuid}/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"holder_name\": \"Ana Updated\", \"travel_address\": \"ta...\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "The updated fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletAddressEntryUpdate"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a wallet address",
        "description": "Deletes the entry. It stops matching new transfers immediately and the address is freed up for re-registration.",
        "operationId": "deleteTravelRuleWalletAddress",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "entry_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE https://verification.didit.me/v3/travel-rule/wallet-addresses/{entry_uuid}/ \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          }
        }
      }
    },
    "/v3/travel-rule/vasps/": {
      "get": {
        "summary": "Search the VASP directory",
        "description": "Paginated search across discoverable Didit customers with Travel Rule enabled, plus VASPs catalogued in the internal counterparty registry. Excludes your own application's profile.",
        "operationId": "listTravelRuleVasps",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive substring match on VASP name."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/travel-rule/vasps/?search=Bene' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated, name-sorted VASP directory results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VaspDirectoryEntry"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/transactions/{transaction_id}/travel-rule/": {
      "patch": {
        "summary": "Finish, cancel, or resend a Travel Rule transfer",
        "description": "Provide `payment_txn_id` to report the on-chain hash and move an outbound COMPLETED transfer to FINISHED (its INTERNAL-rail counterpart also moves to FINISHED), `{\"action\": \"cancel\"}` to cancel a non-terminal transfer, or `{\"action\": \"resend\"}` to re-run routing for an outbound transfer stuck in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA (improve the counterparty data first, e.g. add a travel_address to the destination wallet entry).",
        "operationId": "patchTravelRuleTransfer",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "description": "Didit-stable transaction UUID that owns the transfer.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelRuleTransferPatchRequest"
              },
              "examples": {
                "Finish": {
                  "value": {
                    "payment_txn_id": "0xchainhash"
                  }
                },
                "Cancel": {
                  "value": {
                    "action": "cancel"
                  }
                },
                "Resend": {
                  "value": {
                    "action": "resend"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH https://verification.didit.me/v3/transactions/{transaction_id}/travel-rule/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"payment_txn_id\": \"0xchainhash\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "The updated transfer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleTransferDetail"
                }
              }
            }
          },
          "400": {
            "description": "Neither payment_txn_id nor a supported action (cancel, resend) was provided."
          },
          "409": {
            "description": "The transfer is not in a state that allows this operation (e.g. not COMPLETED/outbound for finish, already terminal for cancel, or not an outbound transfer in a resendable status for resend)."
          }
        }
      }
    },
    "/v3/transactions/{transaction_id}/travel-rule/ownership/": {
      "post": {
        "summary": "Confirm or deny wallet ownership",
        "description": "Called by the beneficiary's application when its INTERNAL-rail transfer is UNCONFIRMED_OWNERSHIP. Confirming marks the matching wallet address book entry as ownership-verified and runs the beneficiary name match on both sides of the transfer; denying declines both sides.",
        "operationId": "confirmTravelRuleOwnership",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "description": "Didit-stable transaction UUID that owns the transfer (the beneficiary side's transaction).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelRuleOwnershipConfirmRequest"
              },
              "example": {
                "confirmed": true
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/transactions/{transaction_id}/travel-rule/ownership/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"confirmed\": true}'"
          }
        ],
        "responses": {
          "200": {
            "description": "The updated transfer. originator_data/beneficiary_data are omitted until ownership_confirmed is true on an inbound transfer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleTransferDetail"
                }
              }
            }
          },
          "409": {
            "description": "The transfer is not currently UNCONFIRMED_OWNERSHIP, or its matching wallet address book entry was deleted."
          }
        }
      }
    },
    "/v3/travel-rule/pickup/{token}/": {
      "get": {
        "summary": "Get email-rail pickup info",
        "description": "Public, unauthenticated. Lets a non-Didit counterparty VASP preview the pending exchange from the emailed pickup link. The token itself is the authentication.",
        "operationId": "getTravelRulePickup",
        "tags": [
          "Travel Rule"
        ],
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl https://verification.didit.me/v3/travel-rule/pickup/{token}/"
          }
        ],
        "responses": {
          "200": {
            "description": "Pickup preview.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRulePickupInfo"
                }
              }
            }
          },
          "404": {
            "description": "Unknown token."
          },
          "410": {
            "description": "The pickup window has closed (expired, or the transfer already left AWAITING_COUNTERPARTY)."
          }
        }
      }
    },
    "/v3/travel-rule/pickup/{token}/respond/": {
      "post": {
        "summary": "Respond to an email-rail pickup",
        "description": "Public, unauthenticated. Accepts or declines the exchange from the emailed pickup link. On accept, beneficiary_name is checked against the originator's name_matching_strictness policy.",
        "operationId": "respondTravelRulePickup",
        "tags": [
          "Travel Rule"
        ],
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelRulePickupRespondRequest"
              },
              "example": {
                "decision": "accept",
                "beneficiary_name": "Carlos Ruiz"
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/travel-rule/pickup/{token}/respond/ \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"decision\": \"accept\", \"beneficiary_name\": \"Carlos Ruiz\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "The resulting exchange status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "status": "COMPLETED"
                }
              }
            }
          },
          "404": {
            "description": "Unknown token."
          },
          "410": {
            "description": "The pickup window has closed."
          }
        }
      }
    },
    "/v3/travel-rule/inbound/": {
      "post": {
        "summary": "Register an after-deposit (sunrise) inbound transfer",
        "description": "Register Travel Rule data for a crypto deposit that already settled on-chain before any exchange took place. Creates an inbound travelRule transaction (or reuses an unclaimed deposit) and resolves the transfer against your wallet address book. A transaction.created webhook fires for newly-created transactions.",
        "operationId": "registerTravelRuleInbound",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelRuleInboundRequest"
              },
              "example": {
                "chain": "ethereum",
                "txid": "0xdeposit-hash",
                "wallet_address": "0xYourDepositWallet",
                "amount": "500.00",
                "currency": "USDC",
                "originator_data": {
                  "name": "Origin CASP SL"
                },
                "beneficiary_data": {
                  "name": "Ana Diaz"
                },
                "originating_vasp": {
                  "name": "Origin CASP SL",
                  "lei": "",
                  "travel_address": "ta..."
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/travel-rule/inbound/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"chain\":\"ethereum\",\"txid\":\"0xdeposit-hash\",\"wallet_address\":\"0xYourDepositWallet\",\"amount\":\"500.00\",\"currency\":\"USDC\"}'"
          }
        ],
        "responses": {
          "201": {
            "description": "A new inbound transaction and transfer were created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleInboundResponse"
                }
              }
            }
          },
          "200": {
            "description": "An existing unclaimed deposit was reused (created is false).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleInboundResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/travel-rule/widget-session/": {
      "post": {
        "summary": "Mint a wallet-ownership widget session",
        "description": "Mint a hosted wallet-ownership widget URL/token. Send the customer to the returned url to prove control of a wallet (message signing, Satoshi test, screenshot, or self-declaration). The widget is web-only in this release - open the url in the system browser or a custom tab, never inside a mobile SDK webview.",
        "operationId": "createTravelRuleWidgetSession",
        "tags": [
          "Travel Rule"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelRuleWidgetSessionCreate"
              },
              "example": {
                "wallet_address": "0xBeneficiaryWallet01",
                "chain": "ethereum",
                "holder_name": "Ana Diaz",
                "vendor_data": "user-042",
                "transaction_id": "22222222-3333-4444-5555-666666666666",
                "expires_in_minutes": 60
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/travel-rule/widget-session/ \\\n  -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \\\n  -d '{\"wallet_address\":\"0xBeneficiaryWallet01\",\"chain\":\"ethereum\",\"holder_name\":\"Ana Diaz\"}'"
          }
        ],
        "responses": {
          "201": {
            "description": "The minted widget session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleWidgetSessionResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v3/travel-rule/widget/{token}/": {
      "get": {
        "summary": "Get wallet-ownership widget context",
        "description": "Public read endpoint keyed by the widget session token - no API key required. Returns the widget context plus the status of every proof, so you can poll it to detect completion; completed_at becomes non-null once a proof is verified. A SATOSHI_TEST proof can sit at status PENDING while its deposit is seen on-chain but unconfirmed - a background job automatically rechecks it and completes it once the deposit confirms, so no client action is needed while it waits. Each proof carries the fields its method needs: deposit_address, expected_amount, and its own expires_at for SATOSHI_TEST; challenge for MESSAGE_SIGNING. Prefer the travel_rule.status.updated webhook over polling when the session is linked to a transfer.",
        "operationId": "getTravelRuleWidgetContext",
        "tags": [
          "Travel Rule"
        ],
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "description": "Opaque session token returned when the widget session was minted.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl https://verification.didit.me/v3/travel-rule/widget/{token}/"
          }
        ],
        "responses": {
          "200": {
            "description": "The widget context and proof statuses.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelRuleWidgetContext"
                }
              }
            }
          },
          "404": {
            "description": "Unknown token."
          },
          "410": {
            "description": "The session expired without completing."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/vendor-users/toggle-ongoing-monitoring/": {
      "patch": {
        "summary": "Toggle AML ongoing monitoring for users",
        "description": "Enables or disables AML ongoing monitoring at the user level. Exactly one monitored AML screening is kept per user; users without any AML screening (for example imported users) get one created and screened first, billed as a regular AML screening. Set estimate_only to preview counts and costs without writing. Batches of 20 or fewer resolve inline (200, COMPLETED); larger batches return 202 and run asynchronously.",
        "operationId": "toggle_vendor_users_ongoing_monitoring",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_enabled"
                ],
                "properties": {
                  "is_enabled": {
                    "type": "boolean",
                    "description": "true to enable monitoring, false to disable it."
                  },
                  "estimate_only": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, returns the cost estimate and performs no writes."
                  },
                  "update_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "Apply to every entity of the application (scoped by the filter_* params when present)."
                  },
                  "filter_search": {
                    "type": "string"
                  },
                  "filter_status": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "filter_country": {
                    "type": "string"
                  },
                  "filter_date_from": {
                    "type": "string",
                    "format": "date"
                  },
                  "filter_date_to": {
                    "type": "string",
                    "format": "date"
                  },
                  "didit_internal_id_list": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Entities to toggle. Required unless update_all is true."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimate (when estimate_only) or the completed job for small batches processed inline.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "job_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "PENDING",
                            "PROCESSING",
                            "COMPLETED",
                            "FAILED"
                          ]
                        },
                        "is_enabled": {
                          "type": "boolean"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "processed": {
                          "type": "integer"
                        },
                        "outcomes": {
                          "type": "object",
                          "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                          "properties": {
                            "enabled": {
                              "type": "integer",
                              "description": "Monitoring enabled on an existing AML screening."
                            },
                            "screened_and_enabled": {
                              "type": "integer",
                              "description": "A new AML screening was created (billed) and monitoring enabled."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                            },
                            "disabled": {
                              "type": "integer",
                              "description": "Monitoring disabled on every AML row of the entity."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Skipped: no full name + date of birth + country available to screen."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Skipped: the user is blocked."
                            },
                            "skipped_sandbox": {
                              "type": "integer",
                              "description": "Skipped: sandbox application."
                            },
                            "failed_provider": {
                              "type": "integer",
                              "description": "The screening provider call failed."
                            },
                            "failed_insufficient_balance": {
                              "type": "integer",
                              "description": "Balance ran out mid-job."
                            }
                          }
                        },
                        "error": {
                          "type": "string",
                          "nullable": true
                        },
                        "estimate": {
                          "type": "object",
                          "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                          "properties": {
                            "users_total": {
                              "type": "integer",
                              "description": "Entities in the selection."
                            },
                            "already_enabled": {
                              "type": "integer"
                            },
                            "with_existing_aml": {
                              "type": "integer",
                              "description": "Entities whose existing AML screening will be switched to monitored."
                            },
                            "needing_screening": {
                              "type": "integer",
                              "description": "Entities without any AML screening that will be screened first (billed)."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer"
                            },
                            "skipped_blocked": {
                              "type": "integer"
                            },
                            "estimated_screening_cost_usd": {
                              "type": "number",
                              "example": 0.2
                            },
                            "estimated_annual_monitoring_cost_usd": {
                              "type": "number",
                              "example": 0.07
                            },
                            "balance_sufficient": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Larger batches are processed asynchronously; poll the job endpoint with the returned job_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring disabled on every AML row of the entity."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: no full name + date of birth + country available to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening provider call failed."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out mid-job."
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing write:sessions privilege, or insufficient balance to enable (the estimate is included in the error body)."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/vendor-users/toggle-ongoing-monitoring/{job_id}/": {
      "get": {
        "summary": "Get AML ongoing monitoring job",
        "description": "Progress and per-outcome counters of a monitoring toggle job. Poll every couple of seconds while status is PENDING or PROCESSING.",
        "operationId": "get_vendor_users_ongoing_monitoring_job",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Monitoring job UUID returned by the toggle endpoint."
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring disabled on every AML row of the entity."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: no full name + date of birth + country available to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening provider call failed."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out mid-job."
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown job for this application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/vendor-businesses/toggle-ongoing-monitoring/": {
      "patch": {
        "summary": "Toggle AML ongoing monitoring for businesses",
        "description": "Business-level equivalent of the user toggle: one monitored AML screening per business, with businesses lacking any AML screening screened first (company entity). Same estimate_only, inline fast-path and async job contract.",
        "operationId": "toggle_vendor_businesses_ongoing_monitoring",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_enabled"
                ],
                "properties": {
                  "is_enabled": {
                    "type": "boolean",
                    "description": "true to enable monitoring, false to disable it."
                  },
                  "estimate_only": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, returns the cost estimate and performs no writes."
                  },
                  "update_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "Apply to every entity of the application (scoped by the filter_* params when present)."
                  },
                  "filter_search": {
                    "type": "string"
                  },
                  "filter_status": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "filter_country": {
                    "type": "string"
                  },
                  "filter_date_from": {
                    "type": "string",
                    "format": "date"
                  },
                  "filter_date_to": {
                    "type": "string",
                    "format": "date"
                  },
                  "didit_internal_id_list": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Entities to toggle. Required unless update_all is true."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimate (when estimate_only) or the completed job for small batches processed inline.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "job_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "PENDING",
                            "PROCESSING",
                            "COMPLETED",
                            "FAILED"
                          ]
                        },
                        "is_enabled": {
                          "type": "boolean"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "processed": {
                          "type": "integer"
                        },
                        "outcomes": {
                          "type": "object",
                          "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                          "properties": {
                            "enabled": {
                              "type": "integer",
                              "description": "Monitoring enabled on an existing AML screening."
                            },
                            "screened_and_enabled": {
                              "type": "integer",
                              "description": "A new AML screening was created (billed) and monitoring enabled."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                            },
                            "disabled": {
                              "type": "integer",
                              "description": "Monitoring disabled on every AML row of the entity."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Skipped: no full name + date of birth + country available to screen."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Skipped: the user is blocked."
                            },
                            "skipped_sandbox": {
                              "type": "integer",
                              "description": "Skipped: sandbox application."
                            },
                            "failed_provider": {
                              "type": "integer",
                              "description": "The screening provider call failed."
                            },
                            "failed_insufficient_balance": {
                              "type": "integer",
                              "description": "Balance ran out mid-job."
                            }
                          }
                        },
                        "error": {
                          "type": "string",
                          "nullable": true
                        },
                        "estimate": {
                          "type": "object",
                          "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                          "properties": {
                            "users_total": {
                              "type": "integer",
                              "description": "Entities in the selection."
                            },
                            "already_enabled": {
                              "type": "integer"
                            },
                            "with_existing_aml": {
                              "type": "integer",
                              "description": "Entities whose existing AML screening will be switched to monitored."
                            },
                            "needing_screening": {
                              "type": "integer",
                              "description": "Entities without any AML screening that will be screened first (billed)."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer"
                            },
                            "skipped_blocked": {
                              "type": "integer"
                            },
                            "estimated_screening_cost_usd": {
                              "type": "number",
                              "example": 0.2
                            },
                            "estimated_annual_monitoring_cost_usd": {
                              "type": "number",
                              "example": 0.07
                            },
                            "balance_sufficient": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Larger batches are processed asynchronously; poll the job endpoint with the returned job_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring disabled on every AML row of the entity."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: no full name + date of birth + country available to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening provider call failed."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out mid-job."
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing write:sessions privilege, or insufficient balance to enable (the estimate is included in the error body)."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/vendor-businesses/toggle-ongoing-monitoring/{job_id}/": {
      "get": {
        "summary": "Get AML ongoing monitoring job",
        "description": "Progress and per-outcome counters of a monitoring toggle job. Poll every couple of seconds while status is PENDING or PROCESSING.",
        "operationId": "get_vendor_businesses_ongoing_monitoring_job",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Monitoring job UUID returned by the toggle endpoint."
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring disabled on every AML row of the entity."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: no full name + date of birth + country available to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening provider call failed."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out mid-job."
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown job for this application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/businesses/toggle-ongoing-monitoring/": {
      "patch": {
        "summary": "Toggle AML ongoing monitoring for business sessions",
        "description": "Session-level toggle for KYB verifications, addressed by session number. Sessions without an AML screening get one created and attached to the session itself. Same estimate_only, inline fast-path and async job contract as the user-level endpoints. Replaces the legacy synchronous behavior that skipped sessions without an AML screening.",
        "operationId": "toggle_business_sessions_ongoing_monitoring",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_enabled"
                ],
                "properties": {
                  "is_enabled": {
                    "type": "boolean",
                    "description": "true to enable monitoring, false to disable it."
                  },
                  "estimate_only": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, returns the cost estimate and performs no writes."
                  },
                  "update_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "Apply to every entity of the application (scoped by the filter_* params when present)."
                  },
                  "filter_search": {
                    "type": "string"
                  },
                  "filter_status": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "filter_country": {
                    "type": "string"
                  },
                  "filter_date_from": {
                    "type": "string",
                    "format": "date"
                  },
                  "filter_date_to": {
                    "type": "string",
                    "format": "date"
                  },
                  "session_numbers": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Business session numbers to toggle. Required unless update_all (or the legacy toggle_all alias) is true."
                  },
                  "toggle_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "Legacy alias of update_all."
                  },
                  "filter_workflow_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimate (when estimate_only) or the completed job for small batches processed inline.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "properties": {
                        "job_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "PENDING",
                            "PROCESSING",
                            "COMPLETED",
                            "FAILED"
                          ]
                        },
                        "is_enabled": {
                          "type": "boolean"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "processed": {
                          "type": "integer"
                        },
                        "outcomes": {
                          "type": "object",
                          "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                          "properties": {
                            "enabled": {
                              "type": "integer",
                              "description": "Monitoring enabled on an existing AML screening."
                            },
                            "screened_and_enabled": {
                              "type": "integer",
                              "description": "A new AML screening was created (billed) and monitoring enabled."
                            },
                            "already_enabled": {
                              "type": "integer",
                              "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                            },
                            "disabled": {
                              "type": "integer",
                              "description": "Monitoring disabled on every AML row of the entity."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer",
                              "description": "Skipped: no full name + date of birth + country available to screen."
                            },
                            "skipped_blocked": {
                              "type": "integer",
                              "description": "Skipped: the user is blocked."
                            },
                            "skipped_sandbox": {
                              "type": "integer",
                              "description": "Skipped: sandbox application."
                            },
                            "failed_provider": {
                              "type": "integer",
                              "description": "The screening provider call failed."
                            },
                            "failed_insufficient_balance": {
                              "type": "integer",
                              "description": "Balance ran out mid-job."
                            }
                          }
                        },
                        "error": {
                          "type": "string",
                          "nullable": true
                        },
                        "estimate": {
                          "type": "object",
                          "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                          "properties": {
                            "users_total": {
                              "type": "integer",
                              "description": "Entities in the selection."
                            },
                            "already_enabled": {
                              "type": "integer"
                            },
                            "with_existing_aml": {
                              "type": "integer",
                              "description": "Entities whose existing AML screening will be switched to monitored."
                            },
                            "needing_screening": {
                              "type": "integer",
                              "description": "Entities without any AML screening that will be screened first (billed)."
                            },
                            "skipped_no_identity_data": {
                              "type": "integer"
                            },
                            "skipped_blocked": {
                              "type": "integer"
                            },
                            "estimated_screening_cost_usd": {
                              "type": "number",
                              "example": 0.2
                            },
                            "estimated_annual_monitoring_cost_usd": {
                              "type": "number",
                              "example": 0.07
                            },
                            "balance_sufficient": {
                              "type": "boolean"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Larger batches are processed asynchronously; poll the job endpoint with the returned job_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring disabled on every AML row of the entity."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: no full name + date of birth + country available to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening provider call failed."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out mid-job."
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Missing write:sessions privilege, or insufficient balance to enable (the estimate is included in the error body)."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/businesses/toggle-ongoing-monitoring/{job_id}/": {
      "get": {
        "summary": "Get AML ongoing monitoring job",
        "description": "Progress and per-outcome counters of a monitoring toggle job. Poll every couple of seconds while status is PENDING or PROCESSING.",
        "operationId": "get_business_sessions_ongoing_monitoring_job",
        "tags": [
          "Businesses"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Monitoring job UUID returned by the toggle endpoint."
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "PENDING",
                        "PROCESSING",
                        "COMPLETED",
                        "FAILED"
                      ]
                    },
                    "is_enabled": {
                      "type": "boolean"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "processed": {
                      "type": "integer"
                    },
                    "outcomes": {
                      "type": "object",
                      "description": "Per-entity outcome counters. Nothing is silently skipped: every requested entity resolves to exactly one counter.",
                      "properties": {
                        "enabled": {
                          "type": "integer",
                          "description": "Monitoring enabled on an existing AML screening."
                        },
                        "screened_and_enabled": {
                          "type": "integer",
                          "description": "A new AML screening was created (billed) and monitoring enabled."
                        },
                        "already_enabled": {
                          "type": "integer",
                          "description": "Monitoring was already active (legacy duplicate rows are consolidated)."
                        },
                        "disabled": {
                          "type": "integer",
                          "description": "Monitoring disabled on every AML row of the entity."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer",
                          "description": "Skipped: no full name + date of birth + country available to screen."
                        },
                        "skipped_blocked": {
                          "type": "integer",
                          "description": "Skipped: the user is blocked."
                        },
                        "skipped_sandbox": {
                          "type": "integer",
                          "description": "Skipped: sandbox application."
                        },
                        "failed_provider": {
                          "type": "integer",
                          "description": "The screening provider call failed."
                        },
                        "failed_insufficient_balance": {
                          "type": "integer",
                          "description": "Balance ran out mid-job."
                        }
                      }
                    },
                    "error": {
                      "type": "string",
                      "nullable": true
                    },
                    "estimate": {
                      "type": "object",
                      "description": "Cost preview. Returned directly when estimate_only is true (no writes are performed).",
                      "properties": {
                        "users_total": {
                          "type": "integer",
                          "description": "Entities in the selection."
                        },
                        "already_enabled": {
                          "type": "integer"
                        },
                        "with_existing_aml": {
                          "type": "integer",
                          "description": "Entities whose existing AML screening will be switched to monitored."
                        },
                        "needing_screening": {
                          "type": "integer",
                          "description": "Entities without any AML screening that will be screened first (billed)."
                        },
                        "skipped_no_identity_data": {
                          "type": "integer"
                        },
                        "skipped_blocked": {
                          "type": "integer"
                        },
                        "estimated_screening_cost_usd": {
                          "type": "number",
                          "example": 0.2
                        },
                        "estimated_annual_monitoring_cost_usd": {
                          "type": "number",
                          "example": 0.07
                        },
                        "balance_sufficient": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown job for this application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/": {
      "get": {
        "summary": "List cases",
        "description": "List cases for the application, newest first. Supports filtering, search, and sorting; see query parameters. Paginated with `limit`/`offset`.",
        "operationId": "list_cases",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size. Defaults to 50."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset of the first record."
          },
          {
            "name": "status__in",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated statuses to include, e.g. OPEN,AWAITING_USER."
          },
          {
            "name": "priority",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated priorities to include."
          },
          {
            "name": "source__in",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated sources to include."
          },
          {
            "name": "blueprint",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to cases on this blueprint."
          },
          {
            "name": "assigned_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to cases assigned to this user."
          },
          {
            "name": "unassigned",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "true for unassigned cases, false for assigned cases."
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter to cases carrying this exact tag."
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Matches title, case_number, tag, subject name/UUID/external ID, linked session UUID, or linked transaction UUID."
          },
          {
            "name": "date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Created-at lower bound (inclusive)."
          },
          {
            "name": "date_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Created-at upper bound (inclusive)."
          },
          {
            "name": "due_before",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "due_at upper bound."
          },
          {
            "name": "overdue",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "true to return only overdue open/awaiting-user cases."
          },
          {
            "name": "ordering",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "created_at",
                "-created_at",
                "due_at",
                "-due_at"
              ],
              "default": "-created_at"
            },
            "description": "Sort order. due_at sorts nulls last."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/?status__in=OPEN,AWAITING_USER&ordering=-due_at' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.get(\n    'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    params={'status__in': 'OPEN,AWAITING_USER', 'ordering': '-due_at'},\n    timeout=10,\n)\nresp.raise_for_status()\nfor case in resp.json()['results']:\n    print(case['case_number'], case['title'], case['priority'], case['due_at'])"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated case list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows. Exact up to 100, capped at 100 beyond that for performance. Rely on `next` being null to detect the last page."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or null."
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or null."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CaseListItem"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create case",
        "description": "Create a case anchored to exactly one subject (a user or a business), directly or by deriving the subject from an attached session/transaction link. Source is always `MANUAL` for API-created cases.",
        "operationId": "create_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "title"
                ],
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "blueprint": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "CaseBlueprint UUID. Omit for no blueprint."
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "LOW",
                      "MEDIUM",
                      "HIGH"
                    ],
                    "default": "MEDIUM"
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "subject": {
                    "type": "object",
                    "description": "Required unless links is provided; the case's exactly-one subject.",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "user",
                          "business"
                        ]
                      },
                      "uuid": {
                        "type": "string",
                        "format": "uuid"
                      }
                    }
                  },
                  "links": {
                    "type": "array",
                    "description": "Sessions/business sessions/transactions to attach on creation, e.g. [{\"entity_type\": \"transaction\", \"entity_uuid\": \"...\"}]. When subject is omitted, the subject is derived from the first link's owner.",
                    "items": {
                      "type": "object"
                    }
                  },
                  "assigned_to": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "User UUID to assign immediately."
                  },
                  "review_duplicates": {
                    "type": "boolean",
                    "default": false,
                    "description": "Recheck existing investigations before creating the case. When true, a subject with existing cases requires a nonblank separate_incident_reason. The console always enables this protection. Omitting it preserves existing API behavior."
                  },
                  "separate_incident_reason": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "source_context": {
                    "$ref": "#/components/schemas/CaseDuplicateCaseFraudSourceContextRequest"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"title\": \"Manual - Jane Doe\", \"blueprint\": \"b1de0000-0000-4000-8000-000000000002\", \"priority\": \"HIGH\", \"subject\": {\"type\": \"user\", \"uuid\": \"5b9a0000-0000-4000-8000-00000000f00d\"}, \"tags\": [\"review\"]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={\n        'title': 'Manual - Jane Doe',\n        'blueprint': 'b1de0000-0000-4000-8000-000000000002',\n        'priority': 'HIGH',\n        'subject': {'type': 'user', 'uuid': '5b9a0000-0000-4000-8000-00000000f00d'},\n    },\n    timeout=10,\n)\nresp.raise_for_status()\ncase = resp.json()\nprint(case['case_number'], case['uuid'])"
          }
        ],
        "responses": {
          "201": {
            "description": "Case created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          },
          "400": {
            "description": "Neither subject nor links provided, or the subject/blueprint/assignee was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "409": {
            "description": "Duplicate review is enabled and an existing case was found without a separate-incident reason. No case was created."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/": {
      "get": {
        "summary": "Get case",
        "description": "Retrieve a case with its subject, blueprint, notes, events, links, and checklist.",
        "operationId": "get_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Case detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          },
          "404": {
            "description": "Case (or nested resource) not found in this application.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update case",
        "description": "Update the case's title, priority, due date, or tags. Logs PRIORITY_CHANGED/DUE_DATE_CHANGED/TAG_ADDED/TAG_REMOVED events as applicable.",
        "operationId": "update_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 255
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "LOW",
                      "MEDIUM",
                      "HIGH"
                    ]
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"priority\": \"HIGH\", \"due_at\": \"2026-08-01T00:00:00Z\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete case",
        "description": "Delete a case. There is no undelete endpoint.",
        "operationId": "delete_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "204": {
            "description": "Case deleted."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/assign/": {
      "post": {
        "summary": "Assign or unassign case",
        "description": "Assign the case to a user, or unassign it by sending assignee_user_id: null. assignee_email/assignee_name auto-provision a User row when the assignee does not exist yet.",
        "operationId": "assign_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "assignee_user_id"
                ],
                "properties": {
                  "assignee_user_id": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "null to unassign."
                  },
                  "assignee_email": {
                    "type": "string",
                    "format": "email",
                    "nullable": true
                  },
                  "assignee_name": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/assign/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"assignee_user_id\": \"9a000000-0000-4000-8000-0000000000aa\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Case assigned/unassigned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/resolve/": {
      "post": {
        "summary": "Resolve case",
        "description": "Resolve the case as false_positive or valid_threat. Blocked with 400 if the blueprint's checklist is not optional and items remain incomplete, or if the blueprint requires a resolution note and none is given. When the case's blueprint has a four_eyes_checker_blueprint configured, the resolution is staged (case.pending_resolution) and the case moves to the checker blueprint instead of resolving immediately; a different user must call approve or reject-approval.",
        "operationId": "resolve_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "resolution"
                ],
                "properties": {
                  "resolution": {
                    "type": "string",
                    "enum": [
                      "FALSE_POSITIVE",
                      "VALID_THREAT"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "nullable": true,
                    "description": "Required when the blueprint sets require_resolution_note."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/resolve/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"resolution\": \"FALSE_POSITIVE\", \"note\": \"Confirmed legitimate activity after reviewing documents.\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/resolve/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={'resolution': 'FALSE_POSITIVE', 'note': 'Confirmed legitimate activity.'},\n    timeout=10,\n)\nresp.raise_for_status()\ncase = resp.json()\nprint(case['status'], case['resolution'], case.get('pending_resolution'))"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved, or staged for 4-eyes approval.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          },
          "400": {
            "description": "Incomplete checklist items, or a resolution note is required.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/reopen/": {
      "post": {
        "summary": "Reopen case",
        "description": "Move an awaiting-user or resolved case back to open, clearing resolution, resolution_notes, resolved_at, and resolved_by_email.",
        "operationId": "reopen_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/reopen/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Reopen case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/request-info/": {
      "post": {
        "summary": "Request info (awaiting user)",
        "description": "Move an open case to awaiting_user while more information is collected from the verified user. Fails with 400 if a resolution is currently pending 4-eyes approval.",
        "operationId": "request_case_info",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/request-info/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Request info (awaiting user).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/escalate/": {
      "post": {
        "summary": "Escalate case",
        "description": "Move the case to its blueprint's configured escalation_blueprint. Requires the current blueprint to have escalation_enabled and an escalation_blueprint set, otherwise 400.",
        "operationId": "escalate_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/escalate/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Escalate case.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/transfer/": {
      "post": {
        "summary": "Transfer case",
        "description": "Move the case to a different, active blueprint of the same application. Requires the current blueprint to have transfer_enabled, otherwise 400.",
        "operationId": "transfer_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "target_blueprint"
                ],
                "properties": {
                  "target_blueprint": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/transfer/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"target_blueprint\": \"b1de0000-0000-4000-8000-000000000002\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Case transferred.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/approve/": {
      "post": {
        "summary": "Approve staged resolution (4-eyes)",
        "description": "Apply a resolution staged by resolve on a maker blueprint. The caller must be a different user than the one who submitted it, otherwise 403.",
        "operationId": "approve_case_resolution",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/approve/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolution applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          },
          "409": {
            "description": "Case has no resolution pending approval.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The caller is the same user who submitted the resolution (or the case has no recorded maker); a different officer must approve it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/reject-approval/": {
      "post": {
        "summary": "Reject staged resolution (4-eyes)",
        "description": "Reject a resolution staged by resolve and return the case to its maker blueprint. The caller must be a different user than the one who submitted it, otherwise 403.",
        "operationId": "reject_case_resolution",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "notes": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/reject-approval/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"notes\": \"Needs a clearer rationale before this can be approved.\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolution rejected, case returned to the maker blueprint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDetail"
                }
              }
            }
          },
          "409": {
            "description": "Case has no resolution pending approval.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "The caller is the same user who submitted the resolution (or the case has no recorded maker); a different officer must reject it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/entity-actions/": {
      "post": {
        "operationId": "apply_case_entity_action",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CaseActionCaseEntityActionRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseActionCaseEntityActionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CaseActionCaseEntityActionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseActionCaseEntityActionResult"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "The reference belongs to a different action payload."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Apply one explicit action to the case subject. Supply a unique client_reference to obtain an action receipt and make retries idempotent. Reusing that reference with a different payload returns 409. With a reference, inspect receipt.status even when HTTP status is 200: FAILED means no action was applied. Repeating a failed request does not execute it again unless retry is true. Omitting client_reference preserves the legacy response."
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/print/": {
      "get": {
        "summary": "Print case (PDF)",
        "description": "Render the full case (summary, subject, checklist state, notes, attached sessions/transactions, events, FIU report list) as a PDF and return a presigned download URL.",
        "operationId": "print_case",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/print/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned PDF URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/notes/": {
      "get": {
        "operationId": "list_case_notes",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "description": "The initial index from which to return the results.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseCollaborationPaginatedCaseNoteList"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "404": {
            "description": "The case or note is unavailable for this caller."
          }
        },
        "tags": [
          "Case Management"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "post": {
        "operationId": "create_case_note",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CaseCollaborationCaseNoteCreateRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseCollaborationCaseNoteCreateRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CaseCollaborationCaseNoteCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseCollaborationCaseNote"
                }
              }
            },
            "description": ""
          },
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseCollaborationCaseNote"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "404": {
            "description": "The case or note is unavailable for this caller."
          },
          "409": {
            "description": "This client reference was already used for another note or for a note that has been deleted."
          }
        },
        "tags": [
          "Case Management"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Add a case-scoped note. An optional client_reference makes an unchanged retry return the same note without duplicate activity or notifications. reply_to must identify a live note in this case. The response includes a bounded parent excerpt without copying that excerpt into the saved reply."
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/notes/{note_uuid}/": {
      "patch": {
        "operationId": "root_partial_update",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "note_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CaseCollaborationPatchedCaseNoteUpdateRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseCollaborationPatchedCaseNoteUpdateRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CaseCollaborationPatchedCaseNoteUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseCollaborationCaseNote"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "404": {
            "description": "The case or note is unavailable for this caller."
          }
        },
        "tags": [
          "Case Management"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Pin or unpin an existing note. Pinned notes appear first. Pin changes are recorded in case activity and do not change evidence or source decisions."
      },
      "delete": {
        "operationId": "delete_case_note",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "note_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "responses": {
          "204": {
            "description": "The note is permanently deleted. Replies remain, without the deleted parent excerpt. Attachments are deleted unless another note still uses them."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "404": {
            "description": "The case or note is unavailable for this caller."
          }
        },
        "tags": [
          "Case Management"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/notes/presign/": {
      "post": {
        "summary": "Upload note attachment",
        "description": "Upload a file (JPEG, PNG, WebP, PDF, plain text, or CSV; max 5 MB) to attach to a note. Returns the s3_key to pass in the note's attachments array.",
        "operationId": "upload_case_note_attachment",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/notes/presign/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -F 'file=@evidence.pdf'"
          }
        ],
        "responses": {
          "201": {
            "description": "File uploaded.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "s3_key": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "filename": {
                      "type": "string"
                    },
                    "file_size": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No file, unsupported content type, or file exceeds 5 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Get note attachment URL",
        "description": "Mint a fresh presigned download URL for an attachment already stored on one of the case's notes.",
        "operationId": "get_case_note_attachment_url",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          },
          {
            "name": "s3_key",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The attachment's s3_key, as returned by upload or listed on the note.",
            "required": true
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/notes/presign/?s3_key=case-notes/c1a5e000-0000-4000-8000-000000000001/evidence.pdf' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "s3_key": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "filename": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "s3_key missing or does not belong to this case.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/links/": {
      "get": {
        "summary": "List case links",
        "description": "List sessions, business sessions, and transactions attached to the case.",
        "operationId": "list_case_links",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/links/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Case links.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CaseLink"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add case link",
        "description": "Attach a session, business session, or transaction to the case. Rejected with 400 if the entity belongs to a different subject than the case.",
        "operationId": "create_case_link",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "entity_type",
                  "entity_uuid"
                ],
                "properties": {
                  "entity_type": {
                    "type": "string",
                    "enum": [
                      "session",
                      "business_session",
                      "transaction"
                    ]
                  },
                  "entity_uuid": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/links/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"entity_type\": \"transaction\", \"entity_uuid\": \"77000000-0000-4000-8000-000000000077\"}'"
          }
        ],
        "responses": {
          "201": {
            "description": "Link created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseLink"
                }
              }
            }
          },
          "400": {
            "description": "Entity belongs to a different profile than the case subject.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/links/{link_uuid}/": {
      "delete": {
        "summary": "Remove case link",
        "description": "Detach a linked session, business session, or transaction from the case.",
        "operationId": "delete_case_link",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          },
          {
            "name": "link_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11000000-0000-4000-8000-000000000004"
            },
            "description": "Link UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/links/11000000-0000-4000-8000-000000000004/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "204": {
            "description": "Link removed."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/events/": {
      "get": {
        "summary": "List case events",
        "description": "Read-only audit timeline of the case (created, status changes, assignment, resolution, escalation, transfers, tag/priority/due-date changes, entity actions, and more).",
        "operationId": "list_case_events",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/events/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated events, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows. Exact up to 100, capped at 100 beyond that for performance. Rely on `next` being null to detect the last page."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the next page, or null."
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true,
                      "description": "Absolute URL of the previous page, or null."
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CaseEvent"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/checklist/": {
      "get": {
        "summary": "List case checklist",
        "description": "List the case's checklist items, copied from the blueprint's content_config.checklist.items at creation, ordered.",
        "operationId": "list_case_checklist",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/checklist/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Checklist items.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CaseChecklistItem"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/checklist/{item_uuid}/": {
      "patch": {
        "summary": "Toggle checklist item",
        "description": "Mark a checklist item complete or incomplete. Resolution is blocked while any item is incomplete, unless the blueprint marks the checklist optional.",
        "operationId": "toggle_case_checklist_item",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          },
          {
            "name": "item_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c4ec0000-0000-4000-8000-000000000005"
            },
            "description": "Checklist item UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "is_completed"
                ],
                "properties": {
                  "is_completed": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/checklist/c4ec0000-0000-4000-8000-000000000005/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"is_completed\": true}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated checklist item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseChecklistItem"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/aml/": {
      "get": {
        "summary": "List case AML hits",
        "description": "List AML screening hits for the case's subject. Same shape as the hits returned by POST /v3/aml/.",
        "operationId": "list_case_aml_hits",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/aml/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "AML hits.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/statistics/": {
      "get": {
        "summary": "Case analytics",
        "description": "Aggregate case analytics for the date range (defaults to the last 30 days; max 731 days). Charts, tables, totals, assignment events, and current queue counts use the same application-scoped filters. Filters use current case values. Dates apply to each metric event, so older cases assigned or resolved during the period remain included. Queue depth is independent of the date range. Invalid filters return 400; an unknown blueprint or assignee returns an empty result.",
        "operationId": "get_case_analytics",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Range start (inclusive). Defaults to 30 days ago."
          },
          {
            "name": "date_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Range end (inclusive). Defaults to today."
          },
          {
            "name": "blueprint",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by the current blueprint UUID."
          },
          {
            "name": "assigned_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by the current assigned reviewer user UUID."
          },
          {
            "name": "priority",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "LOW",
                "MEDIUM",
                "HIGH"
              ]
            },
            "description": "Filter by current case priority."
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "MANUAL",
                "AML_SCREENING",
                "TRANSACTION_RULE",
                "WORKFLOW_BUILDER"
              ]
            },
            "description": "Filter by case creation source."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "OPEN",
                "AWAITING_USER",
                "RESOLVED"
              ]
            },
            "description": "Filter by current case status."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/statistics/?date_from=2026-06-01&date_to=2026-06-30' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Analytics payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "series": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": {
                            "type": "string",
                            "format": "date"
                          },
                          "created": {
                            "type": "integer"
                          },
                          "reviewed": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "tables": {
                      "type": "object",
                      "properties": {
                        "officer": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "description": "Dimension value: officer email, \"blueprint_name:uuid\", source, or status. \"unassigned\"/\"none\" for missing dimensions."
                              },
                              "created": {
                                "type": "integer"
                              },
                              "assigned": {
                                "type": "integer"
                              },
                              "resolved": {
                                "type": "integer"
                              },
                              "threat_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "false_positive_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "unresolved": {
                                "type": "integer"
                              },
                              "reassignment_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "escalation_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_assign_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_resolve_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_handling_hours": {
                                "type": "number",
                                "format": "float"
                              }
                            }
                          }
                        },
                        "blueprint": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "description": "Dimension value: officer email, \"blueprint_name:uuid\", source, or status. \"unassigned\"/\"none\" for missing dimensions."
                              },
                              "created": {
                                "type": "integer"
                              },
                              "assigned": {
                                "type": "integer"
                              },
                              "resolved": {
                                "type": "integer"
                              },
                              "threat_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "false_positive_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "unresolved": {
                                "type": "integer"
                              },
                              "reassignment_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "escalation_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_assign_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_resolve_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_handling_hours": {
                                "type": "number",
                                "format": "float"
                              }
                            }
                          }
                        },
                        "source": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "description": "Dimension value: officer email, \"blueprint_name:uuid\", source, or status. \"unassigned\"/\"none\" for missing dimensions."
                              },
                              "created": {
                                "type": "integer"
                              },
                              "assigned": {
                                "type": "integer"
                              },
                              "resolved": {
                                "type": "integer"
                              },
                              "threat_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "false_positive_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "unresolved": {
                                "type": "integer"
                              },
                              "reassignment_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "escalation_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_assign_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_resolve_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_handling_hours": {
                                "type": "number",
                                "format": "float"
                              }
                            }
                          }
                        },
                        "status": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "description": "Dimension value: officer email, \"blueprint_name:uuid\", source, or status. \"unassigned\"/\"none\" for missing dimensions."
                              },
                              "created": {
                                "type": "integer"
                              },
                              "assigned": {
                                "type": "integer"
                              },
                              "resolved": {
                                "type": "integer"
                              },
                              "threat_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "false_positive_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "unresolved": {
                                "type": "integer"
                              },
                              "reassignment_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "escalation_rate": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_assign_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_resolve_hours": {
                                "type": "number",
                                "format": "float"
                              },
                              "avg_handling_hours": {
                                "type": "number",
                                "format": "float"
                              }
                            }
                          }
                        }
                      }
                    },
                    "totals": {
                      "type": "object",
                      "properties": {
                        "created": {
                          "type": "integer"
                        },
                        "assigned": {
                          "type": "integer"
                        },
                        "resolved": {
                          "type": "integer"
                        },
                        "threat_rate": {
                          "type": "number",
                          "format": "float"
                        },
                        "false_positive_rate": {
                          "type": "number",
                          "format": "float"
                        },
                        "unresolved": {
                          "type": "integer"
                        },
                        "reassignment_rate": {
                          "type": "number",
                          "format": "float"
                        },
                        "escalation_rate": {
                          "type": "number",
                          "format": "float"
                        },
                        "avg_assign_hours": {
                          "type": "number",
                          "format": "float"
                        },
                        "avg_resolve_hours": {
                          "type": "number",
                          "format": "float"
                        },
                        "avg_handling_hours": {
                          "type": "number",
                          "format": "float"
                        }
                      }
                    },
                    "queue": {
                      "type": "object",
                      "description": "Live snapshot, not scoped to the date range.",
                      "properties": {
                        "open": {
                          "type": "integer"
                        },
                        "overdue": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/bulk/status/": {
      "post": {
        "summary": "Bulk update case status",
        "description": "Apply the same status transition to several cases in one call: OPEN reopens, AWAITING_USER requests info, RESOLVED resolves (resolution required). Each case is evaluated independently; gate failures (incomplete checklist, missing required note) are reported per case without aborting the batch.",
        "operationId": "bulk_update_case_status",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "case_uuids",
                  "status"
                ],
                "properties": {
                  "case_uuids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "OPEN",
                      "AWAITING_USER",
                      "RESOLVED"
                    ]
                  },
                  "resolution": {
                    "type": "string",
                    "enum": [
                      "FALSE_POSITIVE",
                      "VALID_THREAT"
                    ],
                    "description": "Required when status is RESOLVED."
                  },
                  "note": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/bulk/status/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"case_uuids\": [\"c1a5e000-0000-4000-8000-000000000001\"], \"status\": \"RESOLVED\", \"resolution\": \"FALSE_POSITIVE\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-case results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "type": "integer"
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "case_uuid": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "detail": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/bulk/assign/": {
      "post": {
        "summary": "Bulk assign cases",
        "description": "Assign (or unassign, with assignee_user_id: null) several cases at once. All cases must share the same blueprint; mismatches are reported per case without aborting the batch.",
        "operationId": "bulk_assign_cases",
        "tags": [
          "Cases"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "case_uuids",
                  "assignee_user_id"
                ],
                "properties": {
                  "case_uuids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1
                  },
                  "assignee_user_id": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true
                  },
                  "assignee_email": {
                    "type": "string",
                    "format": "email",
                    "nullable": true
                  },
                  "assignee_name": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/bulk/assign/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"case_uuids\": [\"c1a5e000-0000-4000-8000-000000000001\"], \"assignee_user_id\": \"9a000000-0000-4000-8000-0000000000aa\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-case results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "type": "integer"
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "case_uuid": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "detail": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/": {
      "get": {
        "summary": "List blueprints",
        "description": "List case blueprints for the application.",
        "operationId": "list_case_blueprints",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated blueprint list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows, capped at 100 for performance."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CaseBlueprintListItem"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create blueprint",
        "description": "Create a case blueprint: general settings (assignment, escalation, transfer, 4-eyes pairing) plus content_config, the six sections that drive the case page. Set publish=false to create an unpublished draft; Publish creates its first live version. Discarding a never-published draft deletes it.",
        "operationId": "create_case_blueprint",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "assignee_pool"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 24,
                    "description": "Max 24 characters, e.g. \"AML investigation\"."
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "assignee_pool": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "description": "List of User UUIDs. Empty arrays are rejected with \"Pick at least one assignee\"."
                  },
                  "assignment_method": {
                    "type": "string",
                    "enum": [
                      "MANUAL",
                      "AUTOMATIC"
                    ],
                    "default": "MANUAL"
                  },
                  "max_active_cases": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1,
                    "description": "Automatic-mode threshold: \"fewer than N cases of this blueprint assigned\"."
                  },
                  "escalation_enabled": {
                    "type": "boolean",
                    "default": false
                  },
                  "escalation_blueprint": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "Target blueprint UUID. Not enforced at save time, but the escalate action fails with 400 until both escalation_enabled and escalation_blueprint are set."
                  },
                  "transfer_enabled": {
                    "type": "boolean",
                    "default": false
                  },
                  "four_eyes_checker_blueprint": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "Setting this enables 4-eyes review: resolutions on this blueprint stage on the checker blueprint's queue."
                  },
                  "require_resolution_note": {
                    "type": "boolean",
                    "default": false
                  },
                  "content_config": {
                    "$ref": "#/components/schemas/CaseContentConfig"
                  },
                  "is_active": {
                    "type": "boolean",
                    "default": true
                  },
                  "default_deadline_hours": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1,
                    "maximum": 8760,
                    "description": "Default deadline for newly opened cases. Existing case deadlines are unchanged."
                  },
                  "publish": {
                    "type": "boolean",
                    "writeOnly": true,
                    "default": true,
                    "description": "Set false to save a never-published draft. The record remains inactive at version 0 until the draft is explicitly published. Omitting this field preserves immediate creation for existing integrations."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\": \"AML investigation\", \"assignee_pool\": [\"9a000000-0000-4000-8000-0000000000aa\"], \"assignment_method\": \"AUTOMATIC\", \"max_active_cases\": 15, \"require_resolution_note\": true, \"content_config\": {\"aml_control\": {\"enabled\": true, \"financial\": true, \"identity\": false}}}'"
          }
        ],
        "responses": {
          "201": {
            "description": "Blueprint created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseBlueprintDetail"
                }
              }
            }
          },
          "400": {
            "description": "Name over 24 chars, empty assignee_pool, or a cross-referenced blueprint (escalation/checker) not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/{blueprint_uuid}/": {
      "get": {
        "summary": "Get blueprint",
        "description": "Retrieve a blueprint, including its connected creation sources (AML config, transaction rules, workflow nodes) and which blueprints escalate to it.",
        "operationId": "get_case_blueprint",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "blueprint_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "b1de0000-0000-4000-8000-000000000002"
            },
            "description": "Blueprint UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/b1de0000-0000-4000-8000-000000000002/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Blueprint detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseBlueprintDetail"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update blueprint",
        "description": "Partially update a blueprint's general settings or content_config.",
        "operationId": "update_case_blueprint",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "blueprint_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "b1de0000-0000-4000-8000-000000000002"
            },
            "description": "Blueprint UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 24,
                    "description": "Max 24 characters, e.g. \"AML investigation\"."
                  },
                  "description": {
                    "type": "string",
                    "nullable": true
                  },
                  "assignee_pool": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "description": "List of User UUIDs. Empty arrays are rejected with \"Pick at least one assignee\"."
                  },
                  "assignment_method": {
                    "type": "string",
                    "enum": [
                      "MANUAL",
                      "AUTOMATIC"
                    ]
                  },
                  "max_active_cases": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1,
                    "description": "Automatic-mode threshold: \"fewer than N cases of this blueprint assigned\"."
                  },
                  "escalation_enabled": {
                    "type": "boolean"
                  },
                  "escalation_blueprint": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "Target blueprint UUID. Not enforced at save time, but the escalate action fails with 400 until both escalation_enabled and escalation_blueprint are set."
                  },
                  "transfer_enabled": {
                    "type": "boolean"
                  },
                  "four_eyes_checker_blueprint": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "Setting this enables 4-eyes review: resolutions on this blueprint stage on the checker blueprint's queue."
                  },
                  "require_resolution_note": {
                    "type": "boolean"
                  },
                  "content_config": {
                    "$ref": "#/components/schemas/CaseContentConfig"
                  },
                  "is_active": {
                    "type": "boolean"
                  },
                  "default_deadline_hours": {
                    "type": "integer",
                    "nullable": true,
                    "minimum": 1,
                    "maximum": 8760,
                    "description": "Default deadline for newly opened cases. Existing case deadlines are unchanged."
                  },
                  "expected_version": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "The version opened by the editor. A stale version returns 409 without changing the review policy."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/b1de0000-0000-4000-8000-000000000002/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"transfer_enabled\": true}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated blueprint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseBlueprintDetail"
                }
              }
            }
          },
          "409": {
            "description": "The review policy changed since expected_version. Review the latest version before retrying."
          }
        }
      },
      "delete": {
        "summary": "Delete blueprint",
        "description": "Delete a blueprint. Deletion always succeeds and does not touch the blueprint's cases: existing cases keep their blueprint reference and its settings continue to apply to them. A deleted blueprint no longer appears in blueprint lists and can no longer be chosen as a transfer target; if a maker blueprint is deleted while a resolution is pending 4-eyes approval, a rejected resolution leaves the case on the checker blueprint.",
        "operationId": "delete_case_blueprint",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "blueprint_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "b1de0000-0000-4000-8000-000000000002"
            },
            "description": "Blueprint UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/b1de0000-0000-4000-8000-000000000002/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "204": {
            "description": "Blueprint deleted."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/presets/": {
      "get": {
        "summary": "List blueprint presets",
        "description": "List the four built-in presets (Screening hit, AML investigation, Suspicious activity, KYC review) with their content_config and whether each is already installed on this application.",
        "operationId": "list_case_blueprint_presets",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/presets/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Preset catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "preset_key": {
                            "type": "string",
                            "enum": [
                              "screening_hit",
                              "aml_investigation",
                              "suspicious_activity",
                              "kyc"
                            ]
                          },
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "content_config": {
                            "$ref": "#/components/schemas/CaseContentConfig"
                          },
                          "installed": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/presets/install/": {
      "post": {
        "summary": "Install blueprint presets",
        "description": "Copy one or more presets into the application as editable blueprints. Idempotent per preset_key; omit preset_keys to install every preset not yet installed.",
        "operationId": "install_case_blueprint_presets",
        "tags": [
          "Case Blueprints"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "preset_keys": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "nullable": true,
                    "description": "Subset of screening_hit, aml_investigation, suspicious_activity, kyc. Omit to install all."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/blueprints/presets/install/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"preset_keys\": [\"aml_investigation\", \"kyc\"]}'"
          }
        ],
        "responses": {
          "201": {
            "description": "One or more presets installed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "No new presets to install (all requested presets already exist).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/report-templates/": {
      "get": {
        "summary": "List report templates",
        "description": "List FIU report templates for the application.",
        "operationId": "list_report_templates",
        "tags": [
          "Report Templates"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/report-templates/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated templates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows, capped at 100 for performance."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ReportTemplateDetail"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create report template",
        "description": "Create a reusable per-jurisdiction, per-report-type goAML header template. Rejected with 400 if any of the template-level obligatory fields (rentity_id, submission_code, currency_code_local) is missing from field_config; an invalid template cannot be saved or used to create a report. Per-filing header fields (action, submission_date, transactions) are enforced at report validate/finalize time instead.",
        "operationId": "create_report_template",
        "tags": [
          "Report Templates"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "jurisdiction",
                  "report_type"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "jurisdiction": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2,
                    "description": "ISO 3166-1 alpha-2 country code, upper-cased on save."
                  },
                  "report_type": {
                    "type": "string",
                    "enum": [
                      "SAR",
                      "STR",
                      "CTR",
                      "TTR",
                      "UTR",
                      "IFT",
                      "CBR",
                      "TFR"
                    ]
                  },
                  "field_config": {
                    "type": "object",
                    "description": "Reusable goAML header defaults. Template-level obligatory fields: rentity_id, submission_code, and currency_code_local (3-letter). Optional: enabled_fields (which optional report blocks to include) plus reporting_person, location, reason, and action defaults. Per-filing header fields (action, submission_date, transactions, jurisdiction) are enforced when the report is validated or finalized, not on the template."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/report-templates/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\": \"US SAR default\", \"jurisdiction\": \"US\", \"report_type\": \"SAR\", \"field_config\": {\"rentity_id\": \"FIU-US-00123\", \"submission_code\": \"E\", \"currency_code_local\": \"USD\"}}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/report-templates/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={\n        'name': 'US SAR default',\n        'jurisdiction': 'US',\n        'report_type': 'SAR',\n        'field_config': {'rentity_id': 'FIU-US-00123', 'submission_code': 'E', 'currency_code_local': 'USD'},\n    },\n    timeout=10,\n)\nresp.raise_for_status()\nprint(resp.json()['uuid'])"
          }
        ],
        "responses": {
          "201": {
            "description": "Template created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportTemplateDetail"
                }
              }
            }
          },
          "400": {
            "description": "Unrecognized jurisdiction, or field_config fails obligatory-field validation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/report-templates/{template_uuid}/": {
      "get": {
        "summary": "Get report template",
        "description": "Retrieve a report template.",
        "operationId": "get_report_template",
        "tags": [
          "Report Templates"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "template_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "7ec00000-0000-4000-8000-000000000006"
            },
            "description": "Report template UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/report-templates/7ec00000-0000-4000-8000-000000000006/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Template detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportTemplateDetail"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update report template",
        "description": "Partially update a report template. Re-validates obligatory goAML fields on save.",
        "operationId": "update_report_template",
        "tags": [
          "Report Templates"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "template_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "7ec00000-0000-4000-8000-000000000006"
            },
            "description": "Report template UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "jurisdiction": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2,
                    "description": "ISO 3166-1 alpha-2 country code, upper-cased on save."
                  },
                  "report_type": {
                    "type": "string",
                    "enum": [
                      "SAR",
                      "STR",
                      "CTR",
                      "TTR",
                      "UTR",
                      "IFT",
                      "CBR",
                      "TFR"
                    ]
                  },
                  "field_config": {
                    "type": "object",
                    "description": "Reusable goAML header defaults. Template-level obligatory fields: rentity_id, submission_code, and currency_code_local (3-letter). Optional: enabled_fields (which optional report blocks to include) plus reporting_person, location, reason, and action defaults. Per-filing header fields (action, submission_date, transactions, jurisdiction) are enforced when the report is validated or finalized, not on the template."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/report-templates/7ec00000-0000-4000-8000-000000000006/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"field_config\": {\"rentity_id\": \"FIU-US-00124\"}}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportTemplateDetail"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete report template",
        "description": "Delete a report template. Reports already created from it are unaffected.",
        "operationId": "delete_report_template",
        "tags": [
          "Report Templates"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "template_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "7ec00000-0000-4000-8000-000000000006"
            },
            "description": "Report template UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/report-templates/7ec00000-0000-4000-8000-000000000006/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "204": {
            "description": "Template deleted."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/regulatory-reports/": {
      "get": {
        "summary": "List reports for case",
        "description": "List FIU reports generated for the case.",
        "operationId": "list_case_regulatory_reports",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/regulatory-reports/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated reports for the case.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows, capped at 100 for performance."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RegulatoryReportDetail"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create report from case",
        "description": "Create a draft FIU report for the case: DRAFT status, auto-populated from the optional template plus the case's subject, linked transactions, and narrative. Validate then finalize to produce the goAML XML and PDF.",
        "operationId": "create_case_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "case_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "c1a5e000-0000-4000-8000-000000000001"
            },
            "description": "Case UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "report_type": {
                    "type": "string",
                    "enum": [
                      "SAR",
                      "STR",
                      "CTR",
                      "TTR",
                      "UTR",
                      "IFT",
                      "CBR",
                      "TFR"
                    ],
                    "description": "Required unless a template is given; the template's report_type is used otherwise."
                  },
                  "jurisdiction": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2,
                    "description": "Required unless a template is given."
                  },
                  "template": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "Report template UUID; its field_config seeds the draft before case-derived data is merged in."
                  },
                  "transactions": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "nullable": true,
                    "description": "Transactions to attach; defaults to the case's linked transactions."
                  },
                  "rentity_id": {
                    "type": "string",
                    "nullable": true
                  },
                  "rentity_branch": {
                    "type": "string",
                    "nullable": true
                  },
                  "submission_code": {
                    "type": "string",
                    "enum": [
                      "E",
                      "M"
                    ],
                    "default": "E"
                  },
                  "entity_reference": {
                    "type": "string",
                    "nullable": true
                  },
                  "fiu_ref_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "currency_code_local": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 3,
                    "nullable": true
                  },
                  "submission_date": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "reporting_person": {
                    "type": "object"
                  },
                  "location": {
                    "type": "object"
                  },
                  "reason": {
                    "type": "string",
                    "nullable": true
                  },
                  "action": {
                    "type": "string",
                    "nullable": true
                  },
                  "activity": {
                    "type": "string",
                    "nullable": true
                  },
                  "narrative": {
                    "type": "object",
                    "properties": {
                      "who": {
                        "type": "string"
                      },
                      "what": {
                        "type": "string"
                      },
                      "when": {
                        "type": "string"
                      },
                      "where": {
                        "type": "string"
                      },
                      "why": {
                        "type": "string"
                      },
                      "how": {
                        "type": "string"
                      }
                    }
                  },
                  "report_indicators": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "included_fields": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/cases/c1a5e000-0000-4000-8000-000000000001/regulatory-reports/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"template\": \"7ec00000-0000-4000-8000-000000000006\"}'"
          }
        ],
        "responses": {
          "201": {
            "description": "Draft report created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryReportDetail"
                }
              }
            }
          },
          "400": {
            "description": "The referenced template was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/regulatory-reports/": {
      "get": {
        "summary": "List reports",
        "description": "Application-wide FIU report list, optionally filtered by status, report_type, or case.",
        "operationId": "list_regulatory_reports",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1
            },
            "description": "Page size."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "DRAFT",
                "VALIDATED",
                "FINALIZED"
              ]
            },
            "description": "Filter by status."
          },
          {
            "name": "report_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "SAR",
                "STR",
                "CTR",
                "TTR",
                "UTR",
                "IFT",
                "CBR",
                "TFR"
              ]
            },
            "description": "Filter by report type."
          },
          {
            "name": "case",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to reports on this case."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated reports across the application.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of matching rows, capped at 100 for performance."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RegulatoryReportDetail"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create standalone report",
        "description": "Create a draft FIU report from the standalone Reports page: both case and template are required (unlike the case-scoped create, which can omit template).",
        "operationId": "create_standalone_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "case",
                  "template"
                ],
                "properties": {
                  "case": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "template": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "report_type": {
                    "type": "string",
                    "enum": [
                      "SAR",
                      "STR",
                      "CTR",
                      "TTR",
                      "UTR",
                      "IFT",
                      "CBR",
                      "TFR"
                    ],
                    "description": "Required unless a template is given; the template's report_type is used otherwise."
                  },
                  "jurisdiction": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2,
                    "description": "Required unless a template is given."
                  },
                  "transactions": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "nullable": true,
                    "description": "Transactions to attach; defaults to the case's linked transactions."
                  },
                  "rentity_id": {
                    "type": "string",
                    "nullable": true
                  },
                  "rentity_branch": {
                    "type": "string",
                    "nullable": true
                  },
                  "submission_code": {
                    "type": "string",
                    "enum": [
                      "E",
                      "M"
                    ],
                    "default": "E"
                  },
                  "entity_reference": {
                    "type": "string",
                    "nullable": true
                  },
                  "fiu_ref_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "currency_code_local": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 3,
                    "nullable": true
                  },
                  "submission_date": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "reporting_person": {
                    "type": "object"
                  },
                  "location": {
                    "type": "object"
                  },
                  "reason": {
                    "type": "string",
                    "nullable": true
                  },
                  "action": {
                    "type": "string",
                    "nullable": true
                  },
                  "activity": {
                    "type": "string",
                    "nullable": true
                  },
                  "narrative": {
                    "type": "object",
                    "properties": {
                      "who": {
                        "type": "string"
                      },
                      "what": {
                        "type": "string"
                      },
                      "when": {
                        "type": "string"
                      },
                      "where": {
                        "type": "string"
                      },
                      "why": {
                        "type": "string"
                      },
                      "how": {
                        "type": "string"
                      }
                    }
                  },
                  "report_indicators": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "included_fields": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"case\": \"c1a5e000-0000-4000-8000-000000000001\", \"template\": \"7ec00000-0000-4000-8000-000000000006\"}'"
          }
        ],
        "responses": {
          "201": {
            "description": "Draft report created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryReportDetail"
                }
              }
            }
          },
          "400": {
            "description": "The referenced template was not found.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/regulatory-reports/{report_uuid}/": {
      "get": {
        "summary": "Get report",
        "description": "Retrieve a regulatory report.",
        "operationId": "get_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "report_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "5ec00000-0000-4000-8000-000000000007"
            },
            "description": "Report UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Report detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryReportDetail"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update report",
        "description": "Edit a draft or validated report's fields. Finalized reports cannot be edited (409).",
        "operationId": "update_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "report_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "5ec00000-0000-4000-8000-000000000007"
            },
            "description": "Report UUID."
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "jurisdiction": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2
                  },
                  "rentity_id": {
                    "type": "string",
                    "nullable": true
                  },
                  "rentity_branch": {
                    "type": "string",
                    "nullable": true
                  },
                  "submission_code": {
                    "type": "string",
                    "enum": [
                      "E",
                      "M"
                    ],
                    "default": "E"
                  },
                  "entity_reference": {
                    "type": "string",
                    "nullable": true
                  },
                  "fiu_ref_number": {
                    "type": "string",
                    "nullable": true
                  },
                  "currency_code_local": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 3,
                    "nullable": true
                  },
                  "submission_date": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "reporting_person": {
                    "type": "object"
                  },
                  "location": {
                    "type": "object"
                  },
                  "reason": {
                    "type": "string",
                    "nullable": true
                  },
                  "action": {
                    "type": "string",
                    "nullable": true
                  },
                  "activity": {
                    "type": "string",
                    "nullable": true
                  },
                  "narrative": {
                    "type": "object",
                    "properties": {
                      "who": {
                        "type": "string"
                      },
                      "what": {
                        "type": "string"
                      },
                      "when": {
                        "type": "string"
                      },
                      "where": {
                        "type": "string"
                      },
                      "why": {
                        "type": "string"
                      },
                      "how": {
                        "type": "string"
                      }
                    }
                  },
                  "report_indicators": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "included_fields": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"rentity_id\": \"FIU-US-00123\", \"currency_code_local\": \"USD\"}'"
          }
        ],
        "responses": {
          "200": {
            "description": "Updated report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryReportDetail"
                }
              }
            }
          },
          "409": {
            "description": "Report is already finalized.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete report",
        "description": "Delete a draft or validated report. Finalized reports cannot be deleted (409).",
        "operationId": "delete_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "report_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "5ec00000-0000-4000-8000-000000000007"
            },
            "description": "Report UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "204": {
            "description": "Report deleted."
          },
          "409": {
            "description": "Report is already finalized.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/regulatory-reports/{report_uuid}/validate/": {
      "post": {
        "summary": "Validate report",
        "description": "Check the report against the obligatory goAML header fields (reporting entity ID, submission code, local currency, action taken, submission date), plus at least one attached transaction and a 2-letter jurisdiction, without generating any files. Also stores the result on the report: validation_errors and validated_at are updated, and a non-finalized report's status moves to VALIDATED (no errors) or back to DRAFT (errors).",
        "operationId": "validate_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "report_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "5ec00000-0000-4000-8000-000000000007"
            },
            "description": "Report UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/validate/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Validation result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "DRAFT",
                        "VALIDATED",
                        "FINALIZED"
                      ]
                    },
                    "is_valid": {
                      "type": "boolean"
                    },
                    "errors": {
                      "type": "array",
                      "description": "Empty when valid.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "field": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/regulatory-reports/{report_uuid}/finalize/": {
      "post": {
        "summary": "Finalize report",
        "description": "Re-validate, then render the goAML XML and PDF and upload both to S3. On SAR/STR/TFR reports, this also moves the case's transaction alerts from Pending SAR to SAR filed.",
        "operationId": "finalize_regulatory_report",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "report_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "5ec00000-0000-4000-8000-000000000007"
            },
            "description": "Report UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/finalize/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/finalize/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    timeout=30,\n)\nif resp.status_code == 400:\n    print('Validation failed:', resp.json()['errors'])\nelse:\n    resp.raise_for_status()\n    report = resp.json()\n    print(report['status'], report['report_number'])"
          }
        ],
        "responses": {
          "200": {
            "description": "Report finalized; xml_s3_key and pdf_s3_key are set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryReportDetail"
                }
              }
            }
          },
          "400": {
            "description": "Report failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "field": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Report is not in a finalizable state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/regulatory-reports/{report_uuid}/download-url/": {
      "get": {
        "summary": "Get report download URL",
        "description": "Mint a presigned URL for a finalized report's goAML XML or PDF.",
        "operationId": "get_regulatory_report_download_url",
        "tags": [
          "Regulatory Reports"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "report_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "5ec00000-0000-4000-8000-000000000007"
            },
            "description": "Report UUID."
          },
          {
            "name": "file",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pdf",
                "xml"
              ],
              "default": "pdf"
            },
            "description": "Which file to download."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/regulatory-reports/5ec00000-0000-4000-8000-000000000007/download-url/?file=xml' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "download_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "file": {
                      "type": "string",
                      "enum": [
                        "pdf",
                        "xml"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Report is not finalized yet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/transactions/rules/": {
      "get": {
        "summary": "List rules",
        "description": "List the application's transaction-monitoring rules: your custom rules plus any library presets you have installed. Filter by source, category, mode, bundle or free-text search; order with `ordering` (run_count, approved_pct, reviewed_pct, declined_pct, latest_triggered_at, title, created_at, source, each with an optional `-` prefix).",
        "operationId": "listTransactionRules",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "PRESET",
                "CUSTOM"
              ]
            },
            "description": "PRESET or CUSTOM"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by rule category"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ACTIVE",
                "DISABLED",
                "TEST"
              ]
            },
            "description": "ACTIVE, DISABLED or TEST"
          },
          {
            "name": "bundle",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter presets by bundle"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive match against title and description"
          },
          {
            "name": "ordering",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated ordering fields, default source,-run_count"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page size"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated rules.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TransactionRuleDetail"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/transactions/rules/?source=CUSTOM&ordering=-run_count' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      },
      "post": {
        "summary": "Create rule",
        "description": "Create a CUSTOM transaction-monitoring rule. Titles are unique per application (duplicate -> 400). A `change_status` action targeting `AWAITING_USER` must carry `workflow_id`. Rules created in ACTIVE mode apply to new transactions immediately - the recommended workflow is create in TEST mode, backtest, then switch mode to ACTIVE.",
        "operationId": "createTransactionRule",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleCreateRequest"
              },
              "example": {
                "title": "Structuring - inbound (custom)",
                "description": "20+ inbound EUR transfers, all under 10,000 EUR, 30 days",
                "category": "finance",
                "mode": "TEST",
                "evaluation_mode": "ALL",
                "scope": {
                  "transaction_types": [
                    "finance"
                  ],
                  "directions": [
                    "INBOUND"
                  ]
                },
                "conditions": [
                  {
                    "field": "currency",
                    "operator": "eq",
                    "value": "EUR"
                  },
                  {
                    "field": "amount",
                    "operator": "lt",
                    "value": 10000
                  }
                ],
                "aggregation": [
                  {
                    "metric": "count",
                    "operator": "gte",
                    "value": 20,
                    "window": "30d",
                    "filters": {
                      "direction": "INBOUND",
                      "transaction_type": "finance",
                      "subject_vendor_data": "__current__",
                      "currency": "EUR"
                    }
                  },
                  {
                    "metric": "max",
                    "field": "amount",
                    "operator": "lt",
                    "value": 10000,
                    "window": "30d",
                    "filters": {
                      "direction": "INBOUND",
                      "transaction_type": "finance",
                      "subject_vendor_data": "__current__",
                      "currency": "EUR"
                    }
                  }
                ],
                "actions": [
                  {
                    "type": "add_score",
                    "value": 35
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleDetail"
                }
              }
            }
          },
          "400": {
            "description": "Validation error - duplicate title, unknown operator/metric, malformed window, invalid scope direction, or AWAITING_USER without workflow_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "title": [
                    "A rule with this name already exists."
                  ]
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/transactions/rules/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"title\": \"Structuring - inbound (custom)\", \"description\": \"20+ inbound EUR transfers, all under 10,000 EUR, 30 days\", \"category\": \"finance\", \"mode\": \"TEST\", \"evaluation_mode\": \"ALL\", \"scope\": {\"transaction_types\": [\"finance\"], \"directions\": [\"INBOUND\"]}, \"conditions\": [{\"field\": \"currency\", \"operator\": \"eq\", \"value\": \"EUR\"}, {\"field\": \"amount\", \"operator\": \"lt\", \"value\": 10000}], \"aggregation\": [{\"metric\": \"count\", \"operator\": \"gte\", \"value\": 20, \"window\": \"30d\", \"filters\": {\"direction\": \"INBOUND\", \"transaction_type\": \"finance\", \"subject_vendor_data\": \"__current__\", \"currency\": \"EUR\"}}, {\"metric\": \"max\", \"field\": \"amount\", \"operator\": \"lt\", \"value\": 10000, \"window\": \"30d\", \"filters\": {\"direction\": \"INBOUND\", \"transaction_type\": \"finance\", \"subject_vendor_data\": \"__current__\", \"currency\": \"EUR\"}}], \"actions\": [{\"type\": \"add_score\", \"value\": 35}]}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nrule = {\n  \"title\": \"Structuring - inbound (custom)\",\n  \"description\": \"20+ inbound EUR transfers, all under 10,000 EUR, 30 days\",\n  \"category\": \"finance\",\n  \"mode\": \"TEST\",\n  \"evaluation_mode\": \"ALL\",\n  \"scope\": {\n    \"transaction_types\": [\n      \"finance\"\n    ],\n    \"directions\": [\n      \"INBOUND\"\n    ]\n  },\n  \"conditions\": [\n    {\n      \"field\": \"currency\",\n      \"operator\": \"eq\",\n      \"value\": \"EUR\"\n    },\n    {\n      \"field\": \"amount\",\n      \"operator\": \"lt\",\n      \"value\": 10000\n    }\n  ],\n  \"aggregation\": [\n    {\n      \"metric\": \"count\",\n      \"operator\": \"gte\",\n      \"value\": 20,\n      \"window\": \"30d\",\n      \"filters\": {\n        \"direction\": \"INBOUND\",\n        \"transaction_type\": \"finance\",\n        \"subject_vendor_data\": \"__current__\",\n        \"currency\": \"EUR\"\n      }\n    },\n    {\n      \"metric\": \"max\",\n      \"field\": \"amount\",\n      \"operator\": \"lt\",\n      \"value\": 10000,\n      \"window\": \"30d\",\n      \"filters\": {\n        \"direction\": \"INBOUND\",\n        \"transaction_type\": \"finance\",\n        \"subject_vendor_data\": \"__current__\",\n        \"currency\": \"EUR\"\n      }\n    }\n  ],\n  \"actions\": [\n    {\n      \"type\": \"add_score\",\n      \"value\": 35\n    }\n  ]\n}\n\nresp = requests.post(\n    'https://verification.didit.me/v3/transactions/rules/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json=rule,\n    timeout=15,\n)\nresp.raise_for_status()\nprint(resp.json()['uuid'], resp.json()['mode'])"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const rule = {\n  \"title\": \"Structuring - inbound (custom)\",\n  \"description\": \"20+ inbound EUR transfers, all under 10,000 EUR, 30 days\",\n  \"category\": \"finance\",\n  \"mode\": \"TEST\",\n  \"evaluation_mode\": \"ALL\",\n  \"scope\": {\n    \"transaction_types\": [\n      \"finance\"\n    ],\n    \"directions\": [\n      \"INBOUND\"\n    ]\n  },\n  \"conditions\": [\n    {\n      \"field\": \"currency\",\n      \"operator\": \"eq\",\n      \"value\": \"EUR\"\n    },\n    {\n      \"field\": \"amount\",\n      \"operator\": \"lt\",\n      \"value\": 10000\n    }\n  ],\n  \"aggregation\": [\n    {\n      \"metric\": \"count\",\n      \"operator\": \"gte\",\n      \"value\": 20,\n      \"window\": \"30d\",\n      \"filters\": {\n        \"direction\": \"INBOUND\",\n        \"transaction_type\": \"finance\",\n        \"subject_vendor_data\": \"__current__\",\n        \"currency\": \"EUR\"\n      }\n    },\n    {\n      \"metric\": \"max\",\n      \"field\": \"amount\",\n      \"operator\": \"lt\",\n      \"value\": 10000,\n      \"window\": \"30d\",\n      \"filters\": {\n        \"direction\": \"INBOUND\",\n        \"transaction_type\": \"finance\",\n        \"subject_vendor_data\": \"__current__\",\n        \"currency\": \"EUR\"\n      }\n    }\n  ],\n  \"actions\": [\n    {\n      \"type\": \"add_score\",\n      \"value\": 35\n    }\n  ]\n};\n\nconst resp = await fetch('https://verification.didit.me/v3/transactions/rules/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.DIDIT_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify(rule),\n});\nif (!resp.ok) throw new Error(await resp.text());\nconst created = await resp.json();\nconsole.log(created.uuid, created.mode);"
          }
        ]
      }
    },
    "/v3/transactions/rules/{rule_uuid}/": {
      "parameters": [
        {
          "name": "rule_uuid",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "The rule's uuid from list or create."
        }
      ],
      "get": {
        "summary": "Get rule",
        "description": "Retrieve one rule with its full configuration and execution counters.",
        "operationId": "getTransactionRule",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleDetail"
                }
              }
            }
          },
          "404": {
            "description": "No such rule on this application.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/transactions/rules/RULE_UUID/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      },
      "patch": {
        "summary": "Update rule",
        "description": "Partially update a rule. Custom rules accept every configuration field. Library (PRESET) rules accept only `mode` - use it to activate, disable, or switch a preset to TEST; any other field returns 400.",
        "operationId": "updateTransactionRule",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleUpdateRequest"
              },
              "example": {
                "mode": "ACTIVE"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleDetail"
                }
              }
            }
          },
          "400": {
            "description": "Validation error, or a non-mode field on a library rule.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X PATCH 'https://verification.didit.me/v3/transactions/rules/RULE_UUID/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"mode\": \"ACTIVE\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.patch(\n    'https://verification.didit.me/v3/transactions/rules/RULE_UUID/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={'mode': 'ACTIVE'},\n    timeout=15,\n)\nresp.raise_for_status()\nprint(resp.json()['mode'])"
          }
        ]
      },
      "delete": {
        "summary": "Delete rule",
        "description": "Delete a CUSTOM rule. Deletion is immediate and permanent: the rule stops evaluating for new transactions and disappears from listings, while past rule runs on already-evaluated transactions keep their recorded results. Library rules cannot be deleted - uninstall them via the install endpoint instead (they can always be reinstalled from the library).",
        "operationId": "deleteTransactionRule",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "400": {
            "description": "The rule is a library preset - uninstall instead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "detail": "Library rules cannot be deleted. Uninstall them via the rules install endpoint instead."
                }
              }
            }
          },
          "404": {
            "description": "No such rule on this application.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/transactions/rules/RULE_UUID/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      }
    },
    "/v3/transactions/rules/backtest/": {
      "post": {
        "summary": "Backtest rule configuration",
        "description": "Evaluate a hypothetical rule configuration against your recent transactions (most recent first, up to the backtest cap) without creating a rule or touching any transaction. Use it before activating a rule to see how often it would have matched and how many subjects it would have affected.",
        "operationId": "backtestTransactionRules",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleBacktestRequest"
              },
              "example": {
                "conditions": [
                  {
                    "field": "currency",
                    "operator": "eq",
                    "value": "EUR"
                  },
                  {
                    "field": "amount",
                    "operator": "lt",
                    "value": 10000
                  }
                ],
                "aggregation": [
                  {
                    "metric": "count",
                    "operator": "gte",
                    "value": 20,
                    "window": "30d",
                    "filters": {
                      "direction": "INBOUND",
                      "transaction_type": "finance",
                      "subject_vendor_data": "__current__",
                      "currency": "EUR"
                    }
                  },
                  {
                    "metric": "max",
                    "field": "amount",
                    "operator": "lt",
                    "value": 10000,
                    "window": "30d",
                    "filters": {
                      "direction": "INBOUND",
                      "transaction_type": "finance",
                      "subject_vendor_data": "__current__",
                      "currency": "EUR"
                    }
                  }
                ],
                "evaluation_mode": "ALL",
                "scope": {
                  "transaction_types": [
                    "finance"
                  ],
                  "directions": [
                    "INBOUND"
                  ]
                },
                "period_days": 90
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Backtest statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleBacktestResult"
                },
                "example": {
                  "evaluated": 4820,
                  "matched": 12,
                  "affected_entities": 4,
                  "period_days": 90
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/transactions/rules/backtest/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"conditions\": [{\"field\": \"currency\", \"operator\": \"eq\", \"value\": \"EUR\"}, {\"field\": \"amount\", \"operator\": \"lt\", \"value\": 10000}], \"aggregation\": [{\"metric\": \"count\", \"operator\": \"gte\", \"value\": 20, \"window\": \"30d\", \"filters\": {\"direction\": \"INBOUND\", \"transaction_type\": \"finance\", \"subject_vendor_data\": \"__current__\", \"currency\": \"EUR\"}}, {\"metric\": \"max\", \"field\": \"amount\", \"operator\": \"lt\", \"value\": 10000, \"window\": \"30d\", \"filters\": {\"direction\": \"INBOUND\", \"transaction_type\": \"finance\", \"subject_vendor_data\": \"__current__\", \"currency\": \"EUR\"}}], \"evaluation_mode\": \"ALL\", \"scope\": {\"transaction_types\": [\"finance\"], \"directions\": [\"INBOUND\"]}, \"period_days\": 90}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\n\nimport requests\n\nresp = requests.post(\n    'https://verification.didit.me/v3/transactions/rules/backtest/',\n    headers={'x-api-key': os.environ['DIDIT_API_KEY']},\n    json={\n    \"conditions\": [\n        {\n            \"field\": \"currency\",\n            \"operator\": \"eq\",\n            \"value\": \"EUR\"\n        },\n        {\n            \"field\": \"amount\",\n            \"operator\": \"lt\",\n            \"value\": 10000\n        }\n    ],\n    \"aggregation\": [\n        {\n            \"metric\": \"count\",\n            \"operator\": \"gte\",\n            \"value\": 20,\n            \"window\": \"30d\",\n            \"filters\": {\n                \"direction\": \"INBOUND\",\n                \"transaction_type\": \"finance\",\n                \"subject_vendor_data\": \"__current__\",\n                \"currency\": \"EUR\"\n            }\n        },\n        {\n            \"metric\": \"max\",\n            \"field\": \"amount\",\n            \"operator\": \"lt\",\n            \"value\": 10000,\n            \"window\": \"30d\",\n            \"filters\": {\n                \"direction\": \"INBOUND\",\n                \"transaction_type\": \"finance\",\n                \"subject_vendor_data\": \"__current__\",\n                \"currency\": \"EUR\"\n            }\n        }\n    ],\n    \"evaluation_mode\": \"ALL\",\n    \"scope\": {\n        \"transaction_types\": [\n            \"finance\"\n        ],\n        \"directions\": [\n            \"INBOUND\"\n        ]\n    },\n    \"period_days\": 90\n},\n    timeout=30,\n)\nresp.raise_for_status()\nstats = resp.json()\nprint(stats['matched'], 'matches across', stats['affected_entities'], 'subjects')"
          }
        ]
      }
    },
    "/v3/transactions/rules/library/": {
      "get": {
        "summary": "List rule library",
        "description": "Browse the full preset rule library (150+ rules) with each entry's complete configuration and an `is_installed` flag for this application. Filter by bundle, category, or free-text search.",
        "operationId": "listTransactionRuleLibrary",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bundle",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by bundle, e.g. finance, aml_ctf, crypto_monitoring, travel_rule"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by category"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive match against title and description"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page size"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated library entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TransactionRuleLibraryEntry"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/transactions/rules/library/?bundle=finance' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      }
    },
    "/v3/transactions/rules/install/": {
      "post": {
        "summary": "Install library rules",
        "description": "Install one or more presets onto the application, by `library_keys` or a whole `bundle`. Installed presets evaluate immediately in their default mode; already-installed keys are skipped.",
        "operationId": "installTransactionRuleLibrary",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleInstallRequest"
              },
              "example": {
                "library_keys": [
                  "structuring-inbound",
                  "structuring-outbound"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What was installed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleInstallResult"
                },
                "example": {
                  "installed_library_keys": [
                    "structuring-inbound",
                    "structuring-outbound"
                  ],
                  "installed_count": 2
                }
              }
            }
          },
          "400": {
            "description": "Neither library_keys nor bundle provided.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST 'https://verification.didit.me/v3/transactions/rules/install/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"library_keys\": [\"structuring-inbound\", \"structuring-outbound\"]}'"
          }
        ]
      },
      "delete": {
        "summary": "Uninstall library rules",
        "description": "Remove installed presets from the application, by `library_keys` or a whole `bundle`. Uninstalled presets stop evaluating immediately and can be reinstalled from the library at any time.",
        "operationId": "uninstallTransactionRuleLibrary",
        "tags": [
          "Transactions"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionRuleInstallRequest"
              },
              "example": {
                "bundle": "responsible_gaming"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "How many presets were removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionRuleInstallResult"
                },
                "example": {
                  "uninstalled_count": 5
                }
              }
            }
          },
          "400": {
            "description": "Neither library_keys nor bundle provided.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE 'https://verification.didit.me/v3/transactions/rules/install/' \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"bundle\": \"responsible_gaming\"}'"
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/": {
      "get": {
        "summary": "List networks",
        "description": "List fraud networks detected within this application's organization, newest activity first by default. By default dismissed networks are excluded; pass status to include them. Sandbox applications never have networks - clustering excludes sandbox data entirely.",
        "operationId": "list_networks",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated statuses to include: active,in_review,resolved,dismissed. Omit to exclude dismissed."
          },
          {
            "name": "signal_type",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated signal types: ip_address,device,face,document_number,phone,email,address."
          },
          {
            "name": "pattern_type",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated pattern types, e.g. exact_same_device,same_email."
          },
          {
            "name": "risk_band",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated bands: low,medium,high."
          },
          {
            "name": "min_size",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Minimum member count."
          },
          {
            "name": "max_size",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Maximum member count."
          },
          {
            "name": "date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Lower bound on last_activity_at (ISO 8601 date or datetime)."
          },
          {
            "name": "date_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Upper bound on first_activity_at (ISO 8601 date or datetime)."
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Free-text search across network name, member names, the network_id (N-0001), and exact pattern_type tokens."
          },
          {
            "name": "ordering",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "One of risk_score, -risk_score, last_activity_at, -last_activity_at, first_activity_at, -first_activity_at, network_number, -network_number. Defaults to -risk_score,-last_activity_at."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "minimum": 1,
              "maximum": 500
            },
            "description": "Page size, 1-500. Defaults to 100."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Zero-based offset of the first record."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/?status=active,in_review&ordering=-risk_score' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated network list with console KPIs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "integer",
                      "nullable": true,
                      "description": "Offset of the next page, or null on the last page."
                    },
                    "previous": {
                      "type": "integer",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NetworkListItem"
                      }
                    },
                    "kpis": {
                      "type": "object",
                      "description": "Each key is {value, delta} over the results matching the current filters.",
                      "properties": {
                        "active": {
                          "type": "object"
                        },
                        "in_review": {
                          "type": "object"
                        },
                        "applicants_involved": {
                          "type": "object"
                        },
                        "detected_this_period": {
                          "type": "object"
                        },
                        "false_positive_rate": {
                          "type": "object"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/": {
      "get": {
        "summary": "Get network",
        "description": "Retrieve a single network's full detail, including stats, fraud tags, and risk signals.",
        "operationId": "get_network",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "n3a5e000-0000-4000-8000-000000000001"
            },
            "description": "Network UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/n3a5e000-0000-4000-8000-000000000001/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Network detail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkDetail"
                }
              }
            }
          },
          "404": {
            "description": "Network not found (or not visible to this application).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/graph/": {
      "get": {
        "summary": "Get network graph",
        "description": "Retrieve the network as a graph of subject nodes (vendor users, vendor businesses, transaction parties) and signal nodes (the shared device/IP/face/document/phone/email/address values linking them), with edges representing memberships.",
        "operationId": "get_network_graph",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "n3a5e000-0000-4000-8000-000000000001"
            },
            "description": "Network UUID."
          },
          {
            "name": "depth",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "2",
                "3",
                "all"
              ]
            },
            "description": "Hops from the focus subject to include. Defaults to all (unbounded)."
          },
          {
            "name": "focus_kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "vendor_user",
                "vendor_business",
                "transaction_party"
              ]
            },
            "description": "Subject type to center the graph on. Must be supplied together with focus_id; defaults to an arbitrary member when depth is bounded and neither is supplied."
          },
          {
            "name": "focus_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Subject UUID to center the graph on."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/n3a5e000-0000-4000-8000-000000000001/graph/?depth=2' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Network graph.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkGraph"
                }
              }
            }
          },
          "404": {
            "description": "Network not found (or not visible to this application).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/members/": {
      "get": {
        "summary": "List network members",
        "description": "List the subjects (vendor users, vendor businesses, or transaction parties) that belong to this network.",
        "operationId": "list_network_members",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "n3a5e000-0000-4000-8000-000000000001"
            },
            "description": "Network UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/n3a5e000-0000-4000-8000-000000000001/members/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Network members. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NetworkMember"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Network not found (or not visible to this application).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/signals/": {
      "get": {
        "summary": "List network signals",
        "description": "List the signals (shared device, IP, face, document number, phone, email, or address values) that link this network's members.",
        "operationId": "list_network_signals",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "n3a5e000-0000-4000-8000-000000000001"
            },
            "description": "Network UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/n3a5e000-0000-4000-8000-000000000001/signals/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Network signals. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NetworkSignal"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Network not found (or not visible to this application).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/timeline/": {
      "get": {
        "summary": "Get network timeline",
        "description": "Chronological events for this network: detection, each signal's observation, and lifecycle status changes.",
        "operationId": "get_network_timeline",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "n3a5e000-0000-4000-8000-000000000001"
            },
            "description": "Network UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/n3a5e000-0000-4000-8000-000000000001/timeline/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Timeline events, oldest first. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NetworkTimelineEvent"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Network not found (or not visible to this application).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/map/": {
      "get": {
        "summary": "Get network map",
        "description": "Geographic points where this network's members' addresses/locations converge, sourced from the sessions, business sessions, and transactions backing its memberships.",
        "operationId": "get_network_map",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "n3a5e000-0000-4000-8000-000000000001"
            },
            "description": "Network UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/networks/n3a5e000-0000-4000-8000-000000000001/map/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Network map.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkMap"
                }
              }
            }
          },
          "404": {
            "description": "Network not found (or not visible to this application).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/sessions/{session_id}/networks/": {
      "get": {
        "summary": "List networks for a session",
        "description": "List the networks the session's vendor user belongs to. Resolves through the session's vendor_data-linked user.",
        "operationId": "list_session_network_memberships",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Session UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/sessions/aaaaaaaa-0000-4000-8000-000000000001/networks/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Networks this entity belongs to. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntityNetworkMembership"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Entity not found in this application, or has no linked subject to look up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/business-sessions/{business_session_id}/networks/": {
      "get": {
        "summary": "List networks for a business session",
        "description": "List the networks the business session's vendor business belongs to.",
        "operationId": "list_business_session_network_memberships",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "business_session_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Business session UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/business-sessions/aaaaaaaa-0000-4000-8000-000000000002/networks/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Networks this entity belongs to. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntityNetworkMembership"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Entity not found in this application, or has no linked subject to look up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/users/{vendor_user_uuid}/networks/": {
      "get": {
        "summary": "List networks for a user",
        "description": "List the networks a vendor user belongs to.",
        "operationId": "list_user_network_memberships",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "vendor_user_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Vendor user UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/users/aaaaaaaa-0000-4000-8000-000000000003/networks/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Networks this entity belongs to. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntityNetworkMembership"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Entity not found in this application, or has no linked subject to look up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/businesses/{vendor_business_uuid}/networks/": {
      "get": {
        "summary": "List networks for a business",
        "description": "List the networks a vendor business belongs to.",
        "operationId": "list_business_network_memberships",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "vendor_business_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Vendor business UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/businesses/aaaaaaaa-0000-4000-8000-000000000004/networks/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Networks this entity belongs to. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntityNetworkMembership"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Entity not found in this application, or has no linked subject to look up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/transactions/{transaction_uuid}/networks/": {
      "get": {
        "summary": "List networks for a transaction",
        "description": "List the networks the transaction's backing KYC/KYB subject belongs to (resolved through the transaction's session or business session).",
        "operationId": "list_transaction_network_memberships",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "transaction_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Transaction UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/transactions/aaaaaaaa-0000-4000-8000-000000000005/networks/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Networks this entity belongs to. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntityNetworkMembership"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Entity not found in this application, or has no linked subject to look up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/transactions/{transaction_uuid}/parties/{transaction_party_uuid}/networks/": {
      "get": {
        "summary": "List networks for a transaction party",
        "description": "List the networks a transaction party (remitter, beneficiary, or counterparty) belongs to, resolved through the party itself rather than through the transaction's backing session.",
        "operationId": "list_transaction_party_network_memberships",
        "tags": [
          "Networks"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "transaction_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Transaction UUID."
          },
          {
            "name": "transaction_party_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Transaction party UUID."
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/transactions/aaaaaaaa-0000-4000-8000-000000000005/parties/bbbbbbbb-0000-4000-8000-000000000006/networks/' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ],
        "responses": {
          "200": {
            "description": "Networks this entity belongs to. Not paginated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EntityNetworkMembership"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Entity not found in this application, or has no linked subject to look up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/biometric-templates/": {
      "get": {
        "summary": "List retained biometric templates",
        "description": "An opted-in application keeps one separately managed, image-free face biometric template anchored to the User when a session is deleted (see `DELETE /v3/session/{sessionId}/delete/`). Templates are biometric data with a finite `expires_at`; they never contain images, session data, or identity fields, and they are purged on User deletion, privacy erasure, expiry, or an explicit purge. These endpoints accept application API keys (`x-api-key`) only; Business Console user tokens are rejected with `403`.\n\nReturns a paginated list of the templates the application currently holds. Purged templates are not listed.",
        "operationId": "list_biometric_templates",
        "tags": [
          "Biometric Templates"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "vendor_data",
            "required": false,
            "description": "Case-insensitive substring match on the owning User's current `vendor_data`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "vendor_user_uuid",
            "required": false,
            "description": "Exact match on the owning User.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "in": "query",
            "name": "status",
            "required": false,
            "description": "Lifecycle status. Purged templates are never listed.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "active",
                "expired",
                "held_out_of_use",
                "purge_pending",
                "purge_failed"
              ]
            }
          },
          {
            "in": "query",
            "name": "source_type",
            "required": false,
            "description": "How the template was created.",
            "schema": {
              "type": "string",
              "enum": [
                "session_delete",
                "automatic_retention",
                "backfill"
              ]
            }
          },
          {
            "in": "query",
            "name": "retained_from",
            "required": false,
            "description": "Templates retained at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "retained_to",
            "required": false,
            "description": "Templates retained at or before this time. Must not be earlier than `retained_from` (`400`).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "ordering",
            "required": false,
            "description": "Sort order.",
            "schema": {
              "type": "string",
              "enum": [
                "retained_at",
                "-retained_at",
                "expires_at",
                "-expires_at"
              ],
              "default": "-retained_at"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "description": "Pagination offset.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated templates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "uuid": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Template id. Randomly generated; not derived from the deleted session or its face."
                          },
                          "vendor_user_uuid": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The owning User."
                          },
                          "vendor_data": {
                            "type": "string",
                            "nullable": true,
                            "description": "The User's current `vendor_data`, resolved when you read the template (never copied)."
                          },
                          "source_type": {
                            "type": "string",
                            "enum": [
                              "session_delete",
                              "automatic_retention",
                              "backfill"
                            ],
                            "description": "How the template was created: a session deletion (API or Console), the application's automatic data-retention window, or a Didit-operated backfill you instructed."
                          },
                          "provenance_reference": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Opaque reference tying the template to its audit trail. It is not the deleted session's id and cannot be resolved to it."
                          },
                          "retention_policy": {
                            "type": "string",
                            "enum": [
                              "delete_with_session",
                              "retain_until_user_deleted"
                            ],
                            "description": "The application policy at retention time."
                          },
                          "retention_override": {
                            "type": "boolean",
                            "nullable": true,
                            "description": "The `retain_face_embeddings` value sent on the deletion, or `null` when the policy applied."
                          },
                          "retained_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "expires_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the template expires and is purged automatically. Always set."
                          },
                          "retained_by": {
                            "type": "string",
                            "nullable": true,
                            "description": "Principal that gave the instruction: the application id for API keys, the Console member id for Console actions, or a `service:` identifier for automatic retention. Never an email address."
                          },
                          "retained_by_type": {
                            "type": "string",
                            "enum": [
                              "API_KEY",
                              "CONSOLE_USER",
                              "SYSTEM"
                            ]
                          },
                          "instruction_class": {
                            "type": "string",
                            "enum": [
                              "operational_session_delete",
                              "privacy_erasure"
                            ]
                          },
                          "instruction_source": {
                            "type": "string",
                            "enum": [
                              "api",
                              "console",
                              "automatic_retention",
                              "backfill",
                              "privacy_erasure",
                              "explicit_template_purge",
                              "vendor_user_delete",
                              "expiry",
                              "reconciliation",
                              "migration",
                              "system"
                            ]
                          },
                          "instruction_id": {
                            "type": "string",
                            "description": "The `instruction_id` sent on the deletion, or a Didit-generated id."
                          },
                          "held_out_of_use": {
                            "type": "boolean",
                            "description": "`true` only while a legal hold applies. A held template is excluded from all matching."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "pending",
                              "active",
                              "expired",
                              "held_out_of_use",
                              "purge_pending",
                              "purge_failed",
                              "purged"
                            ],
                            "description": "Only `active` templates that are not held, not past `expires_at`, and whose User still exists take part in matching."
                          },
                          "purged_at": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "One active template": {
                    "value": {
                      "count": 1,
                      "next": null,
                      "previous": null,
                      "results": [
                        {
                          "uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                          "vendor_user_uuid": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f",
                          "vendor_data": "user-42",
                          "source_type": "session_delete",
                          "provenance_reference": "6b1e8d2f-4a3c-4f9e-8c7d-1a2b3c4d5e6f",
                          "retention_policy": "retain_until_user_deleted",
                          "retention_override": null,
                          "retained_at": "2026-08-28T10:15:42.318402Z",
                          "expires_at": "2027-08-28T10:15:42.318402Z",
                          "retained_by": "3c9e2b1f-7d4a-4e8b-9c1d-5f6a7b8c9d0e",
                          "retained_by_type": "API_KEY",
                          "instruction_class": "operational_session_delete",
                          "instruction_source": "api",
                          "instruction_id": "post-approval-cleanup-2026-08",
                          "held_out_of_use": false,
                          "status": "active",
                          "purged_at": null
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter value, or `retained_to` earlier than `retained_from`. Field-keyed validation errors.",
            "content": {
              "application/json": {
                "examples": {
                  "Bad range": {
                    "value": {
                      "retained_to": [
                        "Must be on or after retained_from."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Console user token, or the API key is not allowed. These endpoints accept application API keys only.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/biometric-templates/?vendor_data=user-42&status=active' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      }
    },
    "/v3/biometric-templates/count/": {
      "get": {
        "summary": "Count retained biometric templates",
        "description": "An opted-in application keeps one separately managed, image-free face biometric template anchored to the User when a session is deleted (see `DELETE /v3/session/{sessionId}/delete/`). Templates are biometric data with a finite `expires_at`; they never contain images, session data, or identity fields, and they are purged on User deletion, privacy erasure, expiry, or an explicit purge. These endpoints accept application API keys (`x-api-key`) only; Business Console user tokens are rejected with `403`.\n\nReturns the number of templates matching the same filters as the list endpoint. Use it to check what a filtered bulk purge with `delete_all: true` would touch.",
        "operationId": "count_biometric_templates",
        "tags": [
          "Biometric Templates"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "vendor_data",
            "required": false,
            "description": "Case-insensitive substring match on the owning User's current `vendor_data`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "vendor_user_uuid",
            "required": false,
            "description": "Exact match on the owning User.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "in": "query",
            "name": "status",
            "required": false,
            "description": "Lifecycle status. Purged templates are never listed.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "active",
                "expired",
                "held_out_of_use",
                "purge_pending",
                "purge_failed"
              ]
            }
          },
          {
            "in": "query",
            "name": "source_type",
            "required": false,
            "description": "How the template was created.",
            "schema": {
              "type": "string",
              "enum": [
                "session_delete",
                "automatic_retention",
                "backfill"
              ]
            }
          },
          {
            "in": "query",
            "name": "retained_from",
            "required": false,
            "description": "Templates retained at or after this time.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "retained_to",
            "required": false,
            "description": "Templates retained at or before this time. Must not be earlier than `retained_from` (`400`).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Count.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                },
                "examples": {
                  "Count": {
                    "value": {
                      "count": 128
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid filter value, or `retained_to` earlier than `retained_from`. Field-keyed validation errors.",
            "content": {
              "application/json": {
                "examples": {
                  "Bad range": {
                    "value": {
                      "retained_to": [
                        "Must be on or after retained_from."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Console user token, or the API key is not allowed. These endpoints accept application API keys only.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET 'https://verification.didit.me/v3/biometric-templates/count/?status=active' \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      }
    },
    "/v3/biometric-templates/{template_uuid}/": {
      "get": {
        "summary": "Get a retained biometric template",
        "description": "An opted-in application keeps one separately managed, image-free face biometric template anchored to the User when a session is deleted (see `DELETE /v3/session/{sessionId}/delete/`). Templates are biometric data with a finite `expires_at`; they never contain images, session data, or identity fields, and they are purged on User deletion, privacy erasure, expiry, or an explicit purge. These endpoints accept application API keys (`x-api-key`) only; Business Console user tokens are rejected with `403`.\n\nReturns one template. The response never includes an image, a vector, the deleted session's id, or identity data.",
        "operationId": "get_biometric_template",
        "tags": [
          "Biometric Templates"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "template_uuid",
            "required": true,
            "description": "Template id, as returned in `biometric_template_uuid` by the session deletion endpoints, `biometric_template_id` on a Face Search match, or the list endpoint.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Template id. Randomly generated; not derived from the deleted session or its face."
                    },
                    "vendor_user_uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "The owning User."
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "The User's current `vendor_data`, resolved when you read the template (never copied)."
                    },
                    "source_type": {
                      "type": "string",
                      "enum": [
                        "session_delete",
                        "automatic_retention",
                        "backfill"
                      ],
                      "description": "How the template was created: a session deletion (API or Console), the application's automatic data-retention window, or a Didit-operated backfill you instructed."
                    },
                    "provenance_reference": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Opaque reference tying the template to its audit trail. It is not the deleted session's id and cannot be resolved to it."
                    },
                    "retention_policy": {
                      "type": "string",
                      "enum": [
                        "delete_with_session",
                        "retain_until_user_deleted"
                      ],
                      "description": "The application policy at retention time."
                    },
                    "retention_override": {
                      "type": "boolean",
                      "nullable": true,
                      "description": "The `retain_face_embeddings` value sent on the deletion, or `null` when the policy applied."
                    },
                    "retained_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the template expires and is purged automatically. Always set."
                    },
                    "retained_by": {
                      "type": "string",
                      "nullable": true,
                      "description": "Principal that gave the instruction: the application id for API keys, the Console member id for Console actions, or a `service:` identifier for automatic retention. Never an email address."
                    },
                    "retained_by_type": {
                      "type": "string",
                      "enum": [
                        "API_KEY",
                        "CONSOLE_USER",
                        "SYSTEM"
                      ]
                    },
                    "instruction_class": {
                      "type": "string",
                      "enum": [
                        "operational_session_delete",
                        "privacy_erasure"
                      ]
                    },
                    "instruction_source": {
                      "type": "string",
                      "enum": [
                        "api",
                        "console",
                        "automatic_retention",
                        "backfill",
                        "privacy_erasure",
                        "explicit_template_purge",
                        "vendor_user_delete",
                        "expiry",
                        "reconciliation",
                        "migration",
                        "system"
                      ]
                    },
                    "instruction_id": {
                      "type": "string",
                      "description": "The `instruction_id` sent on the deletion, or a Didit-generated id."
                    },
                    "held_out_of_use": {
                      "type": "boolean",
                      "description": "`true` only while a legal hold applies. A held template is excluded from all matching."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending",
                        "active",
                        "expired",
                        "held_out_of_use",
                        "purge_pending",
                        "purge_failed",
                        "purged"
                      ],
                      "description": "Only `active` templates that are not held, not past `expires_at`, and whose User still exists take part in matching."
                    },
                    "purged_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true
                    }
                  }
                },
                "examples": {
                  "Active template": {
                    "value": {
                      "uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                      "vendor_user_uuid": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f",
                      "vendor_data": "user-42",
                      "source_type": "session_delete",
                      "provenance_reference": "6b1e8d2f-4a3c-4f9e-8c7d-1a2b3c4d5e6f",
                      "retention_policy": "retain_until_user_deleted",
                      "retention_override": null,
                      "retained_at": "2026-08-28T10:15:42.318402Z",
                      "expires_at": "2027-08-28T10:15:42.318402Z",
                      "retained_by": "3c9e2b1f-7d4a-4e8b-9c1d-5f6a7b8c9d0e",
                      "retained_by_type": "API_KEY",
                      "instruction_class": "operational_session_delete",
                      "instruction_source": "api",
                      "instruction_id": "post-approval-cleanup-2026-08",
                      "held_out_of_use": false,
                      "status": "active",
                      "purged_at": null
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Console user token, or the API key is not allowed. These endpoints accept application API keys only.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown template, a template of another application, or (on `GET`) a purged template.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Biometric template not found."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X GET https://verification.didit.me/v3/biometric-templates/9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b/ \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      },
      "delete": {
        "summary": "Purge a retained biometric template",
        "description": "An opted-in application keeps one separately managed, image-free face biometric template anchored to the User when a session is deleted (see `DELETE /v3/session/{sessionId}/delete/`). Templates are biometric data with a finite `expires_at`; they never contain images, session data, or identity fields, and they are purged on User deletion, privacy erasure, expiry, or an explicit purge. These endpoints accept application API keys (`x-api-key`) only; Business Console user tokens are rejected with `403`.\n\nPurges one template: it is removed from every kind of matching and the stored template is deleted. Irreversible and recorded on the audit trail with the acting principal.\n\n**Retry semantics:** Didit deletes the stored template first and only then marks the template purged. If a biometric store is unavailable the call returns `503`, the template moves to `status: purge_failed` and is already excluded from matching; repeat the same call to finish. Repeating a purge of an already purged template returns `already_purged`.\n\nTemplates are also purged by `POST /v3/users/delete/` for the owning User, by any deletion of that User's sessions with `deletion_instruction: privacy_erasure`, and automatically at `expires_at`.",
        "operationId": "purge_biometric_template",
        "tags": [
          "Biometric Templates"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "template_uuid",
            "required": true,
            "description": "Template id, as returned in `biometric_template_uuid` by the session deletion endpoints, `biometric_template_id` on a Face Search match, or the list endpoint.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Purge outcome.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "outcome": {
                      "type": "string",
                      "enum": [
                        "purged",
                        "already_purged"
                      ]
                    }
                  }
                },
                "examples": {
                  "Purged": {
                    "value": {
                      "uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                      "outcome": "purged"
                    }
                  },
                  "Already purged": {
                    "value": {
                      "uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                      "outcome": "already_purged"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Console user token, or the API key is not allowed. These endpoints accept application API keys only.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown template, a template of another application, or (on `GET`) a purged template.",
            "content": {
              "application/json": {
                "examples": {
                  "Not found": {
                    "value": {
                      "detail": "Biometric template not found."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "A biometric store was unavailable while retaining or purging a biometric template. Nothing is deleted; repeat the same request. Retries are idempotent and converge on a single template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Retryable": {
                    "value": {
                      "detail": "The biometric-template operation could not finish because an external store is unavailable. The operation is retryable."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X DELETE https://verification.didit.me/v3/biometric-templates/9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b/ \\\n  -H 'x-api-key: YOUR_API_KEY'"
          }
        ]
      }
    },
    "/v3/biometric-templates/delete/": {
      "post": {
        "summary": "Bulk purge retained biometric templates",
        "description": "An opted-in application keeps one separately managed, image-free face biometric template anchored to the User when a session is deleted (see `DELETE /v3/session/{sessionId}/delete/`). Templates are biometric data with a finite `expires_at`; they never contain images, session data, or identity fields, and they are purged on User deletion, privacy erasure, expiry, or an explicit purge. These endpoints accept application API keys (`x-api-key`) only; Business Console user tokens are rejected with `403`.\n\nPurges many templates in one call, by explicit id list or with `delete_all: true` optionally narrowed by the same filters as the list endpoint. Templates are purged one by one and each result reports `purged` or `already_purged`. If a biometric store is unavailable the call returns `503` at the first failing template: templates purged earlier in the request stay purged, the failing one moves to `purge_failed` (already excluded from matching), and repeating the request finishes the job.\n\n**`delete_all: true` without filters purges every biometric template in the application and cannot be undone.** Run the count endpoint with the same filters first.",
        "operationId": "bulk_purge_biometric_templates",
        "tags": [
          "Biometric Templates"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "template_uuids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "description": "Templates to purge. Required unless `delete_all` is `true`. Already purged ids are reported as `already_purged`."
                  },
                  "delete_all": {
                    "type": "boolean",
                    "default": false,
                    "description": "When `true`, purges every template matching the filters below (all of the application's templates when no filter is given). `template_uuids` is ignored. Irreversible."
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Only with `delete_all`: case-insensitive substring match on the owning User's `vendor_data`."
                  },
                  "vendor_user_uuid": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Only with `delete_all`: exact match on the owning User."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "pending",
                      "active",
                      "expired",
                      "held_out_of_use",
                      "purge_pending",
                      "purge_failed"
                    ],
                    "description": "Only with `delete_all`."
                  },
                  "source_type": {
                    "type": "string",
                    "enum": [
                      "session_delete",
                      "automatic_retention",
                      "backfill"
                    ],
                    "description": "Only with `delete_all`."
                  },
                  "retained_from": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Only with `delete_all`."
                  },
                  "retained_to": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Only with `delete_all`. Must not be earlier than `retained_from`."
                  }
                }
              },
              "examples": {
                "By id": {
                  "value": {
                    "template_uuids": [
                      "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                      "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
                    ]
                  }
                },
                "Every template of one User": {
                  "value": {
                    "delete_all": true,
                    "vendor_user_uuid": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f"
                  }
                },
                "Every template in the application": {
                  "value": {
                    "delete_all": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-template purge outcomes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "uuid": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "outcome": {
                            "type": "string",
                            "enum": [
                              "purged",
                              "already_purged"
                            ]
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Mixed": {
                    "value": {
                      "results": [
                        {
                          "uuid": "9d2f4b6e-1c3a-4e8f-b7d5-0a1c2e3f4a5b",
                          "outcome": "purged"
                        },
                        {
                          "uuid": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                          "outcome": "already_purged"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error — nothing is purged.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing selector": {
                    "value": {
                      "template_uuids": [
                        "This field is required unless delete_all is true."
                      ]
                    }
                  },
                  "Bad range": {
                    "value": {
                      "retained_to": [
                        "Must be on or after retained_from."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Console user token, or the API key is not allowed. These endpoints accept application API keys only.",
            "content": {
              "application/json": {
                "examples": {
                  "Forbidden": {
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "A biometric store was unavailable while retaining or purging a biometric template. Nothing is deleted; repeat the same request. Retries are idempotent and converge on a single template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "Retryable": {
                    "value": {
                      "detail": "The biometric-template operation could not finish because an external store is unavailable. The operation is retryable."
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/biometric-templates/delete/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"delete_all\": true, \"vendor_user_uuid\": \"2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f\"}'"
          }
        ]
      }
    },
    "/v3/kyb/shareholders/": {
      "post": {
        "summary": "KYB registry company with shareholders (standalone)",
        "operationId": "post_v3_kyb_shareholders",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [],
        "description": "Retrieve the Lite profile **plus the direct shareholders** (natural persons and corporate entities, with their ownership bands) of one candidate returned by `POST /v3/kyb/search/`.\n\n**Pairing with search.** Pass the candidate's `kyb_response_id` exactly as returned by a search of the same application. The search runs on the Lite registry chain; when the country's ownership data lives at another registry Didit re-finds the company there by registration number, at no extra cost.\n\n**Billing.** Billed at the country's Shareholders price - see [KYB registry pricing](/getting-started/kyb-registry-pricing). When the registry holds no shareholder record for the company (or the country offers no ownership data at all) the Lite profile is delivered and billed instead: read `registry_tier_delivered` and `registry_ownership_status`. The balance is checked against the Shareholders price before any registry call (`403` when short).\n\n**Availability.** v3 only. Every call creates a business session (its id is the `request_id`).\n\n**Pending reports.** When a report is still being prepared, or the ownership section has not been retrieved from the registry yet, the endpoint returns 202 Accepted, kyb_registry.fetch_status=pending, kyb_registry.registry_ownership_status=pending, and registry_tier_delivered=null. Keep request_id and retrieve GET /v3/session/{request_id}/decision/ until registry_checks[0].company.fetch_status is resolved. Didit completes the report automatically and charges the delivered tier once it is ready. Do not repeat the purchase while it is pending; every new POST creates a separate request.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kyb_response_id"
                ],
                "properties": {
                  "kyb_response_id": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Candidate handle from `POST /v3/kyb/search/` (`kyb_registry.companies[].kyb_response_id`). Ephemeral — use it shortly after the search that produced it.",
                    "example": "69aeeb95febb0f1704042259"
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for this company; echoed back and stored with the business session."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON stored with the business session and echoed back."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "Must be `true` (the default). KYB registry selects are always persisted so billing and retrieval can be tracked; `false` returns `400`."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/kyb/shareholders/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n    \"vendor_data\": \"company-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, time, requests\n\nsearch = requests.post(\n    \"https://verification.didit.me/v3/kyb/search/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"country_code\": \"GB\", \"name\": \"Tesco\"},\n    timeout=60,\n).json()\nkyb_response_id = search[\"kyb_registry\"][\"companies\"][0][\"kyb_response_id\"]\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/kyb/shareholders/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"kyb_response_id\": kyb_response_id, \"vendor_data\": \"company-1234\"},\n    timeout=90,\n)\nresp.raise_for_status()\ndata = resp.json()\nrequest_id = data[\"request_id\"]\nprint(\"Keep this request ID:\", request_id)\ncompany = data[\"kyb_registry\"]\nif resp.status_code == 202 or company.get(\"fetch_status\") == \"pending\":\n    # This client wait limit does not cancel the report or create a new purchase.\n    deadline = time.monotonic() + 300\n    while company.get(\"fetch_status\") != \"resolved\" and time.monotonic() < deadline:\n        time.sleep(5)\n        decision = requests.get(\n            f\"https://verification.didit.me/v3/session/{request_id}/decision/\",\n            headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n            timeout=30,\n        )\n        decision.raise_for_status()\n        checks = decision.json().get(\"registry_checks\") or []\n        if checks:\n            company = checks[0].get(\"company\") or company\nif company.get(\"fetch_status\") == \"resolved\":\n    print(company[\"company_name\"], company[\"registry_tier_delivered\"])\nelse:\n    print(\"Still processing; retrieve this request later:\", request_id)"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/kyb/shareholders/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    kyb_response_id: '69aeeb95febb0f1704042259',\n    vendor_data: 'company-1234',\n  }),\n});\nif (!res.ok) throw new Error(`Request failed: ${res.status}`);\nconst data = await res.json();\nconst requestId = data.request_id;\nconsole.log('Keep this request ID:', requestId);\nlet company = data.kyb_registry;\nif (res.status === 202 || company.fetch_status === 'pending') {\n  // This client wait limit does not cancel the report or create a new purchase.\n  const deadline = Date.now() + 300000;\n  while (company.fetch_status !== 'resolved' && Date.now() < deadline) {\n    await new Promise(resolve => setTimeout(resolve, 5000));\n    const decisionResponse = await fetch(\n      `https://verification.didit.me/v3/session/${requestId}/decision/`,\n      { headers: { 'x-api-key': 'YOUR_API_KEY' }, signal: AbortSignal.timeout(30000) },\n    );\n    if (!decisionResponse.ok) throw new Error(`Retrieval failed: ${decisionResponse.status}`);\n    const decision = await decisionResponse.json();\n    company = decision.registry_checks?.[0]?.company ?? company;\n  }\n}\nif (company.fetch_status === 'resolved') {\n  console.log(company.company_name, company.registry_tier_delivered);\n} else {\n  console.log('Still processing; retrieve this request later:', requestId);\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Company report returned and billed at the delivered tier. Ownership reports still being prepared can return 202; keep request_id to retrieve their saved decision.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Id of the business session created for this retrieval. The stored record (visible in the console) keeps updating if the registry resolves after the response."
                    },
                    "registry_tier_requested": {
                      "type": "string",
                      "enum": [
                        "basic",
                        "shareholders",
                        "ubo"
                      ],
                      "description": "The tier this endpoint sells: `basic` (Lite) for select, `shareholders`, `ubo`."
                    },
                    "registry_tier_delivered": {
                      "type": "string",
                      "enum": [
                        "basic",
                        "shareholders",
                        "ubo",
                        null
                      ],
                      "description": "The tier actually delivered and billed. Lower than requested when the country's registries hold no ownership data, or the registry has no ownership record for this company.",
                      "nullable": true
                    },
                    "kyb_registry": {
                      "type": "object",
                      "description": "Full registry company profile.",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Didit's id for this company record."
                        },
                        "node_id": {
                          "type": "string",
                          "example": "feature_kyb_registry"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "Not Finished",
                            "Approved",
                            "Declined",
                            "In Review"
                          ],
                          "description": "Didit's assessment of the registry check (e.g. `In Review` when the company is not active in the registry or ownership data could not be derived)."
                        },
                        "registry_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "active",
                            "dissolved",
                            "deregistered",
                            "see full details",
                            "authorised",
                            "appointed representative",
                            "unauthorised",
                            "inactive",
                            "no longer authorised",
                            "closed",
                            "struck off",
                            null
                          ],
                          "description": "Normalized company status as reported by the registry."
                        },
                        "data_resolved": {
                          "type": "boolean",
                          "description": "`true` once the registry returned the full profile. `false` when the registry was still processing after polling — the stored record completes automatically once the registry resolves."
                        },
                        "company_name": {
                          "type": "string",
                          "example": "Tesco PLC"
                        },
                        "registration_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "00445790"
                        },
                        "country_code": {
                          "type": "string",
                          "description": "ISO 3166-1 alpha-2.",
                          "example": "GB"
                        },
                        "region": {
                          "type": "string",
                          "nullable": true,
                          "description": "Subdivision code when the registry is regional (e.g. `CA` for `US-CA`); empty otherwise."
                        },
                        "company_type": {
                          "type": "string",
                          "nullable": true,
                          "example": "Public Limited Company"
                        },
                        "incorporation_date": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "example": "1947-11-27"
                        },
                        "registered_address": {
                          "type": "string",
                          "nullable": true,
                          "example": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA"
                        },
                        "tax_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "GB412 8925 93"
                        },
                        "risk_level": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry-reported risk level, when available."
                        },
                        "verification_status": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry verification status, when available."
                        },
                        "is_from_registry": {
                          "type": "boolean",
                          "description": "Always `true` for this endpoint — the profile was retrieved from an official registry."
                        },
                        "fetch_status": {
                          "type": "string",
                          "enum": [
                            "pending",
                            "resolved"
                          ],
                          "description": "Registry fetch lifecycle. Mirrored by `data_resolved`."
                        },
                        "alternative_names": {
                          "type": "string",
                          "nullable": true,
                          "description": "Alternative, trading, former or original-language company names as text, when reported."
                        },
                        "nature_of_business": {
                          "type": "string",
                          "nullable": true,
                          "description": "Activity description or classification code, when reported."
                        },
                        "registered_capital": {
                          "type": "string",
                          "nullable": true
                        },
                        "registered_capital_amount": {
                          "type": "string",
                          "nullable": true,
                          "description": "Decimal amount as a string, when reported."
                        },
                        "registered_capital_currency": {
                          "type": "string",
                          "nullable": true,
                          "description": "ISO 4217 code, when reported."
                        },
                        "website": {
                          "type": "string",
                          "nullable": true,
                          "example": "https://www.tesco.com/"
                        },
                        "email": {
                          "type": "string",
                          "nullable": true,
                          "example": "customer.service@tesco.co.uk"
                        },
                        "phone": {
                          "type": "string",
                          "nullable": true,
                          "example": "03301231688"
                        },
                        "legal_entity_identifier": {
                          "type": "string",
                          "nullable": true,
                          "description": "LEI, when reported."
                        },
                        "location_of_registration": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry/jurisdiction the company is registered with, when reported."
                        },
                        "vat_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "EU VAT number, when collected during the hosted registry step or edited afterwards. At select time this is typically not yet set — VAT and tax ID validation runs when the end user submits the registry step in the hosted flow."
                        },
                        "vat_validation_status": {
                          "type": "string",
                          "enum": [
                            "valid",
                            "invalid",
                            "format_valid",
                            "invalid_format",
                            "could_not_validate",
                            "not_applicable"
                          ],
                          "description": "Result of validating the VAT number or, when there is none, the `tax_number`, at registry submit. `valid` / `invalid`: decided by the official registry of the country (EU VIES, Norway, Switzerland, Brazil, Colombia, Costa Rica, Ecuador, Paraguay; Poland also by its domestic VAT register). `format_valid` / `invalid_format`: decided by the country's format and check-digit rules where no registry can be queried. `could_not_validate`: the registry was unavailable. `not_applicable`: no number, a country without registry or rules, or a sandbox session."
                        },
                        "vat_validated_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "The number that was checked, as the source knows it (for example the VAT number derived from a French SIREN or a Dutch RSIN). `null` when no check ran."
                        },
                        "vat_validation_source": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "eu_vies",
                            "pl_vat_white_list",
                            "no_brreg",
                            "ch_uid_register",
                            "br_receita_federal",
                            "co_rues",
                            "cr_hacienda",
                            "ec_sri",
                            "py_dnit",
                            "format_rules",
                            null
                          ],
                          "description": "The source that decided `vat_validation_status`: an official registry, or `format_rules`. `null` when no check ran."
                        },
                        "vat_validated_name": {
                          "type": "string",
                          "nullable": true,
                          "description": "Name registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                        },
                        "vat_validated_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Address registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                        },
                        "vat_checked_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Timestamp of the check. `null` when no check ran."
                        },
                        "financial_summary": {
                          "type": "object",
                          "nullable": true,
                          "description": "Registry-reported share/capital details (currency, total shares, share classes), when available."
                        },
                        "officers": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string",
                                "example": "MELISSA BETHELL"
                              },
                              "designation": {
                                "type": "string",
                                "nullable": true,
                                "description": "Raw registry designation (e.g. `Director`, `Secretary`)."
                              },
                              "role": {
                                "type": "string",
                                "description": "Normalized role derived from the designation. Full 17-value model set; registry parsing on this endpoint typically emits director, non_executive_director, secretary, chairman, or company_officer.",
                                "enum": [
                                  "director",
                                  "non_executive_director",
                                  "secretary",
                                  "chairman",
                                  "ubo",
                                  "shareholder",
                                  "representative",
                                  "founder",
                                  "legal_advisor",
                                  "authorized_signatory",
                                  "trustee",
                                  "beneficiary",
                                  "company_officer",
                                  "settlor",
                                  "protector",
                                  "investor",
                                  "other"
                                ]
                              },
                              "nationality": {
                                "type": "string",
                                "nullable": true
                              },
                              "is_active": {
                                "type": "boolean",
                                "description": "`false` when the registry marks the appointment as resigned."
                              },
                              "kyc_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Approved",
                                  "Declined",
                                  "Pending",
                                  null
                                ],
                                "description": "Status of an associated KYC session, when one was started for this officer. `null` otherwise."
                              },
                              "kyc_session_url": {
                                "type": "string",
                                "nullable": true,
                                "description": "Verification URL of the associated KYC session, when one exists."
                              },
                              "first_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Given name when explicitly reported by the registry; not inferred from the full name."
                              },
                              "last_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Family name when explicitly reported by the registry."
                              },
                              "address": {
                                "type": "string",
                                "nullable": true,
                                "description": "Officer address reported by the registry."
                              },
                              "appointment_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Date the officer was appointed.",
                                "format": "date"
                              },
                              "termination_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Date the appointment ended, when reported.",
                                "format": "date"
                              },
                              "date_of_birth": {
                                "type": "string",
                                "nullable": true,
                                "description": "Complete registry-reported birth date. Null when only a birth year or month is known.",
                                "format": "date"
                              },
                              "date_of_birth_year": {
                                "type": "integer",
                                "nullable": true,
                                "minimum": 1,
                                "maximum": 9999,
                                "description": "Registry-reported birth year, including when the full date is unavailable."
                              },
                              "date_of_birth_month": {
                                "type": "integer",
                                "nullable": true,
                                "minimum": 1,
                                "maximum": 12,
                                "description": "Registry-reported birth month. Null when only the year is known."
                              }
                            }
                          },
                          "description": "Directors, secretaries, and other officers extracted from the registry."
                        },
                        "beneficial_owners": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string"
                              },
                              "first_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "last_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "entity_type": {
                                "type": "string",
                                "enum": [
                                  "person",
                                  "company"
                                ],
                                "description": "Whether the owner is a natural person or a corporate entity."
                              },
                              "roles": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Normalized roles (e.g. `ubo`, `shareholder`)."
                              },
                              "ownership_min_shares": {
                                "type": "string",
                                "nullable": true,
                                "description": "Lower bound of the ownership band reported by the registry (e.g. `25%`)."
                              },
                              "ownership_max_shares": {
                                "type": "string",
                                "nullable": true,
                                "description": "Upper bound of the ownership band reported by the registry."
                              },
                              "is_active": {
                                "type": "boolean"
                              },
                              "kyc_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Approved",
                                  "Declined",
                                  "Pending",
                                  null
                                ]
                              },
                              "kyc_session_url": {
                                "type": "string",
                                "nullable": true
                              },
                              "effective_ownership_percent": {
                                "type": "number",
                                "nullable": true,
                                "description": "Parsed ownership percentage (max bound, falling back to min bound)."
                              },
                              "company_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "registration_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "country_of_birth": {
                                "type": "string",
                                "nullable": true
                              },
                              "email": {
                                "type": "string",
                                "nullable": true
                              },
                              "nationality": {
                                "type": "string",
                                "nullable": true
                              },
                              "designation": {
                                "type": "string",
                                "nullable": true
                              },
                              "voting_min_shares": {
                                "type": "string",
                                "nullable": true
                              },
                              "voting_max_shares": {
                                "type": "string",
                                "nullable": true
                              },
                              "date_of_birth": {
                                "type": "string",
                                "nullable": true,
                                "description": "Complete birth date when reported.",
                                "format": "date"
                              },
                              "appointment_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Appointment date when reported.",
                                "format": "date"
                              },
                              "shareholding": {
                                "$ref": "#/components/schemas/KYBRegistryShareholding"
                              }
                            }
                          },
                          "description": "Beneficial owners / persons with significant control extracted from the registry. Can be empty when the registry does not expose ownership."
                        },
                        "addresses": {
                          "type": "array",
                          "nullable": true,
                          "description": "Every address the registry states, one canonical shape. Null when it states none.",
                          "items": {
                            "$ref": "#/components/schemas/KYBRegistryAddress"
                          }
                        },
                        "industries": {
                          "type": "array",
                          "nullable": true,
                          "description": "The activities the registry classifies the company under, one canonical shape. Null when it states none.",
                          "items": {
                            "$ref": "#/components/schemas/KYBRegistryIndustry"
                          }
                        },
                        "accounts": {
                          "type": "object",
                          "nullable": true,
                          "additionalProperties": true,
                          "description": "Registry filing dates, when available. Annual returns and general meetings use last_annual_return_date and last_agm_date; they are distinct from financial accounts."
                        },
                        "registry_data": {
                          "type": "object",
                          "description": "Raw record returned by the registry source, kept for reviewers. Its shape differs by country and source and is not a stable contract: read the canonical fields (`addresses`, `industries`, `ownership`, `beneficial_owners[].shareholding`) instead."
                        },
                        "user_provided_data": {
                          "type": "object",
                          "nullable": true,
                          "description": "Always `null` on this endpoint (used by the hosted KYB flow when end users edit registry data)."
                        },
                        "confirmed_by_user_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Always `null` on this endpoint."
                        },
                        "last_console_edit_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Set when a console reviewer edits the record later."
                        },
                        "is_editable": {
                          "type": "boolean",
                          "description": "Whether the registry-sourced data can still be edited in the hosted flow/console."
                        },
                        "registry_tier_delivered": {
                          "type": "string",
                          "enum": [
                            "basic",
                            "shareholders",
                            "ubo",
                            null
                          ],
                          "description": "Same as the top-level `registry_tier_delivered`.",
                          "nullable": true
                        },
                        "registry_ownership_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "not_requested",
                            "delivered",
                            "unavailable",
                            "pending",
                            null
                          ],
                          "description": "`delivered` when the ownership data came back, `unavailable` when an ownership tier was requested but the registry had none for this company (see `registry_data.ownership_error`), `pending` when the ownership section has not been retrieved from the registry yet and Didit is still completing it, `not_requested` on the Lite tier."
                        },
                        "ownership": {
                          "$ref": "#/components/schemas/KYBRegistryOwnership"
                        },
                        "registry_tier": {
                          "type": "string",
                          "nullable": true,
                          "description": "The registry tier the workflow ordered: `basic`, `shareholders` or `ubo`. Also in `ownership.tier_requested`."
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "description": "Echo of the `metadata` you sent."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "examples": {
                  "Resolved company": {
                    "summary": "Full registry profile (officer list truncated for brevity)",
                    "value": {
                      "request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
                      "kyb_registry": {
                        "uuid": "f1e2d3c4-b5a6-4789-9c0d-1e2f3a4b5c6d",
                        "node_id": "feature_kyb_registry",
                        "status": "In Review",
                        "registry_status": "active",
                        "data_resolved": true,
                        "company_name": "Tesco PLC",
                        "registration_number": "00445790",
                        "country_code": "GB",
                        "region": "",
                        "company_type": "Public Limited Company",
                        "incorporation_date": "1947-11-27",
                        "registered_address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
                        "tax_number": "GB412 8925 93",
                        "risk_level": "low risk",
                        "verification_status": "verified",
                        "is_from_registry": true,
                        "fetch_status": "resolved",
                        "alternative_names": "TESCO STORES (HOLDINGS) PUBLIC LIMITED COMPANY",
                        "nature_of_business": null,
                        "registered_capital": null,
                        "registered_capital_amount": null,
                        "registered_capital_currency": null,
                        "website": "https://www.tesco.com/",
                        "email": "customer.service@tesco.co.uk",
                        "phone": "03301231688",
                        "legal_entity_identifier": null,
                        "location_of_registration": null,
                        "financial_summary": {
                          "currency": "Pound (£)",
                          "total_number_of_shares": "8174378721",
                          "meta_detail": {
                            "Class_Of_Share": "Ordinary"
                          }
                        },
                        "officers": [
                          {
                            "uuid": "a1b2c3d4-e5f6-4789-9a0b-1c2d3e4f5a6b",
                            "name": "CHRISTOPHER JON TAYLOR",
                            "designation": "Secretary",
                            "role": "secretary",
                            "nationality": null,
                            "is_active": true,
                            "kyc_status": null,
                            "kyc_session_url": null
                          },
                          {
                            "uuid": "b2c3d4e5-f6a7-4890-8b1c-2d3e4f5a6b7c",
                            "name": "MELISSA BETHELL",
                            "designation": "Director",
                            "role": "director",
                            "nationality": "British",
                            "is_active": true,
                            "kyc_status": null,
                            "kyc_session_url": null
                          }
                        ],
                        "beneficial_owners": [],
                        "addresses": [
                          {
                            "address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
                            "type": "legal_entity_registry_address",
                            "description": "registered office address"
                          }
                        ],
                        "industries": null,
                        "accounts": {
                          "last_account": "26 February 2025",
                          "next_account": "26 February 2026",
                          "due_by_date": "26 August 2026"
                        },
                        "registry_data": {
                          "name": "Tesco PLC",
                          "registration_number": "00445790",
                          "status": "active",
                          "type": "Public Limited Company",
                          "incorporation_date": "1947-11-27",
                          "tax_number": "GB412 8925 93",
                          "country_code": "GB",
                          "fetch_status": "resolved",
                          "industries_detail": [
                            {
                              "code": "47110",
                              "name": "Retail Sale In Non-specialised Stores With Food, Beverages Or Tobacco Predominating",
                              "description": null,
                              "meta_detail": []
                            }
                          ]
                        },
                        "user_provided_data": null,
                        "confirmed_by_user_at": null,
                        "last_console_edit_at": null,
                        "is_editable": true
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:45:00.000000+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field-level problems use DRF's standard envelope.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing kyb_response_id": {
                    "summary": "`kyb_response_id` is required",
                    "value": {
                      "kyb_response_id": [
                        "This field is required."
                      ]
                    }
                  },
                  "save_api_request=false rejected": {
                    "summary": "Selects are always persisted",
                    "value": {
                      "save_api_request": [
                        "KYB registry select must be saved so billing and retrieval can be tracked."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any screening or provider call happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Report accepted and still processing. When a report is still being prepared, the endpoint returns 202 Accepted, kyb_registry.fetch_status=pending, and registry_tier_delivered=null. Keep request_id and retrieve GET /v3/session/{request_id}/decision/ until registry_checks[0].company.fetch_status is resolved. Didit completes the report automatically and charges the delivered tier once it is ready. Do not repeat the purchase while it is pending; every new POST creates a separate request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/paths/~1v3~1kyb~1shareholders~1/post/responses/200/content/application~1json/schema"
                },
                "examples": {
                  "Pending (registry still resolving)": {
                    "summary": "Ownership report is still processing; retrieve the saved decision",
                    "value": {
                      "request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
                      "kyb_registry": {
                        "uuid": "7c0a4f7e-2b1d-4f6a-9c3e-8d5b2a1f0e9d",
                        "node_id": "feature_kyb_registry",
                        "status": "Not Finished",
                        "registry_status": null,
                        "data_resolved": false,
                        "company_name": "Example Holdings Limited",
                        "registration_number": "12345678",
                        "country_code": "HK",
                        "region": null,
                        "company_type": null,
                        "incorporation_date": null,
                        "registered_address": null,
                        "tax_number": null,
                        "risk_level": null,
                        "verification_status": null,
                        "is_from_registry": true,
                        "fetch_status": "pending",
                        "alternative_names": null,
                        "nature_of_business": null,
                        "registered_capital": null,
                        "registered_capital_amount": null,
                        "registered_capital_currency": null,
                        "website": null,
                        "email": null,
                        "phone": null,
                        "legal_entity_identifier": null,
                        "location_of_registration": null,
                        "financial_summary": {},
                        "officers": [],
                        "beneficial_owners": [],
                        "addresses": null,
                        "industries": null,
                        "accounts": null,
                        "registry_data": {},
                        "user_provided_data": null,
                        "confirmed_by_user_at": null,
                        "last_console_edit_at": null,
                        "is_editable": true,
                        "registry_tier_delivered": null,
                        "registry_ownership_status": "pending"
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:45:00.000000+00:00",
                      "registry_tier_delivered": null,
                      "registry_tier_requested": "shareholders"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/kyb/ubo/": {
      "post": {
        "summary": "KYB registry company with ultimate beneficial owners (standalone)",
        "operationId": "post_v3_kyb_ubo",
        "tags": [
          "Standalone APIs"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [],
        "description": "Retrieve the Lite profile, the direct shareholders **and the ultimate beneficial owners** resolved through the ownership chain (`registry_data.ubo_resolution` carries the corporate parent chain) of one candidate returned by `POST /v3/kyb/search/`.\n\n**Pairing with search.** Pass the candidate's `kyb_response_id` exactly as returned by a search of the same application. The search runs on the Lite registry chain; when the country's ownership data lives at another registry Didit re-finds the company there by registration number, at no extra cost.\n\n**Billing.** Billed at the country's UBO price - see [KYB registry pricing](/getting-started/kyb-registry-pricing). The tier delivered is the highest the country and the registry can serve: Shareholders when the resolved report names no natural person as a beneficial owner, Lite when there is no ownership record at all; `registry_tier_delivered` names what was billed. The balance is checked against the UBO price before any registry call (`403` when short).\n\n**Availability.** v3 only. Every call creates a business session (its id is the `request_id`).\n\n**Pending reports.** When a report is still being prepared, or the ownership section has not been retrieved from the registry yet, the endpoint returns 202 Accepted, kyb_registry.fetch_status=pending, kyb_registry.registry_ownership_status=pending, and registry_tier_delivered=null. Keep request_id and retrieve GET /v3/session/{request_id}/decision/ until registry_checks[0].company.fetch_status is resolved. Didit completes the report automatically and charges the delivered tier once it is ready. Do not repeat the purchase while it is pending; every new POST creates a separate request.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kyb_response_id"
                ],
                "properties": {
                  "kyb_response_id": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Candidate handle from `POST /v3/kyb/search/` (`kyb_registry.companies[].kyb_response_id`). Ephemeral — use it shortly after the search that produced it.",
                    "example": "69aeeb95febb0f1704042259"
                  },
                  "vendor_data": {
                    "type": "string",
                    "description": "Your identifier for this company; echoed back and stored with the business session."
                  },
                  "metadata": {
                    "type": "object",
                    "nullable": true,
                    "description": "Free-form JSON stored with the business session and echoed back."
                  },
                  "save_api_request": {
                    "type": "boolean",
                    "default": true,
                    "description": "Must be `true` (the default). KYB registry selects are always persisted so billing and retrieval can be tracked; `false` returns `400`."
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "curl",
            "source": "curl -X POST https://verification.didit.me/v3/kyb/ubo/ \\\n  -H 'x-api-key: YOUR_API_KEY' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n    \"kyb_response_id\": \"69aeeb95febb0f1704042259\",\n    \"vendor_data\": \"company-1234\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os, time, requests\n\nsearch = requests.post(\n    \"https://verification.didit.me/v3/kyb/search/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"country_code\": \"GB\", \"name\": \"Tesco\"},\n    timeout=60,\n).json()\nkyb_response_id = search[\"kyb_registry\"][\"companies\"][0][\"kyb_response_id\"]\n\nresp = requests.post(\n    \"https://verification.didit.me/v3/kyb/ubo/\",\n    headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n    json={\"kyb_response_id\": kyb_response_id, \"vendor_data\": \"company-1234\"},\n    timeout=90,\n)\nresp.raise_for_status()\ndata = resp.json()\nrequest_id = data[\"request_id\"]\nprint(\"Keep this request ID:\", request_id)\ncompany = data[\"kyb_registry\"]\nif resp.status_code == 202 or company.get(\"fetch_status\") == \"pending\":\n    # This client wait limit does not cancel the report or create a new purchase.\n    deadline = time.monotonic() + 300\n    while company.get(\"fetch_status\") != \"resolved\" and time.monotonic() < deadline:\n        time.sleep(5)\n        decision = requests.get(\n            f\"https://verification.didit.me/v3/session/{request_id}/decision/\",\n            headers={\"x-api-key\": os.environ[\"DIDIT_API_KEY\"]},\n            timeout=30,\n        )\n        decision.raise_for_status()\n        checks = decision.json().get(\"registry_checks\") or []\n        if checks:\n            company = checks[0].get(\"company\") or company\nif company.get(\"fetch_status\") == \"resolved\":\n    print(company[\"company_name\"], company[\"registry_tier_delivered\"])\nelse:\n    print(\"Still processing; retrieve this request later:\", request_id)"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const res = await fetch('https://verification.didit.me/v3/kyb/ubo/', {\n  method: 'POST',\n  headers: {\n    'x-api-key': 'YOUR_API_KEY',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    kyb_response_id: '69aeeb95febb0f1704042259',\n    vendor_data: 'company-1234',\n  }),\n});\nif (!res.ok) throw new Error(`Request failed: ${res.status}`);\nconst data = await res.json();\nconst requestId = data.request_id;\nconsole.log('Keep this request ID:', requestId);\nlet company = data.kyb_registry;\nif (res.status === 202 || company.fetch_status === 'pending') {\n  // This client wait limit does not cancel the report or create a new purchase.\n  const deadline = Date.now() + 300000;\n  while (company.fetch_status !== 'resolved' && Date.now() < deadline) {\n    await new Promise(resolve => setTimeout(resolve, 5000));\n    const decisionResponse = await fetch(\n      `https://verification.didit.me/v3/session/${requestId}/decision/`,\n      { headers: { 'x-api-key': 'YOUR_API_KEY' }, signal: AbortSignal.timeout(30000) },\n    );\n    if (!decisionResponse.ok) throw new Error(`Retrieval failed: ${decisionResponse.status}`);\n    const decision = await decisionResponse.json();\n    company = decision.registry_checks?.[0]?.company ?? company;\n  }\n}\nif (company.fetch_status === 'resolved') {\n  console.log(company.company_name, company.registry_tier_delivered);\n} else {\n  console.log('Still processing; retrieve this request later:', requestId);\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Company report returned and billed at the delivered tier. Ownership reports still being prepared can return 202; keep request_id to retrieve their saved decision.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Id of the business session created for this retrieval. The stored record (visible in the console) keeps updating if the registry resolves after the response."
                    },
                    "registry_tier_requested": {
                      "type": "string",
                      "enum": [
                        "basic",
                        "shareholders",
                        "ubo"
                      ],
                      "description": "The tier this endpoint sells: `basic` (Lite) for select, `shareholders`, `ubo`."
                    },
                    "registry_tier_delivered": {
                      "type": "string",
                      "enum": [
                        "basic",
                        "shareholders",
                        "ubo",
                        null
                      ],
                      "description": "The tier actually delivered and billed. Lower than requested when the country's registries hold no ownership data, when the registry has no ownership record for this company, or when the resolved report of a `ubo` request names no natural person as a beneficial owner.",
                      "nullable": true
                    },
                    "kyb_registry": {
                      "type": "object",
                      "description": "Full registry company profile.",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Didit's id for this company record."
                        },
                        "node_id": {
                          "type": "string",
                          "example": "feature_kyb_registry"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "Not Finished",
                            "Approved",
                            "Declined",
                            "In Review"
                          ],
                          "description": "Didit's assessment of the registry check (e.g. `In Review` when the company is not active in the registry or ownership data could not be derived)."
                        },
                        "registry_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "active",
                            "dissolved",
                            "deregistered",
                            "see full details",
                            "authorised",
                            "appointed representative",
                            "unauthorised",
                            "inactive",
                            "no longer authorised",
                            "closed",
                            "struck off",
                            null
                          ],
                          "description": "Normalized company status as reported by the registry."
                        },
                        "data_resolved": {
                          "type": "boolean",
                          "description": "`true` once the registry returned the full profile. `false` when the registry was still processing after polling — the stored record completes automatically once the registry resolves."
                        },
                        "company_name": {
                          "type": "string",
                          "example": "Tesco PLC"
                        },
                        "registration_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "00445790"
                        },
                        "country_code": {
                          "type": "string",
                          "description": "ISO 3166-1 alpha-2.",
                          "example": "GB"
                        },
                        "region": {
                          "type": "string",
                          "nullable": true,
                          "description": "Subdivision code when the registry is regional (e.g. `CA` for `US-CA`); empty otherwise."
                        },
                        "company_type": {
                          "type": "string",
                          "nullable": true,
                          "example": "Public Limited Company"
                        },
                        "incorporation_date": {
                          "type": "string",
                          "format": "date",
                          "nullable": true,
                          "example": "1947-11-27"
                        },
                        "registered_address": {
                          "type": "string",
                          "nullable": true,
                          "example": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA"
                        },
                        "tax_number": {
                          "type": "string",
                          "nullable": true,
                          "example": "GB412 8925 93"
                        },
                        "risk_level": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry-reported risk level, when available."
                        },
                        "verification_status": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry verification status, when available."
                        },
                        "is_from_registry": {
                          "type": "boolean",
                          "description": "Always `true` for this endpoint — the profile was retrieved from an official registry."
                        },
                        "fetch_status": {
                          "type": "string",
                          "enum": [
                            "pending",
                            "resolved"
                          ],
                          "description": "Registry fetch lifecycle. Mirrored by `data_resolved`."
                        },
                        "alternative_names": {
                          "type": "string",
                          "nullable": true,
                          "description": "Alternative, trading, former or original-language company names as text, when reported."
                        },
                        "nature_of_business": {
                          "type": "string",
                          "nullable": true,
                          "description": "Activity description or classification code, when reported."
                        },
                        "registered_capital": {
                          "type": "string",
                          "nullable": true
                        },
                        "registered_capital_amount": {
                          "type": "string",
                          "nullable": true,
                          "description": "Decimal amount as a string, when reported."
                        },
                        "registered_capital_currency": {
                          "type": "string",
                          "nullable": true,
                          "description": "ISO 4217 code, when reported."
                        },
                        "website": {
                          "type": "string",
                          "nullable": true,
                          "example": "https://www.tesco.com/"
                        },
                        "email": {
                          "type": "string",
                          "nullable": true,
                          "example": "customer.service@tesco.co.uk"
                        },
                        "phone": {
                          "type": "string",
                          "nullable": true,
                          "example": "03301231688"
                        },
                        "legal_entity_identifier": {
                          "type": "string",
                          "nullable": true,
                          "description": "LEI, when reported."
                        },
                        "location_of_registration": {
                          "type": "string",
                          "nullable": true,
                          "description": "Registry/jurisdiction the company is registered with, when reported."
                        },
                        "vat_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "EU VAT number, when collected during the hosted registry step or edited afterwards. At select time this is typically not yet set — VAT and tax ID validation runs when the end user submits the registry step in the hosted flow."
                        },
                        "vat_validation_status": {
                          "type": "string",
                          "enum": [
                            "valid",
                            "invalid",
                            "format_valid",
                            "invalid_format",
                            "could_not_validate",
                            "not_applicable"
                          ],
                          "description": "Result of validating the VAT number or, when there is none, the `tax_number`, at registry submit. `valid` / `invalid`: decided by the official registry of the country (EU VIES, Norway, Switzerland, Brazil, Colombia, Costa Rica, Ecuador, Paraguay; Poland also by its domestic VAT register). `format_valid` / `invalid_format`: decided by the country's format and check-digit rules where no registry can be queried. `could_not_validate`: the registry was unavailable. `not_applicable`: no number, a country without registry or rules, or a sandbox session."
                        },
                        "vat_validated_number": {
                          "type": "string",
                          "nullable": true,
                          "description": "The number that was checked, as the source knows it (for example the VAT number derived from a French SIREN or a Dutch RSIN). `null` when no check ran."
                        },
                        "vat_validation_source": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "eu_vies",
                            "pl_vat_white_list",
                            "no_brreg",
                            "ch_uid_register",
                            "br_receita_federal",
                            "co_rues",
                            "cr_hacienda",
                            "ec_sri",
                            "py_dnit",
                            "format_rules",
                            null
                          ],
                          "description": "The source that decided `vat_validation_status`: an official registry, or `format_rules`. `null` when no check ran."
                        },
                        "vat_validated_name": {
                          "type": "string",
                          "nullable": true,
                          "description": "Name registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                        },
                        "vat_validated_address": {
                          "type": "string",
                          "nullable": true,
                          "description": "Address registered with the source that validated the number, when it discloses one. Only set when the status is `valid`."
                        },
                        "vat_checked_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Timestamp of the check. `null` when no check ran."
                        },
                        "financial_summary": {
                          "type": "object",
                          "nullable": true,
                          "description": "Registry-reported share/capital details (currency, total shares, share classes), when available."
                        },
                        "officers": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string",
                                "example": "MELISSA BETHELL"
                              },
                              "designation": {
                                "type": "string",
                                "nullable": true,
                                "description": "Raw registry designation (e.g. `Director`, `Secretary`)."
                              },
                              "role": {
                                "type": "string",
                                "description": "Normalized role derived from the designation. Full 17-value model set; registry parsing on this endpoint typically emits director, non_executive_director, secretary, chairman, or company_officer.",
                                "enum": [
                                  "director",
                                  "non_executive_director",
                                  "secretary",
                                  "chairman",
                                  "ubo",
                                  "shareholder",
                                  "representative",
                                  "founder",
                                  "legal_advisor",
                                  "authorized_signatory",
                                  "trustee",
                                  "beneficiary",
                                  "company_officer",
                                  "settlor",
                                  "protector",
                                  "investor",
                                  "other"
                                ]
                              },
                              "nationality": {
                                "type": "string",
                                "nullable": true
                              },
                              "is_active": {
                                "type": "boolean",
                                "description": "`false` when the registry marks the appointment as resigned."
                              },
                              "kyc_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Approved",
                                  "Declined",
                                  "Pending",
                                  null
                                ],
                                "description": "Status of an associated KYC session, when one was started for this officer. `null` otherwise."
                              },
                              "kyc_session_url": {
                                "type": "string",
                                "nullable": true,
                                "description": "Verification URL of the associated KYC session, when one exists."
                              },
                              "first_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Given name when explicitly reported by the registry; not inferred from the full name."
                              },
                              "last_name": {
                                "type": "string",
                                "nullable": true,
                                "description": "Family name when explicitly reported by the registry."
                              },
                              "address": {
                                "type": "string",
                                "nullable": true,
                                "description": "Officer address reported by the registry."
                              },
                              "appointment_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Date the officer was appointed.",
                                "format": "date"
                              },
                              "termination_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Date the appointment ended, when reported.",
                                "format": "date"
                              },
                              "date_of_birth": {
                                "type": "string",
                                "nullable": true,
                                "description": "Complete registry-reported birth date. Null when only a birth year or month is known.",
                                "format": "date"
                              },
                              "date_of_birth_year": {
                                "type": "integer",
                                "nullable": true,
                                "minimum": 1,
                                "maximum": 9999,
                                "description": "Registry-reported birth year, including when the full date is unavailable."
                              },
                              "date_of_birth_month": {
                                "type": "integer",
                                "nullable": true,
                                "minimum": 1,
                                "maximum": 12,
                                "description": "Registry-reported birth month. Null when only the year is known."
                              }
                            }
                          },
                          "description": "Directors, secretaries, and other officers extracted from the registry."
                        },
                        "beneficial_owners": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "uuid": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string"
                              },
                              "first_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "last_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "entity_type": {
                                "type": "string",
                                "enum": [
                                  "person",
                                  "company"
                                ],
                                "description": "Whether the owner is a natural person or a corporate entity."
                              },
                              "roles": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Normalized roles (e.g. `ubo`, `shareholder`)."
                              },
                              "ownership_min_shares": {
                                "type": "string",
                                "nullable": true,
                                "description": "Lower bound of the ownership band reported by the registry (e.g. `25%`)."
                              },
                              "ownership_max_shares": {
                                "type": "string",
                                "nullable": true,
                                "description": "Upper bound of the ownership band reported by the registry."
                              },
                              "is_active": {
                                "type": "boolean"
                              },
                              "kyc_status": {
                                "type": "string",
                                "nullable": true,
                                "enum": [
                                  "Approved",
                                  "Declined",
                                  "Pending",
                                  null
                                ]
                              },
                              "kyc_session_url": {
                                "type": "string",
                                "nullable": true
                              },
                              "effective_ownership_percent": {
                                "type": "number",
                                "nullable": true,
                                "description": "Parsed ownership percentage (max bound, falling back to min bound)."
                              },
                              "company_name": {
                                "type": "string",
                                "nullable": true
                              },
                              "registration_number": {
                                "type": "string",
                                "nullable": true
                              },
                              "country_of_birth": {
                                "type": "string",
                                "nullable": true
                              },
                              "email": {
                                "type": "string",
                                "nullable": true
                              },
                              "nationality": {
                                "type": "string",
                                "nullable": true
                              },
                              "designation": {
                                "type": "string",
                                "nullable": true
                              },
                              "voting_min_shares": {
                                "type": "string",
                                "nullable": true
                              },
                              "voting_max_shares": {
                                "type": "string",
                                "nullable": true
                              },
                              "date_of_birth": {
                                "type": "string",
                                "nullable": true,
                                "description": "Complete birth date when reported.",
                                "format": "date"
                              },
                              "appointment_date": {
                                "type": "string",
                                "nullable": true,
                                "description": "Appointment date when reported.",
                                "format": "date"
                              },
                              "shareholding": {
                                "$ref": "#/components/schemas/KYBRegistryShareholding"
                              }
                            }
                          },
                          "description": "Beneficial owners / persons with significant control extracted from the registry. Can be empty when the registry does not expose ownership."
                        },
                        "addresses": {
                          "type": "array",
                          "nullable": true,
                          "description": "Every address the registry states, one canonical shape. Null when it states none.",
                          "items": {
                            "$ref": "#/components/schemas/KYBRegistryAddress"
                          }
                        },
                        "industries": {
                          "type": "array",
                          "nullable": true,
                          "description": "The activities the registry classifies the company under, one canonical shape. Null when it states none.",
                          "items": {
                            "$ref": "#/components/schemas/KYBRegistryIndustry"
                          }
                        },
                        "accounts": {
                          "type": "object",
                          "nullable": true,
                          "additionalProperties": true,
                          "description": "Registry filing dates, when available. Annual returns and general meetings use last_annual_return_date and last_agm_date; they are distinct from financial accounts."
                        },
                        "registry_data": {
                          "type": "object",
                          "description": "Raw record returned by the registry source, kept for reviewers. Its shape differs by country and source and is not a stable contract: read the canonical fields (`addresses`, `industries`, `ownership`, `beneficial_owners[].shareholding`) instead."
                        },
                        "user_provided_data": {
                          "type": "object",
                          "nullable": true,
                          "description": "Always `null` on this endpoint (used by the hosted KYB flow when end users edit registry data)."
                        },
                        "confirmed_by_user_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Always `null` on this endpoint."
                        },
                        "last_console_edit_at": {
                          "type": "string",
                          "format": "date-time",
                          "nullable": true,
                          "description": "Set when a console reviewer edits the record later."
                        },
                        "is_editable": {
                          "type": "boolean",
                          "description": "Whether the registry-sourced data can still be edited in the hosted flow/console."
                        },
                        "registry_tier_delivered": {
                          "type": "string",
                          "enum": [
                            "basic",
                            "shareholders",
                            "ubo",
                            null
                          ],
                          "description": "Same as the top-level `registry_tier_delivered`.",
                          "nullable": true
                        },
                        "registry_ownership_status": {
                          "type": "string",
                          "nullable": true,
                          "enum": [
                            "not_requested",
                            "delivered",
                            "unavailable",
                            "pending",
                            null
                          ],
                          "description": "`delivered` when the ownership data came back, `unavailable` when an ownership tier was requested but the registry had none for this company (see `registry_data.ownership_error`), `pending` when the ownership section has not been retrieved from the registry yet and Didit is still completing it, `not_requested` on the Lite tier."
                        },
                        "ownership": {
                          "$ref": "#/components/schemas/KYBRegistryOwnership"
                        },
                        "registry_tier": {
                          "type": "string",
                          "nullable": true,
                          "description": "The registry tier the workflow ordered: `basic`, `shareholders` or `ubo`. Also in `ownership.tier_requested`."
                        }
                      }
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "Echo of the `vendor_data` you sent."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true,
                      "description": "Echo of the `metadata` you sent."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "examples": {
                  "Resolved company": {
                    "summary": "Full registry profile (officer list truncated for brevity)",
                    "value": {
                      "request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
                      "kyb_registry": {
                        "uuid": "f1e2d3c4-b5a6-4789-9c0d-1e2f3a4b5c6d",
                        "node_id": "feature_kyb_registry",
                        "status": "In Review",
                        "registry_status": "active",
                        "data_resolved": true,
                        "company_name": "Tesco PLC",
                        "registration_number": "00445790",
                        "country_code": "GB",
                        "region": "",
                        "company_type": "Public Limited Company",
                        "incorporation_date": "1947-11-27",
                        "registered_address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
                        "tax_number": "GB412 8925 93",
                        "risk_level": "low risk",
                        "verification_status": "verified",
                        "is_from_registry": true,
                        "fetch_status": "resolved",
                        "alternative_names": "TESCO STORES (HOLDINGS) PUBLIC LIMITED COMPANY",
                        "nature_of_business": null,
                        "registered_capital": null,
                        "registered_capital_amount": null,
                        "registered_capital_currency": null,
                        "website": "https://www.tesco.com/",
                        "email": "customer.service@tesco.co.uk",
                        "phone": "03301231688",
                        "legal_entity_identifier": null,
                        "location_of_registration": null,
                        "financial_summary": {
                          "currency": "Pound (£)",
                          "total_number_of_shares": "8174378721",
                          "meta_detail": {
                            "Class_Of_Share": "Ordinary"
                          }
                        },
                        "officers": [
                          {
                            "uuid": "a1b2c3d4-e5f6-4789-9a0b-1c2d3e4f5a6b",
                            "name": "CHRISTOPHER JON TAYLOR",
                            "designation": "Secretary",
                            "role": "secretary",
                            "nationality": null,
                            "is_active": true,
                            "kyc_status": null,
                            "kyc_session_url": null
                          },
                          {
                            "uuid": "b2c3d4e5-f6a7-4890-8b1c-2d3e4f5a6b7c",
                            "name": "MELISSA BETHELL",
                            "designation": "Director",
                            "role": "director",
                            "nationality": "British",
                            "is_active": true,
                            "kyc_status": null,
                            "kyc_session_url": null
                          }
                        ],
                        "beneficial_owners": [],
                        "addresses": [
                          {
                            "address": "Tesco House, Shire Park, Kestrel Way, Welwyn Garden City, United Kingdom, AL7 1GA",
                            "type": "legal_entity_registry_address",
                            "description": "registered office address"
                          }
                        ],
                        "industries": null,
                        "accounts": {
                          "last_account": "26 February 2025",
                          "next_account": "26 February 2026",
                          "due_by_date": "26 August 2026"
                        },
                        "registry_data": {
                          "name": "Tesco PLC",
                          "registration_number": "00445790",
                          "status": "active",
                          "type": "Public Limited Company",
                          "incorporation_date": "1947-11-27",
                          "tax_number": "GB412 8925 93",
                          "country_code": "GB",
                          "fetch_status": "resolved",
                          "industries_detail": [
                            {
                              "code": "47110",
                              "name": "Retail Sale In Non-specialised Stores With Food, Beverages Or Tobacco Predominating",
                              "description": null,
                              "meta_detail": []
                            }
                          ]
                        },
                        "user_provided_data": null,
                        "confirmed_by_user_at": null,
                        "last_console_edit_at": null,
                        "is_editable": true
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:45:00.000000+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error. Field-level problems use DRF's standard envelope.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing kyb_response_id": {
                    "summary": "`kyb_response_id` is required",
                    "value": {
                      "kyb_response_id": [
                        "This field is required."
                      ]
                    }
                  },
                  "save_api_request=false rejected": {
                    "summary": "Selects are always persisted",
                    "value": {
                      "save_api_request": [
                        "KYB registry select must be saved so billing and retrieval can be tracked."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Permission denied. Returned when the `x-api-key` header is missing, malformed, revoked, or belongs to another environment — and also when the calling organization's balance cannot cover the call. Authentication failures return `403` with `{\"detail\": ...}`; this API never returns `401`. Credit shortfalls return `403` with `{\"error\": ...}` before any screening or provider call happens.",
            "content": {
              "application/json": {
                "examples": {
                  "Missing or invalid API key": {
                    "summary": "No `x-api-key` header, or the key is invalid/revoked",
                    "value": {
                      "detail": "You do not have permission to perform this action."
                    }
                  },
                  "Not enough credits": {
                    "summary": "Organization balance cannot cover the call",
                    "value": {
                      "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. All POST/PATCH/DELETE endpoints share a budget of 300 write requests per minute per API key. The response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers.",
            "content": {
              "application/json": {
                "examples": {
                  "Write rate limit exceeded": {
                    "summary": "More than 300 write requests in the current minute",
                    "value": {
                      "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
                    }
                  }
                },
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Report accepted and still processing. When a report is still being prepared, the endpoint returns 202 Accepted, kyb_registry.fetch_status=pending, and registry_tier_delivered=null. Keep request_id and retrieve GET /v3/session/{request_id}/decision/ until registry_checks[0].company.fetch_status is resolved. Didit completes the report automatically and charges the delivered tier once it is ready. Do not repeat the purchase while it is pending; every new POST creates a separate request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/paths/~1v3~1kyb~1ubo~1/post/responses/200/content/application~1json/schema"
                },
                "examples": {
                  "Pending (registry still resolving)": {
                    "summary": "Ownership report is still processing; retrieve the saved decision",
                    "value": {
                      "request_id": "9d4f2c7a-1b3e-4a5c-8d6f-0e9a8b7c6d5e",
                      "kyb_registry": {
                        "uuid": "7c0a4f7e-2b1d-4f6a-9c3e-8d5b2a1f0e9d",
                        "node_id": "feature_kyb_registry",
                        "status": "Not Finished",
                        "registry_status": null,
                        "data_resolved": false,
                        "company_name": "Example Holdings Limited",
                        "registration_number": "12345678",
                        "country_code": "HK",
                        "region": null,
                        "company_type": null,
                        "incorporation_date": null,
                        "registered_address": null,
                        "tax_number": null,
                        "risk_level": null,
                        "verification_status": null,
                        "is_from_registry": true,
                        "fetch_status": "pending",
                        "alternative_names": null,
                        "nature_of_business": null,
                        "registered_capital": null,
                        "registered_capital_amount": null,
                        "registered_capital_currency": null,
                        "website": null,
                        "email": null,
                        "phone": null,
                        "legal_entity_identifier": null,
                        "location_of_registration": null,
                        "financial_summary": {},
                        "officers": [],
                        "beneficial_owners": [],
                        "addresses": null,
                        "industries": null,
                        "accounts": null,
                        "registry_data": {},
                        "user_provided_data": null,
                        "confirmed_by_user_at": null,
                        "last_console_edit_at": null,
                        "is_editable": true,
                        "registry_tier_delivered": null,
                        "registry_ownership_status": "pending"
                      },
                      "vendor_data": "company-1234",
                      "metadata": null,
                      "created_at": "2026-06-11T10:45:00.000000+00:00",
                      "registry_tier_delivered": null,
                      "registry_tier_requested": "ubo"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v3/id-verification/wallets/": {
      "get": {
        "operationId": "list_wallets",
        "description": "Every Digital ID wallet with its start endpoint, countries, required fields and whether this application can start it in this environment now. Listed does not mean live.",
        "summary": "List Digital ID wallets",
        "tags": [
          "Digital ID wallets"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletCatalogResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiClientCredentialsForbiddenErrorMessage"
                }
              }
            },
            "description": "Missing or invalid credentials (x-api-key or Authorization: Bearer)."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url https://verification.didit.me/v3/id-verification/wallets/ \\\n  --header 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"]\n}\n\nresponse = requests.get(\n    \"https://verification.didit.me/v3/id-verification/wallets/\",\n    headers=headers,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ]
      }
    },
    "/v3/id-verification/wallets/verifications/{request_id}/": {
      "get": {
        "operationId": "get_wallet_verification",
        "description": "Status and result of a wallet verification: the normalized identity and the wallet's own attributes once verified, the error code once declined, the next action while pending. A verification past expires_at is decided timeout.",
        "summary": "Get a wallet verification",
        "parameters": [
          {
            "in": "path",
            "name": "request_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The request_id the start endpoint returned.",
            "required": true
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "ftn",
                      "name": "Finnish Trust Network",
                      "issuing_authority": "Finnish banks and mobile operators (FTN)"
                    },
                    "country": "FIN",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiClientCredentialsForbiddenErrorMessage"
                }
              }
            },
            "description": "Missing or invalid credentials (x-api-key or Authorization: Bearer)."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error not_found: no wallet verification of this application has this request_id."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/ \\\n  --header 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"]\n}\n\nresponse = requests.get(\n    \"https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/\",\n    headers=headers,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ]
      }
    },
    "/v3/id-verification/wallets/verifications/{request_id}/poll/": {
      "post": {
        "operationId": "poll_wallet_verification",
        "description": "Smart-ID and Mobile-ID: ask the provider whether the user confirmed, refused or let the prompt lapse, and verify the signed identity when they confirmed. Redirect wallets complete through the user's browser, so for them this only reads the verification back. Answers the verification as it is afterwards.",
        "summary": "Poll a wallet verification",
        "parameters": [
          {
            "in": "path",
            "name": "request_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The request_id the start endpoint returned.",
            "required": true
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "smart_id",
                      "name": "Smart-ID",
                      "issuing_authority": "SK ID Solutions"
                    },
                    "country": "EST",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "in_app",
                    "simulated": true,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "confirm_in_app",
                      "verification_code": "1234",
                      "poll_interval_seconds": 2
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiClientCredentialsForbiddenErrorMessage"
                }
              }
            },
            "description": "Missing or invalid credentials (x-api-key or Authorization: Bearer)."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error not_found: no wallet verification of this application has this request_id."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/poll/ \\\n  --header 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"]\n}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/poll/\",\n    headers=headers,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ]
      }
    },
    "/v3/id-verification/wallets/verifications/{request_id}/cancel/": {
      "post": {
        "operationId": "cancel_wallet_verification",
        "description": "Withdraw a pending verification: it is declined as cancelled and never billed. A decided one is returned unchanged. Smart-ID and Mobile-ID: a cancel that arrives while a poll is checking the sign-in waits a few seconds for that poll, then declines it, or returns it verified if the user had already confirmed. A verification the user is completing right now cannot be cancelled (409 verification_in_progress with Retry-After): retry after that many seconds to read its outcome.",
        "summary": "Cancel a wallet verification",
        "parameters": [
          {
            "in": "path",
            "name": "request_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The request_id the start endpoint returned.",
            "required": true
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "ftn",
                      "name": "Finnish Trust Network",
                      "issuing_authority": "Finnish banks and mobile operators (FTN)"
                    },
                    "country": "FIN",
                    "status": "Declined",
                    "outcome": "cancelled",
                    "error": "cancelled_by_customer",
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": null,
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiClientCredentialsForbiddenErrorMessage"
                }
              }
            },
            "description": "Missing or invalid credentials (x-api-key or Authorization: Bearer)."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error not_found: no wallet verification of this application has this request_id."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error verification_in_progress: the user is completing this sign-in right now. The Retry-After header says when to retry; the retry returns the decided verification."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/cancel/ \\\n  --header 'x-api-key: YOUR_API_KEY'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"]\n}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/cancel/\",\n    headers=headers,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ]
      }
    },
    "/v3/id-verification/wallets/mitid/": {
      "post": {
        "operationId": "start_mitid_wallet_verification",
        "description": "Start a MitID sign-in (Danish Agency for Digital Government; DNK) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start MitID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMitidWalletVerificationStartRequest"
              },
              "example": {
                "country": "DNK",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMitidWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMitidWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "mitid",
                      "name": "MitID",
                      "issuing_authority": "Danish Agency for Digital Government"
                    },
                    "country": "DNK",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/mitid/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"DNK\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'DNK',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/mitid/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "mitid"
      }
    },
    "/v3/id-verification/wallets/bankid-se/": {
      "post": {
        "operationId": "start_bankid_se_wallet_verification",
        "description": "Start a BankID (SWE) sign-in (Finansiell ID-Teknik / bank consortium; SWE) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start BankID (SWE) verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidSeWalletVerificationStartRequest"
              },
              "example": {
                "country": "SWE",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidSeWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidSeWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "bankid_se",
                      "name": "BankID",
                      "issuing_authority": "Finansiell ID-Teknik / bank consortium"
                    },
                    "country": "SWE",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/bankid-se/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"SWE\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'SWE',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/bankid-se/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "bankid_se"
      }
    },
    "/v3/id-verification/wallets/bankid-no/": {
      "post": {
        "operationId": "start_bankid_no_wallet_verification",
        "description": "Start a BankID (NOR) sign-in (BankID BankAxept AS; NOR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start BankID (NOR) verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidNoWalletVerificationStartRequest"
              },
              "example": {
                "country": "NOR",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidNoWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidNoWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "bankid_no",
                      "name": "BankID",
                      "issuing_authority": "BankID BankAxept AS"
                    },
                    "country": "NOR",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/bankid-no/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"NOR\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'NOR',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/bankid-no/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "bankid_no"
      }
    },
    "/v3/id-verification/wallets/vipps/": {
      "post": {
        "operationId": "start_vipps_wallet_verification",
        "description": "Start a Vipps sign-in (Vipps MobilePay / BankID NO; NOR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Vipps verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiVippsWalletVerificationStartRequest"
              },
              "example": {
                "country": "NOR",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiVippsWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiVippsWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "vipps",
                      "name": "Vipps",
                      "issuing_authority": "Vipps MobilePay / BankID NO"
                    },
                    "country": "NOR",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/vipps/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"NOR\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'NOR',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/vipps/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "vipps"
      }
    },
    "/v3/id-verification/wallets/buypass/": {
      "post": {
        "operationId": "start_buypass_wallet_verification",
        "description": "Start a Buypass ID sign-in (Buypass AS; NOR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Buypass ID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBuypassWalletVerificationStartRequest"
              },
              "example": {
                "country": "NOR",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBuypassWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBuypassWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "buypass",
                      "name": "Buypass ID",
                      "issuing_authority": "Buypass AS"
                    },
                    "country": "NOR",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/buypass/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"NOR\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'NOR',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/buypass/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "buypass"
      }
    },
    "/v3/id-verification/wallets/itsme/": {
      "post": {
        "operationId": "start_itsme_wallet_verification",
        "description": "Start a itsme sign-in (Belgian Mobile ID; BEL, LUX, NLD) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start itsme verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiItsmeWalletVerificationStartRequest"
              },
              "example": {
                "country": "BEL",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiItsmeWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiItsmeWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "itsme",
                      "name": "itsme",
                      "issuing_authority": "Belgian Mobile ID"
                    },
                    "country": "BEL",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/itsme/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"BEL\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'BEL',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/itsme/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "itsme"
      }
    },
    "/v3/id-verification/wallets/idin/": {
      "post": {
        "operationId": "start_idin_wallet_verification",
        "description": "Start a iDIN sign-in (Dutch banks (Currence iDIN); NLD) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start iDIN verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdinWalletVerificationStartRequest"
              },
              "example": {
                "country": "NLD",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdinWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdinWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "idin",
                      "name": "iDIN",
                      "issuing_authority": "Dutch banks (Currence iDIN)"
                    },
                    "country": "NLD",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/idin/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"NLD\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'NLD',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/idin/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "idin"
      }
    },
    "/v3/id-verification/wallets/ftn/": {
      "post": {
        "operationId": "start_ftn_wallet_verification",
        "description": "Start a Finnish Trust Network sign-in (Finnish banks and mobile operators (FTN); FIN) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Finnish Trust Network verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFtnWalletVerificationStartRequest"
              },
              "example": {
                "country": "FIN",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFtnWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFtnWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "ftn",
                      "name": "Finnish Trust Network",
                      "issuing_authority": "Finnish banks and mobile operators (FTN)"
                    },
                    "country": "FIN",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/ftn/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"FIN\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'FIN',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/ftn/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "ftn"
      }
    },
    "/v3/id-verification/wallets/personalausweis/": {
      "post": {
        "operationId": "start_personalausweis_wallet_verification",
        "description": "Start a Personalausweis sign-in (Bundesministerium des Innern (eID); DEU) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Personalausweis verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiPersonalausweisWalletVerificationStartRequest"
              },
              "example": {
                "country": "DEU",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiPersonalausweisWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiPersonalausweisWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "personalausweis",
                      "name": "Personalausweis",
                      "issuing_authority": "Bundesministerium des Innern (eID)"
                    },
                    "country": "DEU",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/personalausweis/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"DEU\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'DEU',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/personalausweis/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "personalausweis"
      }
    },
    "/v3/id-verification/wallets/frejaid/": {
      "post": {
        "operationId": "start_frejaid_wallet_verification",
        "description": "Start a Freja eID sign-in (Freja eID Group; SWE) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Freja eID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFrejaidWalletVerificationStartRequest"
              },
              "example": {
                "country": "SWE",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFrejaidWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFrejaidWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "frejaid",
                      "name": "Freja eID",
                      "issuing_authority": "Freja eID Group"
                    },
                    "country": "SWE",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/frejaid/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"SWE\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'SWE',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/frejaid/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "frejaid"
      }
    },
    "/v3/id-verification/wallets/uae-pass/": {
      "post": {
        "operationId": "start_uae_pass_wallet_verification",
        "description": "Start a UAE PASS sign-in (UAE Digital Government Authority; ARE) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start UAE PASS verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiUaePassWalletVerificationStartRequest"
              },
              "example": {
                "country": "ARE",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiUaePassWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiUaePassWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "uae_pass",
                      "name": "UAE PASS",
                      "issuing_authority": "UAE Digital Government Authority"
                    },
                    "country": "ARE",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/uae-pass/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"ARE\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'ARE',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/uae-pass/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "uae_pass"
      }
    },
    "/v3/id-verification/wallets/govbr/": {
      "post": {
        "operationId": "start_govbr_wallet_verification",
        "description": "Start a gov.br sign-in (Governo Federal do Brasil; BRA) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start gov.br verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovbrWalletVerificationStartRequest"
              },
              "example": {
                "country": "BRA",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovbrWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovbrWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "govbr",
                      "name": "gov.br",
                      "issuing_authority": "Governo Federal do Brasil"
                    },
                    "country": "BRA",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/govbr/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"BRA\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'BRA',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/govbr/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "govbr"
      }
    },
    "/v3/id-verification/wallets/oneid/": {
      "post": {
        "operationId": "start_oneid_wallet_verification",
        "description": "Start a OneID sign-in (OneID (UK bank-verified identity); GBR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start OneID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiOneidWalletVerificationStartRequest"
              },
              "example": {
                "country": "GBR",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiOneidWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiOneidWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "oneid",
                      "name": "OneID",
                      "issuing_authority": "OneID (UK bank-verified identity)"
                    },
                    "country": "GBR",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/oneid/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"GBR\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'GBR',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/oneid/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "oneid"
      }
    },
    "/v3/id-verification/wallets/govuk-wallet/": {
      "post": {
        "operationId": "start_govuk_wallet_wallet_verification",
        "description": "Start a GOV.UK Wallet sign-in (UK Government Digital Service; GBR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start GOV.UK Wallet verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovukWalletWalletVerificationStartRequest"
              },
              "example": {
                "country": "GBR",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovukWalletWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovukWalletWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "govuk_wallet",
                      "name": "GOV.UK Wallet",
                      "issuing_authority": "UK Government Digital Service"
                    },
                    "country": "GBR",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/govuk-wallet/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"GBR\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'GBR',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/govuk-wallet/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "govuk_wallet"
      }
    },
    "/v3/id-verification/wallets/smart-id/": {
      "post": {
        "operationId": "start_smart_id_wallet_verification",
        "description": "Start a Smart-ID sign-in (SK ID Solutions; EST, LVA, LTU, BEL) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=confirm_in_app with the comparison code to show the user; the user confirms it and enters their PIN in the app (never collect the PIN). Poll POST /v3/id-verification/wallets/verifications/{request_id}/poll/ every poll_interval_seconds, or rely on the webhook: Didit polls in the background too. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Smart-ID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiSmartIdWalletVerificationStartRequest"
              },
              "example": {
                "country": "EST",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "personal_code": "00000000000"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiSmartIdWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiSmartIdWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "smart_id",
                      "name": "Smart-ID",
                      "issuing_authority": "SK ID Solutions"
                    },
                    "country": "EST",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "in_app",
                    "simulated": true,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "confirm_in_app",
                      "verification_code": "1234",
                      "poll_interval_seconds": 2
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/smart-id/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"EST\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"personal_code\": \"00000000000\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'EST',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'personal_code': '00000000000'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/smart-id/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "smart_id"
      }
    },
    "/v3/id-verification/wallets/mobile-id/": {
      "post": {
        "operationId": "start_mobile_id_wallet_verification",
        "description": "Start a Mobile-ID sign-in (SK ID Solutions with the national mobile operators; EST, LTU) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=confirm_in_app with the comparison code to show the user; the user confirms it and enters their PIN in the app (never collect the PIN). Poll POST /v3/id-verification/wallets/verifications/{request_id}/poll/ every poll_interval_seconds, or rely on the webhook: Didit polls in the background too. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Mobile-ID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMobileIdWalletVerificationStartRequest"
              },
              "example": {
                "country": "EST",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "personal_code": "00000000000",
                "phone_number": "+37200000000"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMobileIdWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMobileIdWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "mobile_id",
                      "name": "Mobile-ID",
                      "issuing_authority": "SK ID Solutions with the national mobile operators"
                    },
                    "country": "EST",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "in_app",
                    "simulated": true,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "confirm_in_app",
                      "verification_code": "1234",
                      "poll_interval_seconds": 2
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/mobile-id/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"EST\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"personal_code\": \"00000000000\",\n  \"phone_number\": \"+37200000000\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'EST',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'personal_code': '00000000000',\n 'phone_number': '+37200000000'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/mobile-id/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "mobile_id"
      }
    },
    "/v3/id-verification/wallets/idcard-ee/": {
      "post": {
        "operationId": "start_idcard_ee_wallet_verification",
        "description": "Start a Estonian ID-card sign-in (Police and Border Guard Board (Estonia); EST) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Estonian ID-card verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdcardEeWalletVerificationStartRequest"
              },
              "example": {
                "country": "EST",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdcardEeWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdcardEeWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "idcard_ee",
                      "name": "Estonian ID-card",
                      "issuing_authority": "Police and Border Guard Board (Estonia)"
                    },
                    "country": "EST",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/idcard-ee/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"EST\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'EST',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/idcard-ee/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "idcard_ee"
      }
    },
    "/v3/id-verification/wallets/eparaksts-mobile/": {
      "post": {
        "operationId": "start_eparaksts_mobile_wallet_verification",
        "description": "Start a eParaksts mobile sign-in (LVRTC (Latvian State Radio and Television Centre); LVA) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start eParaksts mobile verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiEparakstsMobileWalletVerificationStartRequest"
              },
              "example": {
                "country": "LVA",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiEparakstsMobileWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiEparakstsMobileWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "eparaksts_mobile",
                      "name": "eParaksts mobile",
                      "issuing_authority": "LVRTC (Latvian State Radio and Television Centre)"
                    },
                    "country": "LVA",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/eparaksts-mobile/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"LVA\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'LVA',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/eparaksts-mobile/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "eparaksts_mobile"
      }
    },
    "/v3/id-verification/wallets/bankid-cz/": {
      "post": {
        "operationId": "start_bankid_cz_wallet_verification",
        "description": "Start a Bank iD sign-in (Bankovní identita, a.s.; CZE) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Bank iD verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidCzWalletVerificationStartRequest"
              },
              "example": {
                "country": "CZE",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidCzWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiBankidCzWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "bankid_cz",
                      "name": "Bank iD",
                      "issuing_authority": "Bankovní identita, a.s."
                    },
                    "country": "CZE",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/bankid-cz/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"CZE\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'CZE',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/bankid-cz/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "bankid_cz"
      }
    },
    "/v3/id-verification/wallets/mojeid/": {
      "post": {
        "operationId": "start_mojeid_wallet_verification",
        "description": "Start a MojeID sign-in (CZ.NIC; CZE) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start MojeID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMojeidWalletVerificationStartRequest"
              },
              "example": {
                "country": "CZE",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMojeidWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiMojeidWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "mojeid",
                      "name": "MojeID",
                      "issuing_authority": "CZ.NIC"
                    },
                    "country": "CZE",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/mojeid/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"CZE\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'CZE',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/mojeid/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "mojeid"
      }
    },
    "/v3/id-verification/wallets/diia/": {
      "post": {
        "operationId": "start_diia_wallet_verification",
        "description": "Start a Diia sign-in (Ministry of Digital Transformation of Ukraine; UKR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Diia verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiDiiaWalletVerificationStartRequest"
              },
              "example": {
                "country": "UKR",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiDiiaWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiDiiaWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "diia",
                      "name": "Diia",
                      "issuing_authority": "Ministry of Digital Transformation of Ukraine"
                    },
                    "country": "UKR",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/diia/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"UKR\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'UKR',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/diia/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "diia"
      }
    },
    "/v3/id-verification/wallets/franceconnect/": {
      "post": {
        "operationId": "start_franceconnect_wallet_verification",
        "description": "Start a FranceConnect sign-in (DINUM (French state); FRA) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start FranceConnect verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFranceconnectWalletVerificationStartRequest"
              },
              "example": {
                "country": "FRA",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFranceconnectWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiFranceconnectWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "franceconnect",
                      "name": "FranceConnect",
                      "issuing_authority": "DINUM (French state)"
                    },
                    "country": "FRA",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/franceconnect/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"FRA\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'FRA',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/franceconnect/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "franceconnect"
      }
    },
    "/v3/id-verification/wallets/audkenni/": {
      "post": {
        "operationId": "start_audkenni_wallet_verification",
        "description": "Start a Auðkenni sign-in (Auðkenni (Icelandic electronic ID); ISL) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start Auðkenni verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiAudkenniWalletVerificationStartRequest"
              },
              "example": {
                "country": "ISL",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiAudkenniWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiAudkenniWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "audkenni",
                      "name": "Auðkenni",
                      "issuing_authority": "Auðkenni (Icelandic electronic ID)"
                    },
                    "country": "ISL",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/audkenni/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"ISL\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'ISL',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/audkenni/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "audkenni"
      }
    },
    "/v3/id-verification/wallets/connectid/": {
      "post": {
        "operationId": "start_connectid_wallet_verification",
        "description": "Start a ConnectID sign-in (Australian Payments Plus; AUS) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start ConnectID verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiConnectidWalletVerificationStartRequest"
              },
              "example": {
                "country": "AUS",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiConnectidWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiConnectidWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "connectid",
                      "name": "ConnectID",
                      "issuing_authority": "Australian Payments Plus"
                    },
                    "country": "AUS",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/connectid/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"AUS\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'AUS',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/connectid/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "connectid"
      }
    },
    "/v3/id-verification/wallets/eudi/": {
      "post": {
        "operationId": "start_eudi_wallet_verification",
        "description": "Start a EUDI Wallet sign-in (The user's own member state; the issuer differs per country; AUT, BEL, BGR, HRV, CYP, CZE, DNK, EST, FIN, FRA, DEU, GRC, HUN, IRL, ITA, LVA, LTU, LUX, MLT, NLD, POL, PRT, ROU, SVK, SVN, ESP, SWE, ISL, LIE, NOR) without any workflow. Billed once, only when the identity is verified. The response carries next_action.type=redirect with the URL to send the user's browser to; the user returns to return_url with request_id and result appended. Read the outcome with GET /v3/id-verification/wallets/verifications/{request_id}/ or from the webhook, never from the URL. Sandbox applications get a deterministic simulation (simulated: true) that never contacts the provider.",
        "summary": "Start EUDI Wallet verification",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string"
            },
            "description": "Optional retry-safety key (max 255 characters). Retrying with the same key, wallet and body returns the original verification without starting a second sign-in; the same key with another wallet or body returns 409 idempotency_key_reused."
          }
        ],
        "tags": [
          "Digital ID wallets"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiEudiWalletVerificationStartRequest"
              },
              "example": {
                "country": "AUT",
                "vendor_data": "your-customer-reference",
                "metadata": {
                  "reference": "example"
                },
                "return_url": "https://app.example.com/identity/complete"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiEudiWalletVerificationStartRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/DigitalIdWalletApiEudiWalletVerificationStartRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResponse"
                },
                "example": {
                  "request_id": "00000000-0000-4000-8000-000000000001",
                  "wallet_verification": {
                    "wallet": {
                      "id": "eudi",
                      "name": "EUDI Wallet",
                      "issuing_authority": "The user's own member state; the issuer differs per country"
                    },
                    "country": "AUT",
                    "status": "Not Finished",
                    "outcome": "pending",
                    "error": null,
                    "interaction": "redirect",
                    "simulated": false,
                    "expires_at": "2026-01-01T10:10:00Z",
                    "next_action": {
                      "type": "redirect",
                      "url": "https://wallet.example.com/authorize"
                    },
                    "identity": null,
                    "attributes": null,
                    "level_of_assurance": null,
                    "verified_at": null,
                    "signature_valid": null,
                    "credential_type": "person_identification"
                  },
                  "vendor_data": "your-customer-reference",
                  "metadata": {
                    "reference": "example"
                  },
                  "created_at": "2026-01-01T10:00:00Z"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartBadRequest"
                }
              }
            },
            "description": "Field validation errors ({field: [messages]}), or error return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number or idempotency_key_invalid."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationStartForbidden"
                }
              }
            },
            "description": "Missing or invalid credentials ({detail}), or error wallet_unavailable, insufficient_credits or contract_rate_missing."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error idempotency_key_reused or idempotency_key_in_progress (with Retry-After)."
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_provider_unavailable: the provider could not start; nothing was created."
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
                }
              }
            },
            "description": "error wallet_not_configured: this environment cannot reach the wallet."
          }
        },
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url https://verification.didit.me/v3/id-verification/wallets/eudi/ \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'Idempotency-Key: your-unique-attempt-key' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n  \"country\": \"AUT\",\n  \"vendor_data\": \"your-customer-reference\",\n  \"metadata\": {\n    \"reference\": \"example\"\n  },\n  \"return_url\": \"https://app.example.com/identity/complete\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nheaders = {\n    \"x-api-key\": os.environ[\"DIDIT_API_KEY\"],\n    \"Idempotency-Key\": \"your-unique-attempt-key\"\n}\npayload = {'country': 'AUT',\n 'vendor_data': 'your-customer-reference',\n 'metadata': {'reference': 'example'},\n 'return_url': 'https://app.example.com/identity/complete'}\n\nresponse = requests.post(\n    \"https://verification.didit.me/v3/id-verification/wallets/eudi/\",\n    headers=headers,\n    json=payload,\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"
          }
        ],
        "x-didit-wallet-id": "eudi"
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/teams/": {
      "get": {
        "summary": "List review teams",
        "description": "Requires `list:cases` for the requested application.",
        "operationId": "list_case_teams",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CaseReviewTeam"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Matching count, capped at 100. Follow next to continue beyond the cap."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          }
        }
      },
      "post": {
        "summary": "Create review team",
        "description": "Requires `write:cases` for the requested application.",
        "operationId": "create_case_teams",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseReviewTeam"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseReviewTeamCreate"
              }
            }
          }
        }
      }
    },
    "/v3/fraud/checks/{check_id}/": {
      "get": {
        "operationId": "root_retrieve",
        "description": "Fetch a previously created check by its `check_id`.",
        "summary": "Retrieve a Fraud Check",
        "parameters": [
          {
            "in": "path",
            "name": "check_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudCheckResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudClientCredentialsErrorMessage"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudClientCredentialsForbiddenErrorMessage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "tags": [
          "Fraud Check"
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/requests/": {
      "get": {
        "operationId": "organization_application_cases_requests_list",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "description": "The initial index from which to return the results.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingPaginatedCaseRequestList"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "post": {
        "operationId": "organization_application_cases_requests_create",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseRequestConfirmRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseRequestConfirmRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseRequestConfirmRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "400": {
            "description": "Invalid inputs, unsupported purpose, unavailable verified contact or an existing immutable response."
          },
          "409": {
            "description": "The preview changed or expired. Preview again before confirming."
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingCaseRequest"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Confirm the exact signed preview within 15 minutes. Only fixed templates and an OTP-verified contact belonging to the case subject are accepted. The request ID makes retries idempotent. Delivery is queued; SENT, SIMULATED and UNKNOWN are distinct outcomes. An actionable request sets the case to Awaiting user. A review update leaves its status unchanged."
      }
    },
    "/v3/fraud/checks/": {
      "post": {
        "operationId": "create_fraud_check",
        "description": "Submit one or more typed identifiers and receive normalization, fresh enrichment, authoritative validation where the country and identifier type are covered, independent risk dimensions and a recommendation in one response.\n\nThese profiles support identifier checks. Selfie-based identity binding (`biometric_identity`) requires profile version `2026-09-14.2` and a Brazilian CPF; it runs only with the user's consent and when your organization is entitled to it. Earlier versions report it as `not_available_in_profile_version`. Modules that cannot run are reported as skipped with a deterministic reason; a source that could not answer is never reported as an identity mismatch.",
        "summary": "Run a Fraud Check",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FraudCheckRequestRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FraudCheckRequestRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FraudCheckRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudCheckResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudClientCredentialsErrorMessage"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudClientCredentialsForbiddenErrorMessage"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "Conflict, returned without a charge: the `client_reference` was already used with a different request body; a check with the same `client_reference` is still running (retry after `Retry-After` seconds with the same reference); or the verification this check records into was deleted before the check completed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "error"
                  ]
                },
                "examples": {
                  "different_body": {
                    "summary": "Reference reused with a different body",
                    "value": {
                      "error": "client_reference has already been used with a different request body."
                    }
                  },
                  "still_running": {
                    "summary": "A check with this reference is still running",
                    "value": {
                      "error": "A check with this client_reference is already running. Retry with the same reference later."
                    }
                  },
                  "verification_deleted": {
                    "summary": "The verification was deleted before the check completed",
                    "value": {
                      "error": "This verification was deleted before the check completed."
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, sent when a check with the same `client_reference` is still running.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "tags": [
          "Fraud Check"
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/requests/{request_uuid}/cancel/": {
      "post": {
        "operationId": "organization_application_cases_requests_cancel_create",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "request_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingCaseRequest"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "400": {
            "description": "Invalid inputs, unsupported purpose, unavailable verified contact or an existing immutable response."
          },
          "409": {
            "description": "The preview changed or expired. Preview again before confirming."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/requests/options/": {
      "get": {
        "operationId": "organization_application_cases_requests_options_retrieve",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingCaseRequestOptions"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/requests/{request_uuid}/attachment/": {
      "get": {
        "operationId": "organization_application_cases_requests_attachment_retrieve",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "request_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/routing-rules/{record_uuid}/history/": {
      "get": {
        "operationId": "list_case_routing_rule_history",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "record_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "description": "The initial index from which to return the results.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "history"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutingPublicationPaginatedPolicyRevisionList"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "Case access is required."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/session/{sessionId}/resubmission-preview/": {
      "post": {
        "summary": "Preview a resubmission email",
        "description": "Render the email that would accompany a KYC or KYB resubmission without changing the session, resetting checks, extending its expiry, running checks or sending mail. Requires write:sessions and an application-scoped session in Approved, Declined, In Review, Kyc Expired or Abandoned status. The server validates the selected workflow steps and renders its fixed translated template with the applicable verified white-label sender and branding. The request cannot set a subject, message body or action URL.\n\nThe response includes the recipient, sender, subject, HTML, resolved steps and a signed preview_token. requires_user_action describes whether the selected steps include an interactive check. Email delivery remains conditional: if automatic checks finalize the verification during the subsequent resubmission, no action-request email is sent.\n\nThis preview does not reserve session state or authorize delivery. After reviewing it, call Update Session Status with new_status=Resubmitted, the same selection, recipient and language, and email_preview_token set to the returned preview_token. The receipt expires after 15 minutes. When a receipt is supplied, changed inputs, message content, sender or session state return 409 before any mutation or send. Existing integrations may omit the receipt. Regenerate the preview after a conflict. Treat the response as sensitive verification content; responses use Cache-Control: no-store. Render HTML in a sandboxed frame, never directly in your application DOM.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "sessionId",
            "required": true,
            "description": "UUID of the verification session to update. Accepts both user (KYC) and business (KYB) session IDs — the service resolves the ID across both session types.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "example": "11111111-2222-3333-4444-555555555555"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email_address"
                ],
                "properties": {
                  "nodes_to_resubmit": {
                    "type": "array",
                    "description": "Steps to preview, using the same validation, selection and workflow ordering as a resubmission. Omit to auto-select recorded attempts needing resubmission.",
                    "items": {
                      "type": "object",
                      "required": [
                        "node_id",
                        "feature"
                      ],
                      "properties": {
                        "node_id": {
                          "type": "string",
                          "description": "Node identifier as it appears in the session's workflow definition (for example `feature_ocr`, `feature_liveness`).",
                          "example": "feature_ocr"
                        },
                        "feature": {
                          "type": "string",
                          "description": "Feature type of the node. The aliases `ID_VERIFICATION`, `POA`, `PHONE`, and `EMAIL` are normalized server-side to `OCR`, `PROOF_OF_ADDRESS`, `PHONE_VERIFICATION`, and `EMAIL_VERIFICATION`. `KYB_REGISTRY`, `KYB_KEY_PEOPLE`, and `KYB` pass schema validation but are always rejected with the business-rule `400` shown in the examples.",
                          "enum": [
                            "OCR",
                            "OCR_BACK",
                            "NFC",
                            "AML",
                            "FACE",
                            "LIVENESS",
                            "FACE_MATCH",
                            "IP_ANALYSIS",
                            "AGE_ESTIMATION",
                            "PROOF_OF_ADDRESS",
                            "PHONE_VERIFICATION",
                            "EMAIL_VERIFICATION",
                            "FACE_SEARCH",
                            "DATABASE_VALIDATION",
                            "QUESTIONNAIRE",
                            "DOCUMENT_AI",
                            "KYB_DOCUMENTS",
                            "ID_VERIFICATION",
                            "POA",
                            "PHONE",
                            "EMAIL",
                            "KYB_REGISTRY",
                            "KYB_KEY_PEOPLE",
                            "KYB"
                          ],
                          "example": "OCR"
                        }
                      }
                    }
                  },
                  "email_address": {
                    "type": "string",
                    "format": "email",
                    "description": "Recipient shown in the preview. No email is sent.",
                    "example": "user@example.com"
                  },
                  "email_language": {
                    "type": "string",
                    "description": "Language for the notification email. Accepts any string at schema level; unsupported codes silently fall back to English (`en`).",
                    "default": "en",
                    "example": "en"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview only. The session is unchanged and no email is sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "recipient",
                    "sender",
                    "subject",
                    "html",
                    "nodes_to_resubmit",
                    "requires_user_action",
                    "preview_token"
                  ],
                  "properties": {
                    "recipient": {
                      "type": "string",
                      "format": "email"
                    },
                    "sender": {
                      "type": "string"
                    },
                    "subject": {
                      "type": "string"
                    },
                    "html": {
                      "type": "string",
                      "description": "Rendered email. Inline image attachments use data URLs for preview."
                    },
                    "nodes_to_resubmit": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "node_id",
                          "feature"
                        ],
                        "properties": {
                          "node_id": {
                            "type": "string",
                            "description": "Node identifier as it appears in the session's workflow definition (for example `feature_ocr`, `feature_liveness`).",
                            "example": "feature_ocr"
                          },
                          "feature": {
                            "type": "string",
                            "description": "Feature type of the node. The aliases `ID_VERIFICATION`, `POA`, `PHONE`, and `EMAIL` are normalized server-side to `OCR`, `PROOF_OF_ADDRESS`, `PHONE_VERIFICATION`, and `EMAIL_VERIFICATION`. `KYB_REGISTRY`, `KYB_KEY_PEOPLE`, and `KYB` pass schema validation but are always rejected with the business-rule `400` shown in the examples.",
                            "enum": [
                              "OCR",
                              "OCR_BACK",
                              "NFC",
                              "AML",
                              "FACE",
                              "LIVENESS",
                              "FACE_MATCH",
                              "IP_ANALYSIS",
                              "AGE_ESTIMATION",
                              "PROOF_OF_ADDRESS",
                              "PHONE_VERIFICATION",
                              "EMAIL_VERIFICATION",
                              "FACE_SEARCH",
                              "DATABASE_VALIDATION",
                              "QUESTIONNAIRE",
                              "DOCUMENT_AI",
                              "KYB_DOCUMENTS",
                              "ID_VERIFICATION",
                              "POA",
                              "PHONE",
                              "EMAIL",
                              "KYB_REGISTRY",
                              "KYB_KEY_PEOPLE",
                              "KYB"
                            ],
                            "example": "OCR"
                          }
                        }
                      }
                    },
                    "requires_user_action": {
                      "type": "boolean",
                      "description": "Whether at least one selected check requires user interaction. This does not predict the final workflow outcome."
                    },
                    "preview_token": {
                      "type": "string",
                      "description": "Signed confirmation receipt, valid for 15 minutes. Pass it as email_preview_token when confirming the same message."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid email, state or workflow selection."
          },
          "403": {
            "description": "Authentication or write:sessions permission is missing."
          },
          "404": {
            "description": "No session exists in the requested application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/routing-rules/{record_uuid}/": {
      "get": {
        "summary": "Retrieve routing rule",
        "description": "Requires `read:cases` for the requested application.",
        "operationId": "retrieve_case_routing_rules",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "record_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseRoutingRule"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          },
          "404": {
            "description": "Record not found in this application."
          }
        }
      },
      "patch": {
        "summary": "Update routing rule",
        "description": "Requires `write:cases` for the requested application.",
        "operationId": "update_case_routing_rules",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "record_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseRoutingRule"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          },
          "404": {
            "description": "Record not found in this application."
          },
          "409": {
            "description": "The routing rule changed since expected_version. Review the latest rule before retrying."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseRoutingRuleUpdate"
              }
            }
          }
        }
      }
    },
    "/v3/case-requests/{request_uuid}/": {
      "get": {
        "operationId": "case_requests_retrieve",
        "parameters": [
          {
            "in": "path",
            "name": "request_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingCaseRequestPublic"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          }
        },
        "security": [
          {
            "CaseRequestToken": []
          }
        ],
        "description": "Access one customer request using its request-specific token. No private case findings, original identity data or recipient address are returned. Actionable requests expire after seven days. Cancellation or case resolution invalidates the link. Responses are immutable and remain evidence for reviewer assessment; they never approve or update a source verification."
      },
      "post": {
        "operationId": "case_requests_create",
        "parameters": [
          {
            "in": "path",
            "name": "request_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseCustomerResponseRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseCustomerResponseRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingCaseCustomerResponseResult"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "400": {
            "description": "Invalid inputs, unsupported purpose, unavailable verified contact or an existing immutable response."
          },
          "409": {
            "description": "The preview changed or expired. Preview again before confirming."
          }
        },
        "security": [
          {
            "CaseRequestToken": []
          }
        ],
        "description": "Access one customer request using its request-specific token. No private case findings, original identity data or recipient address are returned. Actionable requests expire after seven days. Cancellation or case resolution invalidates the link. Responses are immutable and remain evidence for reviewer assessment; they never approve or update a source verification."
      }
    },
    "/v3/fraud/checks/plan/": {
      "post": {
        "operationId": "plan_create",
        "description": "Validate selected checks and estimate their price without executing, creating a session or billing.",
        "summary": "Plan a Fraud Check",
        "tags": [
          "Fraud Check"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FraudCheckRequestRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FraudCheckRequestRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FraudCheckRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudCheckPlan"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FraudBadRequestErrorMessage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/routing-rules/": {
      "get": {
        "summary": "List routing rules",
        "description": "Requires `list:cases` for the requested application.",
        "operationId": "list_case_routing_rules",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CaseRoutingRule"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Matching count, capped at 100. Follow next to continue beyond the cap."
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          }
        }
      },
      "post": {
        "summary": "Create routing rule",
        "description": "Requires `write:cases` for the requested application. Set publish=false to create an unpublished draft; Publish creates its first live version. Discarding a never-published draft deletes it.",
        "operationId": "create_case_routing_rules",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseRoutingRule"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseRoutingRuleCreate"
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/routing-rules/{record_uuid}/publish/": {
      "post": {
        "operationId": "publish_case_routing_rule",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "record_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "publish"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftPreconditionRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftPreconditionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftPreconditionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutingPublicationCaseRoutingRule"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "Case access is required."
          },
          "409": {
            "description": "The published version or draft revision has changed. Reload before retrying."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/{blueprint_uuid}/publish/": {
      "post": {
        "operationId": "publish_case_blueprint",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "blueprint_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftPreconditionRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftPreconditionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftPreconditionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CasePublicationCaseBlueprint"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "Published version or saved draft revision changed. Reload before retrying."
          },
          "403": {
            "description": "Required case permission is missing."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/requests/preview/": {
      "post": {
        "operationId": "organization_application_cases_requests_preview_create",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseRequestPreviewRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseRequestPreviewRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CustomerMessagingCaseRequestPreviewRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerMessagingCaseRequestPreviewResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "The request or case is unavailable for this caller."
          },
          "403": {
            "description": "The caller lacks the required cases permission."
          },
          "400": {
            "description": "Invalid inputs, unsupported purpose, unavailable verified contact or an existing immutable response."
          },
          "409": {
            "description": "The preview changed or expired. Preview again before confirming."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Render the production email without sending or changing the case. Returns the exact recipient, sender, subject, body and a signed preview_token. Send the same contact_id, purpose, language, request_id, expires_at and preview_token to confirm within 15 minutes."
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/action-receipts/": {
      "get": {
        "operationId": "action_receipts_retrieve",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer",
              "maximum": 1000000,
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseActionCaseActionReceiptPage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "List subject-action receipts, newest first, with at most 20 results per page. Use next_offset for the next page. Input note text is not exposed in the history."
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/notes/{note_uuid}/": {
      "delete": {
        "operationId": "delete_network_note",
        "tags": [
          "Networks"
        ],
        "summary": "Delete your network note",
        "description": "Requires write:networks and the authenticated author of the note. Deletion is irreversible. Connected account and verification data are unaffected.",
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Network UUID."
          },
          {
            "name": "note_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Console user access token in the form Bearer <token>."
          }
        ],
        "responses": {
          "204": {
            "description": "Note deleted."
          },
          "401": {
            "description": "Authentication is required."
          },
          "403": {
            "description": "Missing permission or Networks access."
          },
          "404": {
            "description": "Network or note is not visible to this application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/{case_uuid}/action-receipts/{receipt_uuid}/retry/": {
      "post": {
        "operationId": "action_receipts_retry_create",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "case_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "receipt_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseActionCaseActionReceipt"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Retry only this failed subject action using its saved inputs. Current write permission is checked. Applied actions return their receipt without executing again. Case closure is independent."
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/{blueprint_uuid}/draft/": {
      "get": {
        "operationId": "get_case_blueprint_draft",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "blueprint_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CasePublicationPolicyDraftResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "Required case permission is missing."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "put": {
        "operationId": "save_case_blueprint_draft",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "blueprint_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftWriteRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftWriteRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftWriteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CasePublicationPolicyDraft"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "Published version or saved draft revision changed. Reload before retrying."
          },
          "403": {
            "description": "Required case permission is missing."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "delete": {
        "operationId": "discard_case_blueprint_draft",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "blueprint_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "204": {
            "description": "No response body"
          },
          "409": {
            "description": "Published version or saved draft revision changed. Reload before retrying."
          },
          "403": {
            "description": "Required case permission is missing."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CasePublicationPolicyDraftPreconditionRequest"
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/teams/{record_uuid}/": {
      "get": {
        "summary": "Retrieve review team",
        "description": "Requires `read:cases` for the requested application.",
        "operationId": "retrieve_case_teams",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "record_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseReviewTeam"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          },
          "404": {
            "description": "Record not found in this application."
          }
        }
      },
      "patch": {
        "summary": "Update review team",
        "description": "Requires `write:cases` for the requested application.",
        "operationId": "update_case_teams",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "record_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseReviewTeam"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          },
          "404": {
            "description": "Record not found in this application."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseReviewTeamUpdate"
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/report/": {
      "get": {
        "operationId": "download_network_report",
        "tags": [
          "Networks"
        ],
        "summary": "Download a network evidence report",
        "description": "Download a PDF of the current organization network, its observed account connections, signal references and review status. Requires read:networks. Global intelligence and private analyst notes are not included. Each account and signal list is capped at 500 entries and the report states when it is incomplete. The request does not change network status. Errors are returned as JSON.",
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Network UUID."
          },
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Console user access token in the form Bearer <token>."
          }
        ],
        "responses": {
          "200": {
            "description": "Network evidence report. Cache-Control: no-store.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Authentication is required."
          },
          "403": {
            "description": "Missing permission or Networks access."
          },
          "404": {
            "description": "Network or note is not visible to this application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/networks/{network_uuid}/notes/": {
      "get": {
        "operationId": "list_network_notes",
        "tags": [
          "Networks"
        ],
        "summary": "List private network notes",
        "description": "Console users with read:networks can read notes on a network visible to the application. Notes stay within the organization and are not contributed to shared intelligence. Newest notes appear first.",
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Network UUID."
          },
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Console user access token in the form Bearer <token>."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 1000000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of notes. Count is capped at 100; use next to continue.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous": {
                      "type": "string",
                      "nullable": true
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NetworkNote"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Authentication is required."
          },
          "403": {
            "description": "Missing permission or Networks access."
          },
          "404": {
            "description": "Network or note is not visible to this application."
          }
        }
      },
      "post": {
        "operationId": "create_network_note",
        "tags": [
          "Networks"
        ],
        "summary": "Add a private network note",
        "description": "Requires a console user with write:networks. The author is assigned from the authenticated user. Supply a new random UUID client_reference for each note; retry the same body and reference after an uncertain response to avoid duplicates. Reusing a reference for another body, author or network returns 409. Notes follow the surviving investigation when networks merge.",
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          },
          {
            "name": "network_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Network UUID."
          },
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Console user access token in the form Bearer <token>."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "comment",
                  "client_reference"
                ],
                "properties": {
                  "comment": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10000
                  },
                  "client_reference": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved private note.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkNote"
                }
              }
            }
          },
          "200": {
            "description": "Saved private note.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkNote"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or blank note."
          },
          "409": {
            "description": "The reference was already used for another note."
          },
          "401": {
            "description": "Authentication is required."
          },
          "403": {
            "description": "Missing permission or Networks access."
          },
          "404": {
            "description": "Network or note is not visible to this application."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/routing-rules/{record_uuid}/draft/": {
      "get": {
        "operationId": "get_case_routing_rule_draft",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "record_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "draft"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutingPublicationPolicyDraftResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "Case access is required."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "put": {
        "operationId": "save_case_routing_rule_draft",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "record_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "draft"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftWriteRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftWriteRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftWriteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoutingPublicationPolicyDraft"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "Case access is required."
          },
          "409": {
            "description": "The published version or draft revision has changed. Reload before retrying."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      },
      "delete": {
        "operationId": "discard_case_routing_rule_draft",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "record_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "draft"
        ],
        "responses": {
          "204": {
            "description": "No response body"
          },
          "403": {
            "description": "Case access is required."
          },
          "409": {
            "description": "The published version or draft revision has changed. Reload before retrying."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraftPreconditionRequest"
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/duplicates/": {
      "post": {
        "operationId": "duplicates_create",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          }
        ],
        "tags": [
          "Case Management"
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CaseDuplicateCaseDuplicateQueryRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseDuplicateCaseDuplicateQueryRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CaseDuplicateCaseDuplicateQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseDuplicateCaseDuplicatePage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "description": "Review existing cases for a subject or owned source record before manual case creation. Both open and resolved investigations are returned. Each page contains at most 20 cases; use next_offset to request another page."
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/routing-rules/preview/": {
      "post": {
        "summary": "Test case routing",
        "description": "Requires `read:cases` for the requested application. Evaluates current rules or a supplied draft against current reviewer access, availability, skills and capacity. It does not save the draft or reserve reviewer capacity.",
        "operationId": "preview_case_routing",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseRoutingPreview"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CaseRoutingPreviewRequest"
              }
            }
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/reviewers/": {
      "get": {
        "summary": "List eligible case reviewers",
        "description": "Requires `list:cases` for the requested application.",
        "operationId": "list_case_reviewers",
        "tags": [
          "Case Assignment"
        ],
        "parameters": [
          {
            "name": "organization_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Organization UUID."
          },
          {
            "name": "application_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Application UUID."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "email": {
                            "type": "string",
                            "format": "email"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input."
          },
          "403": {
            "description": "Insufficient permission."
          },
          "503": {
            "description": "Reviewer access could not be verified. Retry later."
          }
        }
      }
    },
    "/v3/organization/{organization_id}/application/{application_id}/cases/blueprints/{blueprint_uuid}/history/": {
      "get": {
        "operationId": "list_case_blueprint_history",
        "parameters": [
          {
            "in": "path",
            "name": "organization_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "application_id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "blueprint_uuid",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "required": false,
            "in": "query",
            "description": "The initial index from which to return the results.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "tags": [
          "Case Management"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CasePublicationPaginatedPolicyRevisionList"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "Required case permission is missing."
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "DocumentAIDetectedCode": {
        "type": "object",
        "required": [
          "type",
          "page_number",
          "position",
          "x",
          "y",
          "width",
          "height",
          "page_width",
          "page_height",
          "raw_payload",
          "parsed_payload"
        ],
        "properties": {
          "type": {
            "type": "string",
            "description": "Detected symbology, for example `QR_CODE`, `CODE_128`, `EAN_13`, `DATA_MATRIX`, or `PDF_417`."
          },
          "page_number": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based page number."
          },
          "position": {
            "type": "array",
            "nullable": true,
            "description": "Detected polygon in rendered-page pixel coordinates. `null` when no reliable location is available.",
            "items": {
              "type": "array",
              "minItems": 2,
              "maxItems": 2,
              "items": {
                "type": "integer"
              }
            }
          },
          "x": {
            "type": "integer",
            "nullable": true,
            "description": "Left edge of the bounding box in rendered-page pixels."
          },
          "y": {
            "type": "integer",
            "nullable": true,
            "description": "Top edge of the bounding box in rendered-page pixels."
          },
          "width": {
            "type": "integer",
            "nullable": true,
            "description": "Bounding-box width in rendered-page pixels."
          },
          "height": {
            "type": "integer",
            "nullable": true,
            "description": "Bounding-box height in rendered-page pixels."
          },
          "page_width": {
            "type": "integer",
            "description": "Rendered page width in pixels."
          },
          "page_height": {
            "type": "integer",
            "description": "Rendered page height in pixels."
          },
          "raw_payload": {
            "type": "string",
            "description": "Raw decoder payload as a base64 string when available; otherwise an empty string."
          },
          "parsed_payload": {
            "nullable": true,
            "description": "Decoded string or structured value. `null` when the code was located but could not be decoded."
          }
        }
      },
      "SessionImportJob": {
        "type": "object",
        "required": [
          "uuid",
          "status",
          "import_type",
          "source_format",
          "source_filename",
          "total_rows",
          "processed_rows",
          "created_count",
          "updated_count",
          "skipped_count",
          "failed_count"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "Import job id. Use this value to poll progress and fetch row errors."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "PROCESSING",
              "COMPLETED",
              "FAILED",
              "PAUSED",
              "CANCELLED"
            ]
          },
          "import_type": {
            "type": "string",
            "enum": [
              "user_verification",
              "business_verification",
              "status_rules",
              "transactions"
            ]
          },
          "source_format": {
            "type": "string",
            "enum": [
              "csv",
              "ndjson"
            ]
          },
          "source_filename": {
            "type": "string"
          },
          "total_rows": {
            "type": "integer",
            "format": "int64"
          },
          "processed_rows": {
            "type": "integer",
            "format": "int64"
          },
          "checkpoint_row": {
            "type": "integer",
            "format": "int64"
          },
          "created_count": {
            "type": "integer",
            "format": "int64"
          },
          "updated_count": {
            "type": "integer",
            "format": "int64"
          },
          "skipped_count": {
            "type": "integer",
            "format": "int64"
          },
          "failed_count": {
            "type": "integer",
            "format": "int64"
          },
          "total_media_bytes": {
            "type": "integer",
            "format": "int64"
          },
          "last_error": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "SessionImportError": {
        "type": "object",
        "required": [
          "uuid",
          "row_number",
          "error",
          "raw_row"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "row_number": {
            "type": "integer",
            "format": "int64"
          },
          "external_id": {
            "type": "string",
            "nullable": true
          },
          "error": {
            "type": "string"
          },
          "raw_row": {
            "type": "object",
            "additionalProperties": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BrandingCustomizationUpdate": {
        "type": "object",
        "description": "Partial branding update body. Provide only the fields you want to change. Hex colors accept `#RRGGBB` or `#RRGGBBAA`. Custom domain and white-label email are not accepted here.",
        "properties": {
          "color_primary": {
            "type": "string",
            "description": "Headers / primary text color."
          },
          "color_secondary": {
            "type": "string",
            "description": "Paragraph / secondary text color."
          },
          "color_background": {
            "type": "string",
            "description": "Page background color."
          },
          "color_panel": {
            "type": "string",
            "description": "Panel / accent color."
          },
          "color_panel_10": {
            "type": "string",
            "description": "Panel color at 10% opacity."
          },
          "color_on_panel_1": {
            "type": "string",
            "description": "Support text color on panels."
          },
          "color_on_panel_2": {
            "type": "string",
            "description": "Pill / badge color on panels."
          },
          "color_on_background": {
            "type": "string",
            "description": "Text color on background."
          },
          "color_button_1": {
            "type": "string",
            "description": "Primary button color."
          },
          "color_button_2": {
            "type": "string",
            "description": "Secondary button color."
          },
          "color_button_text_1": {
            "type": "string",
            "description": "Primary button text color."
          },
          "color_button_text_2": {
            "type": "string",
            "description": "Secondary button text color."
          },
          "color_pill_text": {
            "type": "string",
            "description": "Text color for pills, inputs and selectors."
          },
          "border_radius_panel": {
            "type": "integer",
            "minimum": 0,
            "description": "Panel corner radius in pixels."
          },
          "border_radius_buttons": {
            "type": "integer",
            "minimum": 0,
            "description": "Button corner radius in pixels."
          },
          "font_family": {
            "type": "string",
            "description": "Google Font family name (e.g. `Inter`, `AR One Sans`)."
          },
          "font_weight": {
            "type": "string",
            "description": "Font weight available for the selected family (e.g. `regular`, `500`, `700`)."
          },
          "app_public_name": {
            "type": "string",
            "nullable": true,
            "description": "Public name shown in the verification flow."
          },
          "privacy_policy_url": {
            "type": "string",
            "nullable": true,
            "description": "Privacy policy URL shown to the end user."
          },
          "skip_welcome_screen": {
            "type": "boolean",
            "description": "Skip the initial welcome screen."
          },
          "disable_login_with_didit": {
            "type": "boolean",
            "description": "Continue as guest instead of showing the login-with-Didit screen. Cannot be set back to `false` while a custom domain is configured (400)."
          },
          "hide_progress_bar": {
            "type": "boolean",
            "description": "Hide the progress bar during the flow."
          },
          "callback_seconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Delay (seconds) before redirecting to the callback URL."
          },
          "delete_logo_square": {
            "type": "boolean",
            "description": "When `true`, removes the current square logo."
          },
          "delete_logo_rectangular": {
            "type": "boolean",
            "description": "When `true`, removes the current rectangular logo."
          },
          "delete_favicon": {
            "type": "boolean",
            "description": "When `true`, removes the current favicon."
          }
        }
      },
      "BrandingCustomization": {
        "type": "object",
        "description": "White-label branding for an application: colors, fonts, radii, logo URLs and UI/UX options. Logo URLs are read-only (set them by uploading images). Custom domain and white-label email are not included.",
        "properties": {
          "color_primary": {
            "type": "string"
          },
          "color_secondary": {
            "type": "string"
          },
          "color_background": {
            "type": "string"
          },
          "color_panel": {
            "type": "string"
          },
          "color_panel_10": {
            "type": "string"
          },
          "color_on_panel_1": {
            "type": "string"
          },
          "color_on_panel_2": {
            "type": "string"
          },
          "color_on_background": {
            "type": "string"
          },
          "color_button_1": {
            "type": "string"
          },
          "color_button_2": {
            "type": "string"
          },
          "color_button_text_1": {
            "type": "string"
          },
          "color_button_text_2": {
            "type": "string"
          },
          "color_pill_text": {
            "type": "string"
          },
          "border_radius_panel": {
            "type": "integer"
          },
          "border_radius_buttons": {
            "type": "integer"
          },
          "font_family": {
            "type": "string"
          },
          "font_weight": {
            "type": "string"
          },
          "font_url": {
            "type": "string",
            "nullable": true,
            "description": "Read-only. Resolved Google Fonts stylesheet URL for the selected family."
          },
          "logo_square": {
            "type": "string",
            "nullable": true,
            "description": "Read-only URL of the square logo. Upload via `image_square`."
          },
          "logo_rectangular": {
            "type": "string",
            "nullable": true,
            "description": "Read-only URL of the rectangular logo. Upload via `image_rectangular`."
          },
          "favicon": {
            "type": "string",
            "nullable": true,
            "description": "Read-only URL of the favicon. Upload via `image_favicon`."
          },
          "app_public_name": {
            "type": "string",
            "nullable": true
          },
          "privacy_policy_url": {
            "type": "string",
            "nullable": true
          },
          "skip_welcome_screen": {
            "type": "boolean"
          },
          "disable_login_with_didit": {
            "type": "boolean"
          },
          "hide_progress_bar": {
            "type": "boolean"
          },
          "callback_seconds": {
            "type": "integer"
          }
        }
      },
      "WebhookEvent": {
        "type": "string",
        "description": "Supported webhook event name. Use these exact strings in `subscribed_events`; unsupported values are rejected.",
        "enum": [
          "status.updated",
          "data.updated",
          "user.status.updated",
          "user.data.updated",
          "business.status.updated",
          "business.data.updated",
          "activity.created",
          "transaction.created",
          "transaction.status.updated",
          "travel_rule.status.updated"
        ]
      },
      "WebhookSubscribedEvents": {
        "type": "array",
        "description": "Event filter for this webhook destination. Didit delivers only webhooks whose event type exactly matches one of these values — there is no wildcard subscription. When sent, the list must contain at least one valid event (an explicit `[]` is rejected with 400); a destination whose list is empty (field omitted at create) receives nothing. On update the list is replaced wholesale, never merged.",
        "minItems": 1,
        "uniqueItems": true,
        "items": {
          "$ref": "#/components/schemas/WebhookEvent"
        },
        "example": [
          "status.updated",
          "data.updated"
        ]
      },
      "PhoneVerificationSendResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Session id of the verification. A `Retry` send returns the same `request_id` as the original send. This id appears in the Business Console, is returned again by a finalized `POST /v3/phone/check/`, and can be passed to `GET /v3/session/{sessionId}/decision/`."
          },
          "status": {
            "type": "string",
            "enum": [
              "Success",
              "Retry",
              "Blocked"
            ],
            "description": "`Success` — OTP sent to a new verification. `Retry` — OTP re-sent for the pending verification created by a previous send. `Blocked` — the anti-fraud layer refused to send; the verification is immediately finalized as `Declined` and nothing is billed."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "description": "Why a send was `Blocked` (e.g., `repeated_attempts`, `suspicious`, `spam`). `null` on `Success` and `Retry`."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Echo of the `vendor_data` stored on the session (from the first send)."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "Echo of the `metadata` stored on the session (from the first send)."
          }
        }
      },
      "PhoneVerificationCheckResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "On `Approved`/`Declined`: the session id of the matched verification — identical to the `request_id` returned by `POST /v3/phone/send/`. On `Failed` and `Expired or Not Found`: a random one-off UUID that cannot be looked up later."
          },
          "status": {
            "type": "string",
            "enum": [
              "Approved",
              "Declined",
              "Failed",
              "Expired or Not Found"
            ],
            "description": "`Approved` — correct code, no declining risk. `Declined` — terminal: a declining risk matched or the attempt budget (3) was exhausted. `Failed` — wrong code, attempts remaining. `Expired or Not Found` — no pending verification for this number in the last 5 minutes."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation of the outcome, including the number of attempts remaining after a wrong code."
          },
          "phone": {
            "type": "object",
            "nullable": true,
            "description": "Full phone report. Present (non-null) only on finalized outcomes (`Approved`/`Declined`); `null` on `Failed` and absent on `Expired or Not Found`.",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "Approved",
                  "Declined",
                  "In Review",
                  "Not Finished",
                  "Expired"
                ],
                "description": "Final status of the phone verification. Matches the top-level `status` for finalized checks."
              },
              "phone_number_prefix": {
                "type": "string",
                "description": "Country calling code with leading `+` (e.g., `+1`).",
                "example": "+1"
              },
              "phone_number": {
                "type": "string",
                "description": "National number without the country calling code.",
                "example": "4155552671"
              },
              "full_number": {
                "type": "string",
                "description": "Complete number in E.164 format.",
                "example": "+14155552671"
              },
              "country_code": {
                "type": "string",
                "nullable": true,
                "description": "ISO 3166-1 alpha-2 country of the number.",
                "example": "US"
              },
              "country_name": {
                "type": "string",
                "description": "Full country name derived from `country_code`.",
                "example": "United States"
              },
              "carrier": {
                "type": "object",
                "description": "Current network serving the number, from the carrier lookup run at finalization.",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Carrier name. Empty string when the lookup could not identify it."
                  },
                  "type": {
                    "type": "string",
                    "description": "Line type reported by the lookup: `mobile`, `fixed_line`, `voip`, `isp`, `vpn`, `toll_free`, `premium_rate`, `pager`, `payphone`, `satellite`, `service`, `shared_cost`, `short_codes_commercial`, `calling_cards`, `local_rate`, `universal_access`, `voice_mail`, `other`, or `unknown`."
                  }
                }
              },
              "is_disposable": {
                "type": "boolean",
                "description": "`true` when the number belongs to a temporary/burner number service."
              },
              "is_virtual": {
                "type": "boolean",
                "description": "`true` when the line type is virtual (`voip`, `isp`, or `vpn`)."
              },
              "verification_method": {
                "type": "string",
                "description": "Channel that actually delivered the OTP once delivery is confirmed (e.g., `whatsapp`, `sms`); until then, the requested channel."
              },
              "verification_attempts": {
                "type": "integer",
                "description": "Number of OTP sends for this verification (1, or 2 after a retry)."
              },
              "verified_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true,
                "description": "When the correct code was entered. `null` if the verification was never approved."
              },
              "warnings": {
                "type": "array",
                "description": "Risk warnings recorded during the verification (duplicate, disposable, VoIP, attempts exceeded, blocklist, etc.). Empty array when there are none.",
                "items": {
                  "type": "object",
                  "properties": {
                    "feature": {
                      "type": "string",
                      "description": "Feature that produced the warning. Always `PHONE` here."
                    },
                    "risk": {
                      "type": "string",
                      "description": "Machine-readable risk code."
                    },
                    "additional_data": {
                      "type": "object",
                      "nullable": true,
                      "description": "Risk-specific context (e.g., the duplicated session id for duplicate risks). `null` when the risk carries no extra data."
                    },
                    "log_type": {
                      "type": "string",
                      "enum": [
                        "error",
                        "warning",
                        "information"
                      ],
                      "description": "Severity. `error` risks decline the verification, `warning` flags it for review, `information` is recorded without affecting the status."
                    },
                    "short_description": {
                      "type": "string",
                      "description": "Human-readable one-line summary of the risk."
                    },
                    "long_description": {
                      "type": "string",
                      "description": "Human-readable explanation of the risk."
                    }
                  }
                }
              },
              "lifecycle": {
                "type": "array",
                "description": "Chronological audit trail of the verification. Event `type` is one of `PHONE_VERIFICATION_MESSAGE_SENT`, `PHONE_VERIFICATION_RETRY_MESSAGE_SENT`, `PHONE_VERIFICATION_BLOCKED`, `PHONE_DELIVERY_DELIVERED`, `PHONE_DELIVERY_UNDELIVERABLE`, `VALID_CODE_ENTERED`, `INVALID_CODE_ENTERED`, `PHONE_VERIFICATION_APPROVED`, `PHONE_VERIFICATION_DECLINED`, `PHONE_VERIFICATION_IN_REVIEW`, `PHONE_VERIFICATION_EXPIRED`.",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Event type."
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the event happened."
                    },
                    "details": {
                      "type": "object",
                      "nullable": true,
                      "description": "Event-specific payload. Send events: `{status, reason, channel, actual_channel}` (`actual_channel` is filled once delivery is confirmed). Delivery events: `{channel, status}`. Code-entry events: `{code_tried, status}`. Final-status events: `null`, or `{reason}` when declined or in review."
                    },
                    "fee": {
                      "type": "number",
                      "description": "USD amount billed for this event. Non-zero only on send events (the delivery price); 0 for code entries, delivery confirmations, and status events."
                    }
                  }
                }
              },
              "matches": {
                "type": "array",
                "description": "Other sessions of your application (KYC, KYB, or API) where the same phone number was used by a different user (different `vendor_data`). Up to 5 entries, a synthetic list-entry blocklist match first when present (session-derived matches keep query order). Empty array when there are no matches.",
                "items": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Session id of the other verification that used this phone number."
                    },
                    "session_number": {
                      "type": "integer",
                      "description": "Human-friendly sequential number of that session."
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "`vendor_data` of that session."
                    },
                    "verification_date": {
                      "type": "string",
                      "description": "When that session was created (`YYYY-MM-DDTHH:MM:SSZ`)."
                    },
                    "phone_number": {
                      "type": "string",
                      "description": "The matched phone number."
                    },
                    "status": {
                      "type": "string",
                      "description": "Status of that session (e.g., `Approved`, `Declined`, `In Progress`)."
                    },
                    "is_blocklisted": {
                      "type": "boolean",
                      "description": "Whether the phone number is on your application's blocklist."
                    },
                    "api_service": {
                      "type": "string",
                      "nullable": true,
                      "description": "For API-type sessions, the standalone API that created it (e.g., `PHONE_VERIFICATION`); `null` for regular verification sessions."
                    },
                    "source": {
                      "type": "string",
                      "description": "Where the match was found. Usually `session`; a blocklist hit via an organization list entry prepends a synthetic match with `source: \"list_entry\"` and null `session_id`/`session_number`."
                    }
                  }
                }
              },
              "phone_social": {
                "$ref": "#/components/schemas/PhoneSocialFootprint"
              }
            }
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "`vendor_data` of the matched verification's session. `null` on `Expired or Not Found`."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "`metadata` of the matched verification's session. `null` on `Expired or Not Found`."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of this check response."
          }
        }
      },
      "EmailVerificationSendResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Session id of the verification. A `Retry` send returns the same `request_id` as the original send. This id appears in the Business Console, is returned again by a finalized `POST /v3/email/check/`, and can be passed to `GET /v3/session/{sessionId}/decision/`."
          },
          "status": {
            "type": "string",
            "enum": [
              "Success",
              "Retry",
              "Undeliverable"
            ],
            "description": "`Success` — OTP emailed to a new verification (billed). `Retry` — fresh OTP emailed for the pending verification created by a previous send (free). `Undeliverable` — the address failed deliverability validation or the message could not be sent; the verification is immediately finalized as `Declined` and nothing is billed."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "enum": [
              "email_can_not_be_delivered",
              null
            ],
            "description": "`email_can_not_be_delivered` when `status` is `Undeliverable`; `null` otherwise."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Echo of the `vendor_data` stored on the session (from the first send)."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "Echo of the `metadata` stored on the session (from the first send)."
          }
        }
      },
      "EmailVerificationCheckResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "On `Approved`/`Declined`: the session id of the matched verification — identical to the `request_id` returned by `POST /v3/email/send/`. On `Failed` and `Expired or Not Found`: a random one-off UUID that cannot be looked up later."
          },
          "status": {
            "type": "string",
            "enum": [
              "Approved",
              "Declined",
              "Failed",
              "Expired or Not Found"
            ],
            "description": "`Approved` — correct code, no declining risk. `Declined` — terminal: a declining risk matched or the attempt budget (3) was exhausted. `Failed` — wrong code, attempts remaining. `Expired or Not Found` — no pending verification for this address in the last 5 minutes."
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation of the outcome, including the number of attempts remaining after a wrong code."
          },
          "email": {
            "type": "object",
            "nullable": true,
            "description": "Full email report. Present (non-null) only on finalized outcomes (`Approved`/`Declined`); `null` on `Failed` and absent on `Expired or Not Found`.",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "Approved",
                  "Declined",
                  "In Review",
                  "Not Finished",
                  "Expired"
                ],
                "description": "Final status of the email verification. Matches the top-level `status` for finalized checks."
              },
              "email": {
                "type": "string",
                "format": "email",
                "description": "The verified email address.",
                "example": "alice@example.com"
              },
              "is_breached": {
                "type": "boolean",
                "description": "`true` when the address appears in known data breaches (breach intelligence lookup run at finalization)."
              },
              "breaches": {
                "type": "array",
                "description": "Up to 5 most recent known breaches containing this address. Empty array (or omitted) when `is_breached` is `false`.",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Breach identifier."
                    },
                    "domain": {
                      "type": "string",
                      "description": "Domain of the breached service."
                    },
                    "breach_date": {
                      "type": "string",
                      "format": "date",
                      "description": "Date the breach occurred."
                    },
                    "breach_emails_count": {
                      "type": "integer",
                      "description": "Total number of accounts exposed in the breach."
                    },
                    "description": {
                      "type": "string",
                      "description": "Human-readable description of the breach (may contain HTML markup)."
                    },
                    "logo_path": {
                      "type": "string",
                      "description": "URL of the breached service's logo."
                    },
                    "data_classes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Categories of data exposed, in snake_case (e.g., `email_addresses`, `passwords`)."
                    },
                    "is_verified": {
                      "type": "boolean",
                      "description": "Whether the breach has been verified as legitimate."
                    }
                  }
                }
              },
              "is_disposable": {
                "type": "boolean",
                "description": "`true` when the domain belongs to a known disposable/temporary-mail provider."
              },
              "is_undeliverable": {
                "type": "boolean",
                "description": "`true` when the address cannot receive mail (failed syntax or DNS/MX validation, or the message bounced)."
              },
              "verification_attempts": {
                "type": "integer",
                "description": "Number of OTP sends for this verification (1, or 2 after a retry)."
              },
              "verified_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true,
                "description": "When the correct code was entered. `null` if the verification was never approved."
              },
              "warnings": {
                "type": "array",
                "description": "Risk warnings recorded during the verification (duplicate, breached, disposable, undeliverable, attempts exceeded, blocklist, etc.). Empty array when there are none.",
                "items": {
                  "type": "object",
                  "properties": {
                    "feature": {
                      "type": "string",
                      "description": "Feature that produced the warning. Always `EMAIL` here."
                    },
                    "risk": {
                      "type": "string",
                      "description": "Machine-readable risk code."
                    },
                    "additional_data": {
                      "type": "object",
                      "nullable": true,
                      "description": "Risk-specific context (e.g., the duplicated session id for duplicate risks). `null` when the risk carries no extra data."
                    },
                    "log_type": {
                      "type": "string",
                      "enum": [
                        "error",
                        "warning",
                        "information"
                      ],
                      "description": "Severity. `error` risks decline the verification, `warning` flags it for review, `information` is recorded without affecting the status."
                    },
                    "short_description": {
                      "type": "string",
                      "description": "Human-readable one-line summary of the risk."
                    },
                    "long_description": {
                      "type": "string",
                      "description": "Human-readable explanation of the risk."
                    }
                  }
                }
              },
              "lifecycle": {
                "type": "array",
                "description": "Chronological audit trail of the verification. Event `type` is one of `EMAIL_VERIFICATION_MESSAGE_SENT`, `EMAIL_VERIFICATION_RETRY_MESSAGE_SENT`, `VALID_CODE_ENTERED`, `INVALID_CODE_ENTERED`, `EMAIL_VERIFICATION_APPROVED`, `EMAIL_VERIFICATION_DECLINED`, `EMAIL_VERIFICATION_IN_REVIEW`, `EMAIL_VERIFICATION_EXPIRED`.",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Event type."
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the event happened."
                    },
                    "details": {
                      "type": "object",
                      "nullable": true,
                      "description": "Event-specific payload. Send events: `{status, reason}`. Code-entry events: `{code_tried, status}`. Final-status events: `null`, or `{reason}` when declined or in review."
                    },
                    "fee": {
                      "type": "number",
                      "description": "USD amount billed for this event. Non-zero only on the first successful send; 0 for retries, code entries, and status events."
                    }
                  }
                }
              },
              "matches": {
                "type": "array",
                "description": "Other sessions of your application (KYC, KYB, or API) where the same email address was used by a different user (different `vendor_data`). Up to 5 entries; a synthetic list-entry blocklist match is prepended when present (and only when no session-derived blocklisted email exists) — session-derived matches keep created_at order. Empty array when there are no matches.",
                "items": {
                  "type": "object",
                  "properties": {
                    "session_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Session id of the other verification that used this email address."
                    },
                    "session_number": {
                      "type": "integer",
                      "description": "Human-friendly sequential number of that session."
                    },
                    "vendor_data": {
                      "type": "string",
                      "nullable": true,
                      "description": "`vendor_data` of that session."
                    },
                    "verification_date": {
                      "type": "string",
                      "description": "When that session was created (`YYYY-MM-DDTHH:MM:SSZ`)."
                    },
                    "email": {
                      "type": "string",
                      "description": "The matched email address."
                    },
                    "status": {
                      "type": "string",
                      "description": "Status of that session (e.g., `Approved`, `Declined`, `In Progress`)."
                    },
                    "is_blocklisted": {
                      "type": "boolean",
                      "description": "Whether the email address is on your application's blocklist."
                    },
                    "api_service": {
                      "type": "string",
                      "nullable": true,
                      "description": "For API-type sessions, the standalone API that created it (e.g., `PHONE_VERIFICATION`); `null` for regular verification sessions."
                    },
                    "source": {
                      "type": "string",
                      "description": "Where the match was found. Usually `session`; a blocklist hit via an organization list entry prepends a synthetic match with `source: \"list_entry\"` and null `session_id`/`session_number`."
                    }
                  }
                }
              },
              "email_social": {
                "$ref": "#/components/schemas/EmailSocialFootprint"
              }
            }
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "`vendor_data` of the matched verification's session. `null` on `Expired or Not Found`."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "`metadata` of the matched verification's session. `null` on `Expired or Not Found`."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of this check response."
          }
        }
      },
      "WorkflowListItem": {
        "type": "object",
        "description": "One workflow version in the list view.",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "Per-version UUID. Use as `{settings_uuid}` for get/update/delete, and as `workflow_id` when creating sessions."
          },
          "workflow_id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable group ID shared by every version of the same workflow. Equals `uuid` for version 1."
          },
          "workflow_label": {
            "type": "string",
            "description": "Display name for the workflow."
          },
          "workflow_type": {
            "type": "string",
            "nullable": true,
            "description": "Base type for simple workflows: `kyc`, `kyb`, `adaptive_age_verification`, `biometric_authentication`, etc. `null` for graph-based workflows without a KYB feature."
          },
          "is_default": {
            "type": "boolean",
            "description": "Whether this is the default workflow for new sessions."
          },
          "is_archived": {
            "type": "boolean"
          },
          "is_white_label_enabled": {
            "type": "boolean",
            "description": "Whether white-label customization applies to sessions created with this workflow."
          },
          "total_price": {
            "type": "number",
            "description": "Fixed price per verification in USD (JSON number, excludes variable-priced features such as DATABASE_VALIDATION and PHONE_VERIFICATION)."
          },
          "min_price": {
            "type": "number",
            "description": "Cheapest fixed price across workflow-graph paths, in USD."
          },
          "max_price": {
            "type": "number",
            "description": "Most expensive fixed price across workflow-graph paths, in USD."
          },
          "features": {
            "type": "string",
            "description": "Enabled features as a single `\" + \"`-joined string, e.g. `\"OCR + LIVENESS + FACE_MATCH\"`. Split on `\" + \"` to get a list."
          },
          "is_simple_workflow": {
            "type": "boolean",
            "description": "True when the workflow has no custom workflow graph."
          },
          "is_editable": {
            "type": "boolean",
            "description": "True when this version is a `draft` (drafts are editable in place; published versions are immutable in the Console)."
          },
          "workflow_url": {
            "type": "string",
            "format": "uri",
            "description": "Public shareable verification URL for this workflow (`https://verify.didit.me/u/<token>`)."
          },
          "max_retry_attempts": {
            "type": "integer",
            "description": "Maximum retry attempts allowed after a declined verification (0-10)."
          },
          "retry_window_days": {
            "type": "integer",
            "nullable": true,
            "description": "Rolling window in days used to count retries (1-365). `null` = all-time limit."
          },
          "session_expiration_time": {
            "type": "integer",
            "description": "Seconds before an unfinished session expires (3600-2419200)."
          },
          "version": {
            "type": "integer",
            "description": "Version number within the `workflow_id` group, starting at 1."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ],
            "description": "Version status. New sessions use the latest `published` version of a group."
          },
          "has_draft": {
            "type": "boolean",
            "description": "True when any version in this `workflow_id` group is currently a draft."
          },
          "created_by": {
            "type": "object",
            "nullable": true,
            "description": "Who created this version: `{name, email, type}` where `type` is `user` (Console user, `email` set) or `api_key` (`name` is the client id, `email` is null). `null` when no creator was recorded.",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "user",
                  "api_key"
                ]
              }
            }
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SimpleWorkflowRequest": {
        "type": "object",
        "description": "Create a simple linear workflow. The API converts this feature list into a node-based workflow graph internally. STRICT field whitelist: any key not listed here (including `workflow_type`) is rejected with a 400.",
        "required": [
          "features"
        ],
        "properties": {
          "workflow_label": {
            "type": "string",
            "maxLength": 50,
            "default": "ID Verification",
            "description": "Display name for the workflow (max 50 characters). Defaults to `\"ID Verification\"` when omitted — always set it so workflows stay distinguishable.",
            "example": "Standard KYC"
          },
          "is_default": {
            "type": "boolean",
            "description": "Set this workflow as the default for new sessions."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ],
            "description": "Omit this field to create a published workflow ready for sessions. Use `draft` only when you want to save without publishing."
          },
          "features": {
            "type": "array",
            "minItems": 1,
            "description": "Verification features in execution order. The API links each item to the next one and adds one final status node automatically.",
            "items": {
              "$ref": "#/components/schemas/SimpleWorkflowFeature"
            }
          },
          "is_white_label_enabled": {
            "type": "boolean",
            "description": "Enable white-label customization for sessions created with this workflow.",
            "default": false
          },
          "is_desktop_allowed": {
            "type": "boolean",
            "description": "Allow the verification flow to run on desktop browsers.",
            "default": false
          },
          "max_retry_attempts": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10,
            "default": 3,
            "description": "Maximum retry attempts allowed after a declined verification. `0` blocks the user after the first decline."
          },
          "retry_window_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "nullable": true,
            "default": 7,
            "description": "Rolling window in days used to count retries. `null` enforces an all-time limit."
          },
          "face_liveness_max_attempts": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3,
            "default": 3,
            "description": "Maximum liveness submissions per session. Default 3: one initial attempt plus two retries. This value is also copied into generated liveness and age-estimation workflow nodes unless the feature-level config overrides it."
          },
          "face_match_max_attempts": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3,
            "default": 3,
            "description": "Maximum face-match submissions per session. Default 3: one initial attempt plus two retries. This value is also copied into generated face-match workflow nodes unless the feature-level config overrides it."
          },
          "session_expiration_time": {
            "type": "integer",
            "minimum": 3600,
            "maximum": 2419200,
            "default": 604800,
            "description": "Seconds before an unfinished session expires. Minimum 1 hour (3600), maximum 4 weeks (2419200)."
          }
        }
      },
      "SimpleWorkflowUpdateRequest": {
        "type": "object",
        "description": "Update workflow metadata or replace the full linear feature list. STRICT field whitelist: any key not listed here is rejected with a 400.",
        "properties": {
          "workflow_label": {
            "type": "string",
            "maxLength": 50,
            "description": "Display name for the workflow (max 50 characters)."
          },
          "is_default": {
            "type": "boolean",
            "description": "Set this workflow as the default for new sessions."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ],
            "description": "Controls versioning. Omit to update the current version in place (drafts auto-publish). `published` on an already-published version creates and returns a NEW version. `draft` is only valid while the version is still a draft."
          },
          "features": {
            "type": "array",
            "minItems": 1,
            "description": "If provided, this replaces the full feature order and configuration.",
            "items": {
              "$ref": "#/components/schemas/SimpleWorkflowFeature"
            }
          },
          "is_white_label_enabled": {
            "type": "boolean",
            "description": "Enable white-label customization for sessions created with this workflow."
          },
          "is_desktop_allowed": {
            "type": "boolean",
            "description": "Allow the verification flow to run on desktop browsers."
          },
          "max_retry_attempts": {
            "type": "integer",
            "minimum": 0,
            "maximum": 10,
            "description": "Maximum retry attempts allowed after a declined verification. `0` blocks the user after the first decline."
          },
          "retry_window_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "nullable": true,
            "description": "Rolling window in days used to count retries. `null` enforces an all-time limit."
          },
          "face_liveness_max_attempts": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3,
            "description": "Maximum liveness submissions per session. This value is also copied into generated liveness and age-estimation workflow nodes unless the feature-level config overrides it."
          },
          "face_match_max_attempts": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3,
            "description": "Maximum face-match submissions per session. This value is also copied into generated face-match workflow nodes unless the feature-level config overrides it."
          },
          "session_expiration_time": {
            "type": "integer",
            "minimum": 3600,
            "maximum": 2419200,
            "description": "Seconds before an unfinished session expires. Minimum 1 hour (3600), maximum 4 weeks (2419200)."
          }
        }
      },
      "SimpleWorkflowFeature": {
        "type": "object",
        "required": [
          "feature"
        ],
        "properties": {
          "feature": {
            "type": "string",
            "description": "Feature to run. Use the uppercase values shown here.",
            "enum": [
              "OCR",
              "NFC",
              "LIVENESS",
              "FACE_MATCH",
              "PROOF_OF_ADDRESS",
              "QUESTIONNAIRE",
              "DOCUMENT_AI",
              "PHONE_VERIFICATION",
              "EMAIL_VERIFICATION",
              "DATABASE_VALIDATION",
              "AML",
              "IP_ANALYSIS",
              "AGE_ESTIMATION",
              "KYB_REGISTRY",
              "KYB_DOCUMENTS",
              "KYB_KEY_PEOPLE"
            ]
          },
          "config": {
            "type": "object",
            "description": "Feature-specific settings. For `QUESTIONNAIRE`, include `questionnaire_uuid` with the `questionnaire_id` returned by the questionnaire create endpoint. For `OCR`, `methods` selects which ID Verification methods each country may use (document capture, non-doc lookup against a government or other authoritative source, and digital identity wallets); omit it and every country is document capture only.",
            "additionalProperties": true
          },
          "label": {
            "type": "string",
            "description": "Optional internal label for this workflow node."
          }
        }
      },
      "ReviewItem": {
        "type": "object",
        "description": "One entry in a session's review / activity feed. Status changes carry `previous_status`, `new_status`, `previous_value`, `new_value`, and `changed_fields`; comments carry `comment` and (for Console comments) `mentioned_emails`; the remaining fields are `null` or empty when they do not apply to the activity type.",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of this feed entry.",
            "example": "de0561bc-5583-4409-9171-1a31a4c8a5f4"
          },
          "activity_type": {
            "type": "string",
            "enum": [
              "COMMENT",
              "STATUS_UPDATED",
              "KYC_DATA_UPDATED",
              "POA_DATA_UPDATED",
              "FILE_ADDED",
              "FILE_REMOVED",
              "AML_ONGOING_MATCH",
              "AML_STATUS_UPDATED",
              "AML_HIT_STATUS_UPDATED",
              "KYB_DATA_UPDATED",
              "KYB_DOCUMENT_UPLOADED",
              "TAG_ADDED",
              "TAG_REMOVED"
            ],
            "description": "What kind of activity this entry records. `STATUS_UPDATED` rows come from manual decisions (`PATCH /v3/session/{session_id}/update-status/`) and from entries added via `POST …/reviews/` (which default to this type even when no status is recorded). `COMMENT` rows come from Console reviewers; Console detail-page views are also stored as `COMMENT` rows flagged with `metadata.system_event = \"DETAIL_VIEWED\"`. The remaining types track data edits, file changes, tags, and AML monitoring activity. STATUS_UPDATED rows are also written by system actors (e.g. AML ongoing monitoring with actor_type SYSTEM, and automatic feature-status updates), not only by the update-status endpoint and manual review posts.",
            "example": "STATUS_UPDATED"
          },
          "actor_display": {
            "type": "string",
            "description": "Human-readable author label, resolved in order: actor's full name → Console account identifier → local part of `actor_email` → `\"API Client\"` (for `API_KEY` actors) → `\"System\"` (for `SYSTEM` actors) → `\"Unknown\"`. Entries created via `POST …/reviews/` always display `\"Unknown\"` because that endpoint records no actor attribution.",
            "example": "API Client"
          },
          "actor_email": {
            "type": "string",
            "nullable": true,
            "description": "Email of the Console user who performed the action. `null` for API-key and system actors.",
            "example": null
          },
          "actor_type": {
            "type": "string",
            "enum": [
              "API_KEY",
              "CONSOLE_USER",
              "SYSTEM"
            ],
            "description": "Who performed the action: an API key, a Console user, or Didit itself (`SYSTEM`, e.g. AML ongoing monitoring). Entries created via `POST …/reviews/` carry the default `CONSOLE_USER` regardless of the caller.",
            "example": "API_KEY"
          },
          "new_status": {
            "type": "string",
            "nullable": true,
            "enum": [
              "Not Started",
              "In Progress",
              "Approved",
              "Declined",
              "In Review",
              "Expired",
              "Abandoned",
              "Kyc Expired",
              "Resubmitted",
              "Awaiting User"
            ],
            "description": "Session status recorded by this entry (for status updates). `null` for comments and data-change entries.",
            "example": "Approved"
          },
          "previous_status": {
            "type": "string",
            "nullable": true,
            "enum": [
              "Not Started",
              "In Progress",
              "Approved",
              "Declined",
              "In Review",
              "Expired",
              "Abandoned",
              "Kyc Expired",
              "Resubmitted",
              "Awaiting User"
            ],
            "description": "Status the session had before the change. Populated on `STATUS_UPDATED` entries written by the update-status endpoint; `null` on entries added via `POST …/reviews/`. Also populated on system-written STATUS_UPDATED rows.",
            "example": "In Review"
          },
          "comment": {
            "type": "string",
            "nullable": true,
            "description": "Free-text note attached to the entry, or `null`.",
            "example": "Document re-checked manually; address matches."
          },
          "mentioned_emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Console users `@email`-mentioned in the comment. Always empty for entries created via this API — mention processing is a Console-only feature.",
            "example": []
          },
          "previous_value": {
            "type": "object",
            "nullable": true,
            "description": "Snapshot of the changed data before the action, e.g. `{\"status\": \"In Review\"}` on a status change. `null` when nothing was changed.",
            "example": {
              "status": "In Review"
            }
          },
          "new_value": {
            "type": "object",
            "nullable": true,
            "description": "Snapshot of the changed data after the action, e.g. `{\"status\": \"Approved\"}`. `null` when nothing was changed.",
            "example": {
              "status": "Approved"
            }
          },
          "changed_fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of the fields modified by this activity (e.g. `[\"status\"]`). Empty for comments and for entries added via `POST …/reviews/`.",
            "example": [
              "status"
            ]
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "description": "Extra context for system-generated entries. Console detail-page views carry `{\"system_event\": \"DETAIL_VIEWED\", \"detail_type\": \"verification\"}` so they can be filtered out of notification logic. `null` for ordinary entries.",
            "example": null
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the entry was written, ISO 8601 UTC.",
            "example": "2026-06-12T00:19:31.918735Z"
          }
        }
      },
      "QuestionnaireListItem": {
        "type": "object",
        "description": "One questionnaire version in the list view.",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "Per-version UUID. Use as `{questionnaire_uuid}` for get/update/delete and as `questionnaire_uuid` in a workflow's QUESTIONNAIRE feature config."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "default_language": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "is_simple_questionnaire": {
            "type": "boolean",
            "description": "True for linear questionnaires created through this API; false for graph-based questionnaires built in the Console."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "question_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Uppercase element types of the answerable questions, in creation order (e.g. `SHORT_TEXT`, `MULTIPLE_CHOICE`, `FILE_UPLOAD`). Structural `SECTION_HEADER` and `SEPARATOR` elements are excluded. One entry per question, so values can repeat."
          },
          "workflow_names": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Names of workflows using this questionnaire. Currently always `[]` on this endpoint (populated only in the Console listing)."
          },
          "questionnaire_group_id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable identifier that groups all versions of the same questionnaire."
          },
          "version": {
            "type": "integer",
            "description": "Version number within the group, starting at 1."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ]
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When this version was published. `null` for drafts."
          },
          "is_editable": {
            "type": "boolean",
            "description": "True when this version is a `draft`."
          }
        }
      },
      "SimpleQuestionnaireRequest": {
        "type": "object",
        "description": "Create a simple linear questionnaire. The API converts `form_elements` into the internal questionnaire graph.",
        "required": [
          "title",
          "languages",
          "form_elements"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Internal name for the questionnaire."
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "languages": {
            "type": "array",
            "description": "Languages included in every label. Must include `en`.",
            "items": {
              "type": "string"
            },
            "example": [
              "en"
            ]
          },
          "default_language": {
            "type": "string",
            "description": "Default language. Must be included in `languages`.",
            "example": "en"
          },
          "is_active": {
            "type": "boolean",
            "default": true
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ],
            "description": "Omit this field to create a published questionnaire ready for workflows."
          },
          "form_elements": {
            "type": "array",
            "minItems": 1,
            "description": "Questions in the exact order users should see them. Branching and conditional fields are not supported.",
            "items": {
              "$ref": "#/components/schemas/SimpleQuestionnaireElement"
            }
          }
        }
      },
      "SimpleQuestionnaireUpdateRequest": {
        "type": "object",
        "description": "Update questionnaire metadata or replace the full linear `form_elements` list.",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "default_language": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ]
          },
          "form_elements": {
            "type": "array",
            "minItems": 1,
            "description": "If provided, this replaces the full linear question list.",
            "items": {
              "$ref": "#/components/schemas/SimpleQuestionnaireElement"
            }
          }
        }
      },
      "SimpleQuestionnaireElement": {
        "type": "object",
        "required": [
          "element_type",
          "label"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Optional stable question id. If omitted, the API generates `q1`, `q2`, etc. Use lowercase letters, numbers, and underscores for readability.",
            "example": "source_of_funds"
          },
          "element_type": {
            "type": "string",
            "description": "Question type. The API accepts these lowercase values and their uppercase equivalents.",
            "enum": [
              "short_text",
              "long_text",
              "dropdown",
              "single_choice",
              "multiple_choice",
              "number",
              "image",
              "file_upload",
              "time",
              "email",
              "address",
              "phone",
              "country",
              "date_picker",
              "consent",
              "section_header",
              "separator",
              "heading",
              "paragraph"
            ]
          },
          "label": {
            "type": "object",
            "description": "Question label by language code, for example `{ \"en\": \"Source of funds\" }`.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "description": {
            "type": "object",
            "nullable": true,
            "additionalProperties": {
              "type": "string"
            }
          },
          "placeholder": {
            "type": "object",
            "nullable": true,
            "additionalProperties": {
              "type": "string"
            }
          },
          "is_required": {
            "type": "boolean",
            "default": false
          },
          "options": {
            "type": "array",
            "description": "Use for `dropdown`, `single_choice`, and `multiple_choice`. If `value` is omitted, the API generates one from the option label.",
            "items": {
              "type": "object",
              "required": [
                "label"
              ],
              "properties": {
                "value": {
                  "type": "string"
                },
                "label": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "max_files": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "description": "Use with `file_upload` or `image`."
          },
          "validation": {
            "type": "object",
            "nullable": true,
            "description": "Optional format validation for `short_text`, `long_text`, or `number`. Enforced while the user fills the field (they cannot proceed until it passes) and re-checked by the API on submission.",
            "properties": {
              "pattern": {
                "type": "string",
                "description": "Regular expression (ECMA-262 subset) the value must fully match. For `short_text` and `long_text`. Do not add ^/$ anchors; the whole value is matched."
              },
              "min_length": {
                "type": "integer",
                "minimum": 0,
                "description": "Minimum number of characters. For `short_text` and `long_text`."
              },
              "max_length": {
                "type": "integer",
                "minimum": 0,
                "description": "Maximum number of characters. For `short_text` and `long_text`."
              },
              "min": {
                "type": "number",
                "description": "Minimum numeric value. For `number`."
              },
              "max": {
                "type": "number",
                "description": "Maximum numeric value. For `number`."
              },
              "error_message": {
                "type": "object",
                "description": "Translated message shown when validation fails, keyed by language code.",
                "additionalProperties": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "QuestionnaireDetail": {
        "type": "object",
        "description": "Full questionnaire detail returned from GET, POST (create) and PATCH (update) endpoints.",
        "properties": {
          "questionnaire_id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier of the questionnaire. Use this id when referencing the questionnaire from a workflow or in subsequent update/delete requests."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "default_language": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "is_simple_questionnaire": {
            "type": "boolean"
          },
          "graph": {
            "type": "object",
            "description": "Graph structure with start_node and nodes map."
          },
          "sections": {
            "type": "array",
            "description": "Questionnaire content grouped into sections (derived from the graph).",
            "items": {
              "type": "object"
            }
          },
          "questionnaire_group_id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable identifier that groups all versions of the same questionnaire."
          },
          "version": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ]
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "is_editable": {
            "type": "boolean",
            "description": "True when the questionnaire can still be edited in place (draft versions)."
          }
        }
      },
      "UserListItem": {
        "type": "object",
        "description": "A verified user.",
        "properties": {
          "didit_internal_id": {
            "type": "string",
            "format": "uuid",
            "description": "Didit's stable internal UUID for this user."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your unique identifier for this user (passed when creating sessions). This can be null when no vendor identifier was supplied."
          },
          "display_name": {
            "type": "string",
            "nullable": true,
            "description": "Custom display name set by you"
          },
          "full_name": {
            "type": "string",
            "nullable": true,
            "description": "Full name extracted from verified documents"
          },
          "date_of_birth": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "effective_name": {
            "type": "string",
            "nullable": true,
            "description": "Best available name: display_name if set, otherwise full_name"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "FLAGGED",
              "BLOCKED"
            ],
            "description": "Lifecycle status of the user record (NOT a session status). `ACTIVE` is the default, `FLAGGED` marks the user for manual attention, `BLOCKED` prevents new sessions for this `vendor_data`."
          },
          "portrait_image_url": {
            "type": "string",
            "nullable": true,
            "description": "Presigned URL of the user's portrait photo (expires after a few hours)"
          },
          "session_count": {
            "type": "integer",
            "description": "Total number of verification sessions for this user"
          },
          "approved_count": {
            "type": "integer",
            "description": "Number of approved sessions"
          },
          "declined_count": {
            "type": "integer",
            "description": "Number of declined sessions"
          },
          "in_review_count": {
            "type": "integer",
            "description": "Number of sessions in review"
          },
          "issuing_states": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "ISO 3166-1 alpha-3 codes of issuing countries seen on this user's approved ID documents, e.g. `[\"USA\", \"ESP\"]`. Empty array when none."
          },
          "approved_emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Verified email addresses collected from this user's approved sessions, e.g. `[\"john@example.com\"]`."
          },
          "approved_phones": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Verified phone numbers collected from this user's approved sessions, e.g. `[\"+14155551234\"]`."
          },
          "features": {
            "type": "object",
            "description": "Aggregated per-feature status across all of this user's sessions. Possible keys: `ID_VERIFICATION`, `NFC`, `LIVENESS`, `FACE_MATCH`, `POA`, `QUESTIONNAIRE`, `EMAIL_VERIFICATION`, `PHONE`, `AML`, `IP_ANALYSIS`, `AGE_ESTIMATION`, `DATABASE_VALIDATION`. Possible values: `Approved`, `Declined`, `In Review`, `Not Finished`, `Resub Requested`."
          },
          "features_list": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "feature": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                }
              }
            },
            "description": "Same data as `features`, as an ordered array of `{feature, status}` objects."
          },
          "last_session_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of the most recent session"
          },
          "first_session_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of the first session"
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of the most recent activity on this user (session, transaction, status change, data edit, etc.)."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                }
              }
            },
            "description": "Tags assigned to this user"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BlocklistItem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "face",
              "document",
              "phone",
              "email"
            ]
          },
          "session_id": {
            "type": "string",
            "format": "uuid"
          },
          "session_number": {
            "type": "integer"
          },
          "blocklisted_at": {
            "type": "string",
            "format": "date-time"
          },
          "face_image": {
            "type": "string",
            "nullable": true
          },
          "document_type": {
            "type": "string",
            "nullable": true
          },
          "document_number": {
            "type": "string",
            "nullable": true
          },
          "phone_number": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "UserDetailItem": {
        "type": "object",
        "description": "Full user detail. Extends UserListItem with metadata, comments, and updated_at.",
        "allOf": [
          {
            "$ref": "#/components/schemas/UserListItem"
          },
          {
            "type": "object",
            "properties": {
              "metadata": {
                "type": "object",
                "description": "Custom metadata JSON you attached to this user. Defaults to `{}`."
              },
              "tags": {
                "type": "array",
                "description": "Tag assignments. NOTE: on detail responses each entry is a tag *link* object (`{uuid, tag: {...}, added_by_email, added_by_name, created_at}`), unlike the flat `{uuid, name, color}` shape used on list responses.",
                "items": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid",
                      "description": "UUID of the tag assignment (not the tag itself)."
                    },
                    "tag": {
                      "type": "object",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "name": {
                          "type": "string"
                        },
                        "color": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string",
                          "nullable": true
                        },
                        "source": {
                          "type": "string",
                          "enum": [
                            "didit",
                            "custom"
                          ]
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updated_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "added_by_email": {
                      "type": "string",
                      "nullable": true
                    },
                    "added_by_name": {
                      "type": "string",
                      "nullable": true
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              },
              "comments": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "comment_type": {
                      "type": "string",
                      "enum": [
                        "COMMENT",
                        "STATUS_CHANGED",
                        "METADATA_UPDATED",
                        "TAG_ADDED",
                        "TAG_REMOVED",
                        "PROFILE_UPDATED"
                      ]
                    },
                    "comment": {
                      "type": "string",
                      "nullable": true
                    },
                    "actor_email": {
                      "type": "string",
                      "nullable": true
                    },
                    "actor_name": {
                      "type": "string",
                      "nullable": true
                    },
                    "previous_status": {
                      "type": "string",
                      "nullable": true,
                      "enum": [
                        "ACTIVE",
                        "FLAGGED",
                        "BLOCKED",
                        null
                      ]
                    },
                    "new_status": {
                      "type": "string",
                      "nullable": true,
                      "enum": [
                        "ACTIVE",
                        "FLAGGED",
                        "BLOCKED",
                        null
                      ]
                    },
                    "previous_value": {
                      "type": "object",
                      "nullable": true,
                      "description": "Previous field values for PROFILE_UPDATED entries."
                    },
                    "new_value": {
                      "type": "object",
                      "nullable": true,
                      "description": "New field values for PROFILE_UPDATED entries."
                    },
                    "changed_fields": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Names of the fields changed by a PROFILE_UPDATED entry."
                    },
                    "metadata": {
                      "type": "object",
                      "nullable": true
                    },
                    "mentioned_emails": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "description": "Activity log and comments for this user (status changes, profile edits, manual notes)."
              },
              "updated_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        ]
      },
      "BusinessListItem": {
        "type": "object",
        "description": "A verified business.",
        "properties": {
          "didit_internal_id": {
            "type": "string",
            "format": "uuid",
            "description": "Didit's stable internal UUID for this business."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your unique identifier for this business (passed when creating sessions). This can be null when no vendor identifier was supplied."
          },
          "display_name": {
            "type": "string",
            "nullable": true,
            "description": "Custom display name set by you"
          },
          "legal_name": {
            "type": "string",
            "nullable": true,
            "description": "Official legal name from registry or manual entry"
          },
          "registration_number": {
            "type": "string",
            "nullable": true,
            "description": "Company registration or incorporation number"
          },
          "country_code": {
            "type": "string",
            "nullable": true,
            "description": "Country of incorporation (ISO 3166-1 alpha-2, e.g. `GB`, `US`)."
          },
          "effective_name": {
            "type": "string",
            "nullable": true,
            "description": "Best available name: display_name if set, otherwise legal_name"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "FLAGGED",
              "BLOCKED"
            ],
            "description": "Lifecycle status of the business record (NOT a session status). `ACTIVE` is the default, `FLAGGED` marks it for manual attention, `BLOCKED` prevents new sessions for this `vendor_data`."
          },
          "session_count": {
            "type": "integer",
            "description": "Total number of verification sessions for this business"
          },
          "approved_count": {
            "type": "integer",
            "description": "Number of approved sessions"
          },
          "declined_count": {
            "type": "integer",
            "description": "Number of declined sessions"
          },
          "in_review_count": {
            "type": "integer",
            "description": "Number of sessions in review"
          },
          "features": {
            "type": "object",
            "description": "Aggregated per-feature status across all of this business's KYB sessions. Currently the only key is `KYB` (the registry company check status). Possible values: `Approved`, `Declined`, `In Review`, `Not Finished`, `Resub Requested`."
          },
          "features_list": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "feature": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                }
              }
            },
            "description": "Same data as `features`, as an ordered array of `{feature, status}` objects."
          },
          "last_session_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of the most recent session"
          },
          "first_session_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of the first session"
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Timestamp of the most recent activity (status change, session update, etc.)"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                }
              }
            },
            "description": "Tags assigned to this business"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BusinessDetailItem": {
        "type": "object",
        "description": "Full business detail. Extends BusinessListItem with metadata and updated_at.",
        "allOf": [
          {
            "$ref": "#/components/schemas/BusinessListItem"
          },
          {
            "type": "object",
            "properties": {
              "metadata": {
                "type": "object",
                "description": "Custom metadata JSON you attached to this business. Defaults to `{}`."
              },
              "updated_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        ]
      },
      "TransactionDetail": {
        "type": "object",
        "description": "Full monitoring record for one transaction, as returned by `GET /v3/transactions/{transaction_id}/` and `POST /v3/transactions/`.",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "description": "Didit-stable transaction identifier. Use as `{transaction_id}` for follow-up calls."
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "sandbox"
            ],
            "description": "Environment of the application that owns the transaction. A `sandbox` transaction is stored but never evaluated, screened, notified or billed, so its empty `rule_runs` means \"not evaluated\"."
          },
          "transaction_number": {
            "type": "integer",
            "description": "Application-scoped sequential transaction number shown in Console (e.g. `4123`)."
          },
          "txn_id": {
            "type": "string",
            "description": "The `transaction_id` you supplied at create time (max 128 chars). Unique per application."
          },
          "txn_date": {
            "type": "string",
            "format": "date-time",
            "description": "When the transaction occurred (from `transaction_at`; defaults to submission time)."
          },
          "zone_id": {
            "type": "string",
            "nullable": true,
            "description": "IANA time zone identifier provided at create time."
          },
          "transaction_type": {
            "type": "string",
            "description": "Top-level category as stored: `finance`, `kyc`, `travelRule`, `userPlatformEvent`, `gamblingBet`, `gamblingLimitChange`, `gamblingBonusChange`, `auditTrailEvent`. Note multi-word values are echoed back in camelCase even when submitted in snake_case."
          },
          "action_type": {
            "type": "string",
            "description": "Sub-type within the category (e.g. `deposit`, `withdrawal`, `transfer`). Defaults to the category when not supplied."
          },
          "direction": {
            "type": "string",
            "enum": [
              "INBOUND",
              "OUTBOUND"
            ],
            "description": "Direction relative to the subject. Stored uppercase regardless of the casing submitted (`in`/`out`/`inbound`/`outbound` are accepted on input)."
          },
          "status": {
            "type": "string",
            "enum": [
              "APPROVED",
              "IN_REVIEW",
              "DECLINED",
              "AWAITING_USER"
            ],
            "description": "Current monitoring verdict. Transactions are created `APPROVED`; rules may flip them to `IN_REVIEW`/`DECLINED` synchronously."
          },
          "source": {
            "type": "string",
            "enum": [
              "LIVE",
              "IMPORTED"
            ],
            "description": "How the record originated: `LIVE` for transactions submitted through the API or SDK, `IMPORTED` for transactions loaded through the console import."
          },
          "amount": {
            "type": "string",
            "description": "Transaction amount as a decimal string with trailing zeros stripped (e.g. `\"1500\"`, `\"0.5\"`, `\"0.123456789012345678\"`). Up to 18 decimal places."
          },
          "currency": {
            "type": "string",
            "description": "Currency code of `amount`. Any ISO 4217 alphabetic code is accepted (e.g. `EUR`, `USD`, `NGN`), as is a crypto asset symbol (e.g. `BTC`). Prefer a currently-circulating code. Not every accepted code has an exchange rate: when none is available for the code (for example the ISO accounting unit `XSU`, or a crypto symbol Didit does not price), automatic conversion fails and `preferred_currency_amount` is returned null unless the request supplied a pre-converted `amount_in_default_currency`."
          },
          "currency_type": {
            "type": "string",
            "nullable": true,
            "description": "`fiat` or `crypto`, as submitted in `currency_kind`."
          },
          "amount_in_default_currency": {
            "type": "string",
            "nullable": true,
            "description": "Pre-converted amount you supplied, as a decimal string with trailing zeros stripped."
          },
          "default_currency_code": {
            "type": "string",
            "nullable": true
          },
          "preferred_currency_amount": {
            "type": "string",
            "nullable": true,
            "description": "`amount` converted to the application's preferred currency, when available."
          },
          "preferred_currency_code": {
            "type": "string",
            "nullable": true
          },
          "payment_details": {
            "type": "string",
            "nullable": true,
            "description": "Free-text payment reference or memo from the submission."
          },
          "payment_txn_id": {
            "type": "string",
            "nullable": true,
            "description": "External payment system reference (e.g. blockchain transaction hash) from `payment_reference_id`."
          },
          "score": {
            "type": "integer",
            "description": "Risk score accumulated by rules (typically 0–100). Higher = riskier."
          },
          "severity": {
            "type": "string",
            "nullable": true,
            "enum": [
              "UNKNOWN",
              "LOW",
              "MEDIUM",
              "HIGH",
              "CRITICAL"
            ],
            "description": "Categorical risk severity set by rules/providers (`UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, `CRITICAL`). `null` until something sets it."
          },
          "decision_reason_code": {
            "type": "string",
            "nullable": true,
            "description": "Machine-readable reason for the current `status`."
          },
          "decision_reason_label": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable label for `decision_reason_code`."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Convenience copy of the applicant's `vendor_data`."
          },
          "metadata": {
            "type": "object",
            "description": "Snapshot of the `subject` and `counterparty` payloads as submitted at create time."
          },
          "props": {
            "type": "object",
            "description": "The `custom_properties` you supplied at create time. Each key is addressable in rule conditions as `custom_values.<key>`."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                },
                "description": {
                  "type": "string",
                  "nullable": true
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "didit",
                    "custom"
                  ],
                  "description": "Whether the tag is a Didit preset or a custom tag."
                }
              }
            },
            "description": "Tags attached to the transaction (manually or by rules)."
          },
          "parties": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "role": {
                  "type": "string",
                  "enum": [
                    "APPLICANT",
                    "REMITTER",
                    "BENEFICIARY",
                    "COUNTERPARTY"
                  ],
                  "description": "Party role. The create endpoint assigns `APPLICANT` (the subject) and `COUNTERPARTY`."
                },
                "entity_type": {
                  "type": "string",
                  "enum": [
                    "individual",
                    "company",
                    "external",
                    "unhostedWallet"
                  ]
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "USER",
                    "BUSINESS",
                    "EXTERNAL"
                  ],
                  "description": "`USER`/`BUSINESS` parties link back to a Didit-owned entity via `vendor_data`. `EXTERNAL` parties have no Didit entity behind them."
                },
                "vendor_data": {
                  "type": "string",
                  "nullable": true,
                  "description": "Your internal user/business identifier."
                },
                "full_name": {
                  "type": "string",
                  "nullable": true
                },
                "first_name": {
                  "type": "string",
                  "nullable": true
                },
                "last_name": {
                  "type": "string",
                  "nullable": true
                },
                "country_code": {
                  "type": "string",
                  "nullable": true,
                  "description": "Country code from the submitted `address.country` (typically ISO 3166-1 alpha-3)."
                },
                "dob": {
                  "type": "string",
                  "format": "date",
                  "nullable": true,
                  "description": "Date of birth from the submitted `date_of_birth`."
                },
                "address": {
                  "type": "object",
                  "description": "Address object as submitted. `{}` when omitted."
                },
                "institution_info": {
                  "type": "object",
                  "description": "Institution details as submitted. `{}` when omitted."
                },
                "device": {
                  "type": "object",
                  "description": "Normalized device context, including server-side IP enrichment under network_context (geolocation, VPN/data-center flags) when an IP was provided.",
                  "properties": {
                    "fingerprint": {
                      "type": "string",
                      "description": "Unique device fingerprint."
                    },
                    "persistent_device_id": {
                      "type": "string",
                      "description": "Stable cross-session device identifier (v2 fingerprint schema)."
                    },
                    "user_agent": {
                      "type": "string",
                      "description": "Browser or app user agent string."
                    },
                    "browser_family": {
                      "type": "string",
                      "description": "Browser family (e.g. Chrome, Firefox, Safari)."
                    },
                    "browser_version": {
                      "type": "string",
                      "description": "Browser version string."
                    },
                    "platform": {
                      "type": "string",
                      "description": "Platform identifier (web, ios, android, macos, windows, linux)."
                    },
                    "os_family": {
                      "type": "string",
                      "description": "Operating system family (e.g. iOS, Android, Windows)."
                    },
                    "os_version": {
                      "type": "string",
                      "description": "Operating system version string."
                    },
                    "accept_language": {
                      "type": "string",
                      "description": "Accept-Language header value."
                    },
                    "session_id": {
                      "type": "string",
                      "description": "Session identifier (stored in metadata)."
                    },
                    "session_age_ms": {
                      "type": "number",
                      "description": "Session age in milliseconds."
                    },
                    "network_context": {
                      "type": "object",
                      "description": "Network context with IP address and geo-location.",
                      "properties": {
                        "ip_address": {
                          "type": "string",
                          "description": "Client IP address."
                        },
                        "ip_country_code": {
                          "type": "string",
                          "description": "Geo-resolved country of the IP (ISO 3166-1 alpha-3)."
                        },
                        "latitude": {
                          "type": "number",
                          "description": "Geographic latitude of the IP."
                        },
                        "longitude": {
                          "type": "number",
                          "description": "Geographic longitude of the IP."
                        }
                      }
                    }
                  }
                },
                "external_party_snapshot": {
                  "type": "object",
                  "nullable": true,
                  "description": "Frozen copy of the party data for `EXTERNAL` parties. `null` while the party is linked to a Didit user or business."
                }
              }
            },
            "description": "Transaction parties (applicant, counterparty)."
          },
          "payment_methods": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "payment_method_type": {
                  "type": "string",
                  "enum": [
                    "bank_card",
                    "bank_account",
                    "e_wallet",
                    "crypto_wallet",
                    "unhosted_wallet",
                    "other"
                  ]
                },
                "label": {
                  "type": "string",
                  "nullable": true
                },
                "fingerprint": {
                  "type": "string",
                  "nullable": true,
                  "description": "SHA-256 over `type:account_id:issuing_country` — stable identifier to correlate reuse of the same instrument."
                },
                "account_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "Account identifier (IBAN, wallet address, card token, …)."
                },
                "issuing_country": {
                  "type": "string",
                  "nullable": true
                },
                "owner_kind": {
                  "type": "string",
                  "enum": [
                    "USER",
                    "BUSINESS",
                    "EXTERNAL"
                  ]
                },
                "vendor_data": {
                  "type": "string",
                  "nullable": true,
                  "description": "Your identifier for the owning user/business."
                },
                "owner_name": {
                  "type": "string",
                  "nullable": true
                },
                "institution_info": {
                  "type": "object"
                },
                "details": {
                  "type": "object",
                  "description": "Raw `payment_method` object as submitted."
                },
                "external_owner_snapshot": {
                  "type": "object",
                  "nullable": true
                },
                "role": {
                  "type": "string",
                  "enum": [
                    "SOURCE",
                    "DESTINATION",
                    "FUNDING",
                    "BENEFICIARY"
                  ],
                  "description": "How this method was used in the transaction. The create endpoint assigns `SOURCE`/`DESTINATION` from the direction (outbound: subject = SOURCE; inbound: subject = DESTINATION)."
                }
              }
            },
            "description": "Payment methods linked to the transaction."
          },
          "documents": {
            "type": "array",
            "description": "Files attached to the transaction from the console. `[]` when none.",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "label": {
                  "type": "string",
                  "nullable": true
                },
                "note": {
                  "type": "string",
                  "nullable": true
                },
                "uploaded_by": {
                  "type": "string",
                  "nullable": true
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "files": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "uuid": {
                        "type": "string",
                        "format": "uuid"
                      },
                      "file_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "Short-lived signed download URL; fetch it when needed rather than storing it."
                      },
                      "original_filename": {
                        "type": "string",
                        "nullable": true
                      },
                      "file_size": {
                        "type": "integer",
                        "nullable": true
                      }
                    }
                  }
                }
              }
            }
          },
          "activities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "activity_type": {
                  "type": "string",
                  "description": "E.g. `TRANSACTION_CREATED`, `TRANSACTION_NOTE_ADDED`, `TRANSACTION_STATUS_CHANGED`."
                },
                "source": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "nullable": true
                },
                "title": {
                  "type": "string",
                  "nullable": true
                },
                "description": {
                  "type": "string",
                  "nullable": true
                },
                "metadata": {
                  "type": "object"
                },
                "occurred_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            },
            "description": "Activity log entries (creation, notes, manual reviews, status changes)."
          },
          "alerts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": "string",
                  "nullable": true
                },
                "severity": {
                  "type": "string",
                  "enum": [
                    "UNKNOWN",
                    "LOW",
                    "MEDIUM",
                    "HIGH",
                    "CRITICAL"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "OPEN",
                    "INVESTIGATING",
                    "AWAITING_USER",
                    "PENDING_SAR",
                    "SAR_FILED",
                    "RESOLVED",
                    "DISMISSED"
                  ]
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "RULE",
                    "PROVIDER",
                    "MANUAL"
                  ]
                },
                "metadata": {
                  "type": "object"
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "due_at": {
                  "type": "string",
                  "format": "date-time",
                  "nullable": true
                }
              }
            },
            "description": "Alerts raised by rules and providers."
          },
          "rule_runs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "rule": {
                  "type": "string",
                  "format": "uuid",
                  "description": "UUID of the rule that ran."
                },
                "rule_title": {
                  "type": "string"
                },
                "rule_description": {
                  "type": "string",
                  "nullable": true
                },
                "rule_category": {
                  "type": "string"
                },
                "matched": {
                  "type": "boolean",
                  "description": "Whether the rule's conditions matched this transaction. A run is recorded only for matched rules, so live evaluations always carry `true`."
                },
                "is_test": {
                  "type": "boolean",
                  "description": "True when the rule ran in TEST mode (no effect on status/score)."
                },
                "mode": {
                  "type": "string",
                  "enum": [
                    "ACTIVE",
                    "DISABLED",
                    "TEST"
                  ]
                },
                "severity": {
                  "type": "string",
                  "nullable": true
                },
                "score_delta": {
                  "type": "integer",
                  "description": "Score added by this rule's `add_score` actions."
                },
                "status_target": {
                  "type": "string",
                  "nullable": true,
                  "description": "Status set by a `change_status` action, if any."
                },
                "action_summary": {
                  "type": "string",
                  "nullable": true,
                  "description": "Summary of the actions the rule executed, joined with `; ` (e.g. `score +30; change_status:IN_REVIEW; add_tag:high_risk_country`). Parts: `score +N`, `change_status:<STATUS>`, `add_tag:<name>`, `add_note`, `add_to_list`, `open_case`. `null` when the rule executed no action."
                },
                "metadata": {
                  "type": "object",
                  "description": "Evaluation detail: `scope_match`, `conditions[]` and `aggregations[]`. Each condition entry carries `field`, `operator`, `expected_value`, the `current_value` read from the transaction, `matched`, `group_index` and `group_logic`. Each aggregation entry (velocity / count / sum) carries `metric`, `field`, `operator`, `expected_value`, the `computed_value` the aggregate evaluated to, `window`, `filters`, `matched` and `sample_references`; deferred async aggregations have `computed_value: null` and `deferred: true`."
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            },
            "description": "Per-rule execution results — which rule fired, with what score impact."
          },
          "provider_results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "provider": {
                  "type": "string"
                },
                "result_type": {
                  "type": "string",
                  "enum": [
                    "FIAT_MONITORING",
                    "WALLET_SCREENING",
                    "TRANSACTION_SCREENING",
                    "TRAVEL_RULE",
                    "NETWORK_GRAPH",
                    "CUSTOM"
                  ]
                },
                "status": {
                  "type": "string"
                },
                "severity": {
                  "type": "string",
                  "nullable": true
                },
                "score": {
                  "type": "integer"
                },
                "summary": {
                  "type": "string",
                  "nullable": true
                },
                "payload": {
                  "type": "object",
                  "description": "Raw provider response payload."
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            },
            "description": "Raw provider payloads (AML screening, blockchain analytics, etc.)."
          },
          "travel_rule": {
            "type": "object",
            "nullable": true,
            "description": "Travel Rule transfer or check. Populated when `travel_rule_details` was submitted, and also when Travel Rule is enabled and the transaction was created with `transaction_category: travelRule` (Didit initiates the exchange itself, even without `travel_rule_details`). `null` when no transfer or check exists.",
            "properties": {
              "uuid": {
                "type": "string",
                "format": "uuid"
              },
              "status": {
                "type": "string"
              },
              "protocol": {
                "type": "string",
                "nullable": true
              },
              "required": {
                "type": "boolean"
              },
              "obligations_count": {
                "type": "integer"
              },
              "originator_data": {
                "type": "object"
              },
              "beneficiary_data": {
                "type": "object"
              },
              "metadata": {
                "type": "object"
              }
            }
          },
          "network_snapshot": {
            "type": "object",
            "nullable": true,
            "description": "Graph snapshot of related transactions/parties used by the rules engine. Either the `network_snapshot` submitted with the transaction or the graph Didit builds from a successful AML wallet screening (which replaces a submitted one). `null` when neither exists.",
            "properties": {
              "uuid": {
                "type": "string",
                "format": "uuid"
              },
              "nodes": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "edges": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "metrics": {
                "type": "object"
              }
            }
          },
          "remediation": {
            "type": "object",
            "nullable": true,
            "description": "Remediation session offered to the user when re-verification is required. Superseded by `action_required`, which is the canonical block; kept for backward compatibility.",
            "properties": {
              "session_id": {
                "type": "string"
              },
              "session_token": {
                "type": "string"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "status": {
                "type": "string"
              }
            }
          },
          "action_required": {
            "type": "object",
            "nullable": true,
            "description": "Pending end-user action required to complete this transaction, or null when there is none. The Didit SDKs auto-launch the action by default and refresh the transaction when it finishes. Two variants, discriminated by `type`: `verification_session` (a hosted verification session created by a rule action) and `wallet_ownership` (a wallet-ownership widget session auto-minted for a Travel Rule transfer that needs proof of wallet control, gated by the `auto_wallet_verification` Travel Rule setting). When both could apply, `wallet_ownership` takes precedence because it blocks the Travel Rule exchange.",
            "oneOf": [
              {
                "title": "Verification session",
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "verification_session"
                    ]
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Hosted verification URL to open for the end user."
                  },
                  "session_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Verification session id."
                  },
                  "session_token": {
                    "type": "string",
                    "description": "Session token, used by the mobile SDKs to launch the flow natively."
                  },
                  "status": {
                    "type": "string",
                    "description": "Verification session status."
                  }
                },
                "required": [
                  "type",
                  "url"
                ]
              },
              {
                "title": "Wallet ownership",
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "wallet_ownership"
                    ]
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Hosted wallet-ownership widget URL. Open it in a real browser surface - on mobile use SFSafariViewController or a Chrome Custom Tab, never an embedded webview."
                  },
                  "widget_session_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Wallet-ownership widget session id."
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the widget session expires."
                  }
                },
                "required": [
                  "type",
                  "url"
                ]
              }
            ]
          },
          "cost_breakdown": {
            "type": "object",
            "nullable": true,
            "description": "Cost of this transaction: `total_price` and `items`, one per charge, each with `usage_type`, `price`, `details` and `created_at`. A re-screen of the same transaction is a new item."
          }
        }
      },
      "TravelRuleSettingsDetail": {
        "type": "object",
        "properties": {
          "is_enabled": {
            "type": "boolean",
            "description": "Whether the managed Travel Rule negotiation flow is active for outbound `travelRule` transactions on this application."
          },
          "jurisdiction": {
            "type": "string",
            "maxLength": 8,
            "description": "Your VASP's operating jurisdiction code. Default `\"EU\"`."
          },
          "name_matching_strictness": {
            "type": "string",
            "enum": [
              "NONE",
              "STRICT",
              "DEFAULT",
              "FUZZY"
            ],
            "description": "How strictly beneficiary names must match before a transfer can reach COMPLETED."
          },
          "confirmation_timeout_hours": {
            "type": "integer",
            "minimum": 1,
            "description": "Hours an AWAITING_COUNTERPARTY transfer may remain unconfirmed before the periodic sweeper expires it. Default 48."
          },
          "timeout_outcome": {
            "type": "string",
            "enum": [
              "HOLD",
              "REJECT",
              "PROCEED"
            ],
            "description": "What happens to the underlying transaction when a transfer expires. Default HOLD."
          },
          "threshold_amount": {
            "type": "string",
            "description": "Decimal string. Minimum transfer amount that triggers a managed exchange; transfers below it resolve straight to NOT_APPLICABLE. Defaults to \"0.00\" (EU TFR applies no minimum amount)."
          },
          "legal_name": {
            "type": "string",
            "description": "Your VASP's legal name. Required (non-blank) to set is_enabled to true."
          },
          "lei": {
            "type": "string",
            "description": "Your Legal Entity Identifier, surfaced in the VASP directory."
          },
          "compliance_email": {
            "type": "string",
            "format": "email",
            "description": "Compliance contact email for your VASP profile."
          },
          "is_discoverable": {
            "type": "boolean",
            "description": "Whether your VASP profile appears in GET /v3/travel-rule/vasps/ search results and can be reached on the INTERNAL rail. Default true."
          },
          "inbound_auto_accept": {
            "type": "boolean",
            "description": "When true, inbound transfers whose beneficiary wallet is a verified address-book entry with a matching name are accepted automatically, without a manual review step. Default false."
          },
          "allow_self_declaration": {
            "type": "boolean",
            "description": "When true, the wallet-ownership widget offers self-declaration as a fallback proof method. Default false."
          },
          "allow_screenshot_proof": {
            "type": "boolean",
            "description": "When true, the wallet-ownership widget offers screenshot upload as an ownership evidence method. Default true."
          },
          "auto_wallet_verification": {
            "type": "boolean",
            "description": "When true, submitting an outbound Travel Rule transfer that needs end-user proof of wallet control auto-mints a wallet-ownership widget session bound to the transaction and exposes it in the transaction's action_required block. Default true."
          },
          "vasp_attribution_enabled": {
            "type": "boolean",
            "description": "When true, an outbound Travel Rule transfer that no rail can route is attributed through blockchain analytics: the destination wallet is resolved to its owning VASP, the entity is recorded on the transfer and in the VASP directory, and the rails are re-run once with the attributed name. Default true."
          },
          "travel_address": {
            "type": "string",
            "description": "Read-only. Your VASP's own travel address - the encoded inbound TRP inquiry endpoint other VASPs use to reach you. Populated once your VASP profile is complete."
          },
          "disabled_networks": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "GTR",
                "TRUST",
                "VERIFYVASP",
                "SYGNA"
              ]
            },
            "description": "Networks opted out of platform membership. Does not disable your connected own memberships or provision unavailable networks.",
            "default": []
          },
          "networks": {
            "type": "object",
            "readOnly": true,
            "description": "Effective membership configuration for each network. No network, including GTR, is included by default. This is not a live health or delivery check.",
            "properties": {
              "gtr": {
                "type": "object",
                "properties": {
                  "rail": {
                    "type": "string",
                    "enum": [
                      "GTR"
                    ]
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "own",
                      "didit",
                      "off",
                      "unavailable"
                    ],
                    "description": "own: connected customer membership takes precedence; didit: configured platform membership allowed; off: platform routing disabled with no own membership; unavailable: neither membership available."
                  },
                  "platform_available": {
                    "type": "boolean",
                    "description": "Whether platform membership is configured; not a live health check."
                  },
                  "connected": {
                    "type": "boolean",
                    "description": "Whether a connected customer membership exists. Credentials are validated locally; network validation occurs on a live exchange."
                  }
                }
              },
              "trust": {
                "type": "object",
                "properties": {
                  "rail": {
                    "type": "string",
                    "enum": [
                      "TRUST"
                    ]
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "own",
                      "didit",
                      "off",
                      "unavailable"
                    ],
                    "description": "own: connected customer membership takes precedence; didit: configured platform membership allowed; off: platform routing disabled with no own membership; unavailable: neither membership available."
                  },
                  "platform_available": {
                    "type": "boolean",
                    "description": "Whether platform membership is configured; not a live health check."
                  },
                  "connected": {
                    "type": "boolean",
                    "description": "Whether a connected customer membership exists. Credentials are validated locally; network validation occurs on a live exchange."
                  }
                }
              },
              "verifyvasp": {
                "type": "object",
                "properties": {
                  "rail": {
                    "type": "string",
                    "enum": [
                      "VERIFYVASP"
                    ]
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "own",
                      "didit",
                      "off",
                      "unavailable"
                    ],
                    "description": "own: connected customer membership takes precedence; didit: configured platform membership allowed; off: platform routing disabled with no own membership; unavailable: neither membership available."
                  },
                  "platform_available": {
                    "type": "boolean",
                    "description": "Whether platform membership is configured; not a live health check."
                  },
                  "connected": {
                    "type": "boolean",
                    "description": "Whether a connected customer membership exists. Credentials are validated locally; network validation occurs on a live exchange."
                  }
                }
              },
              "sygna": {
                "type": "object",
                "properties": {
                  "rail": {
                    "type": "string",
                    "enum": [
                      "SYGNA"
                    ]
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "own",
                      "didit",
                      "off",
                      "unavailable"
                    ],
                    "description": "own: connected customer membership takes precedence; didit: configured platform membership allowed; off: platform routing disabled with no own membership; unavailable: neither membership available."
                  },
                  "platform_available": {
                    "type": "boolean",
                    "description": "Whether platform membership is configured; not a live health check."
                  },
                  "connected": {
                    "type": "boolean",
                    "description": "Whether a connected customer membership exists. Credentials are validated locally; network validation occurs on a live exchange."
                  }
                }
              }
            }
          }
        }
      },
      "TravelRuleSettingsUpdate": {
        "type": "object",
        "properties": {
          "is_enabled": {
            "type": "boolean"
          },
          "legal_name": {
            "type": "string"
          },
          "lei": {
            "type": "string"
          },
          "jurisdiction": {
            "type": "string",
            "maxLength": 8
          },
          "name_matching_strictness": {
            "type": "string",
            "enum": [
              "NONE",
              "STRICT",
              "DEFAULT",
              "FUZZY"
            ]
          },
          "confirmation_timeout_hours": {
            "type": "integer",
            "minimum": 1
          },
          "timeout_outcome": {
            "type": "string",
            "enum": [
              "HOLD",
              "REJECT",
              "PROCEED"
            ]
          },
          "compliance_email": {
            "type": "string",
            "format": "email"
          },
          "is_discoverable": {
            "type": "boolean"
          },
          "threshold_amount": {
            "type": "string",
            "description": "Decimal string. Minimum transfer amount that triggers a managed exchange."
          },
          "inbound_auto_accept": {
            "type": "boolean"
          },
          "allow_self_declaration": {
            "type": "boolean"
          },
          "allow_screenshot_proof": {
            "type": "boolean",
            "description": "When true, the wallet-ownership widget offers screenshot upload as an ownership evidence method. Default true."
          },
          "auto_wallet_verification": {
            "type": "boolean"
          },
          "vasp_attribution_enabled": {
            "type": "boolean"
          },
          "disabled_networks": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "GTR",
                "TRUST",
                "VERIFYVASP",
                "SYGNA"
              ]
            },
            "description": "Networks opted out of platform membership. Does not disable your connected own memberships or provision unavailable networks.",
            "default": []
          }
        },
        "description": "All fields optional; PUT applies a partial update."
      },
      "WalletAddressEntry": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "address": {
            "type": "string",
            "description": "The wallet address. Unique per application and chain among non-deleted entries."
          },
          "chain": {
            "type": "string",
            "nullable": true,
            "description": "Free-text chain identifier, e.g. \"ethereum\", \"bitcoin\"."
          },
          "holder_vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your internal identifier for the holder."
          },
          "holder_name": {
            "type": "string",
            "nullable": true,
            "description": "Name of the wallet holder, used for the beneficiary name match."
          },
          "entity_type": {
            "type": "string",
            "description": "Free text, defaults to \"individual\"."
          },
          "is_ownership_verified": {
            "type": "boolean",
            "description": "Read-only. Whether ownership of this address has been proven."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "self_declared": {
            "type": "boolean",
            "description": "Whether the entry was created as a self-declared ownership proof."
          },
          "travel_address": {
            "type": "string",
            "nullable": true,
            "description": "The counterparty VASP's travel address for this wallet, if known. Lets Didit route this beneficiary's transfers over the TRP rail."
          }
        }
      },
      "WalletAddressEntryCreate": {
        "type": "object",
        "required": [
          "address"
        ],
        "properties": {
          "address": {
            "type": "string"
          },
          "chain": {
            "type": "string"
          },
          "holder_vendor_data": {
            "type": "string"
          },
          "holder_name": {
            "type": "string"
          },
          "entity_type": {
            "type": "string",
            "default": "individual"
          },
          "self_declared": {
            "type": "boolean",
            "default": false,
            "description": "Write-only. When true, the entry is created already ownership-verified via a SELF_DECLARATION proof."
          },
          "travel_address": {
            "type": "string",
            "description": "Optional. The counterparty VASP's travel address for this wallet, enabling TRP routing."
          }
        }
      },
      "WalletAddressEntryUpdate": {
        "type": "object",
        "properties": {
          "holder_name": {
            "type": "string"
          },
          "holder_vendor_data": {
            "type": "string"
          },
          "entity_type": {
            "type": "string"
          },
          "travel_address": {
            "type": "string"
          }
        },
        "description": "PATCH is a partial update; the response echoes only holder_name, holder_vendor_data, entity_type, and travel_address."
      },
      "TravelRuleTransferDetail": {
        "type": "object",
        "description": "Full transfer object returned by the ownership-confirmation and finish/cancel endpoints. originator_data/beneficiary_data are omitted while PII is masked (see description).",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "AWAITING_COUNTERPARTY",
              "ON_HOLD",
              "COMPLETED",
              "FINISHED",
              "CANCELLED",
              "EXPIRED",
              "COUNTERPARTY_MISMATCHED_DATA",
              "COUNTERPARTY_VASP_NOT_FOUND",
              "COUNTERPARTY_VASP_NOT_REACHABLE",
              "UNCONFIRMED_OWNERSHIP",
              "COUNTERPARTY_VASP_GENERAL_DECLINE",
              "NOT_ENOUGH_COUNTERPARTY_DATA",
              "NOT_APPLICABLE"
            ]
          },
          "direction": {
            "type": "string",
            "enum": [
              "INBOUND",
              "OUTBOUND"
            ]
          },
          "rail": {
            "type": "string",
            "nullable": true,
            "enum": [
              "INTERNAL",
              "TRP",
              "GTR",
              "EMAIL",
              null
            ]
          },
          "protocol": {
            "type": "string",
            "nullable": true
          },
          "ivms_version": {
            "type": "string",
            "example": "ivms101.2023"
          },
          "required": {
            "type": "boolean"
          },
          "ownership_confirmed": {
            "type": "boolean",
            "nullable": true
          },
          "deadline_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "timeline": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "detail": {
                  "type": "string"
                }
              }
            }
          },
          "counterparty_vasp": {
            "type": "object",
            "nullable": true,
            "properties": {
              "name": {
                "type": "string"
              },
              "lei": {
                "type": "string"
              },
              "dd_score": {
                "type": "integer"
              }
            }
          },
          "originator_data": {
            "type": "object"
          },
          "beneficiary_data": {
            "type": "object"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TravelRuleOwnershipConfirmRequest": {
        "type": "object",
        "required": [
          "confirmed"
        ],
        "properties": {
          "confirmed": {
            "type": "boolean"
          }
        }
      },
      "TravelRuleTransferPatchRequest": {
        "type": "object",
        "description": "Provide exactly one of: payment_txn_id (finish), action=cancel, or action=resend.",
        "properties": {
          "payment_txn_id": {
            "type": "string",
            "description": "The on-chain transaction hash. Requires the transfer to be an outbound transfer in COMPLETED status."
          },
          "action": {
            "type": "string",
            "enum": [
              "cancel",
              "resend"
            ],
            "description": "\"cancel\" cancels a non-terminal transfer. \"resend\" re-runs routing for an outbound transfer stuck in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA."
          }
        }
      },
      "VaspDirectoryEntry": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "lei": {
            "type": "string"
          },
          "jurisdiction": {
            "type": "string"
          },
          "dd_status": {
            "type": "string",
            "enum": [
              "NOT_STARTED",
              "IN_PROGRESS",
              "COMPLETED",
              "REJECTED"
            ]
          },
          "dd_score": {
            "type": "integer"
          },
          "reachable_rails": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "INTERNAL",
                "TRP",
                "GTR",
                "EMAIL"
              ]
            }
          },
          "is_didit_customer": {
            "type": "boolean",
            "description": "true for discoverable Didit applications (dd_status is always COMPLETED, dd_score always 0 for these); false for internal counterparty-registry rows, which carry a real due-diligence status and score."
          },
          "dd_score_breakdown": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            },
            "description": "Per-component contributions to dd_score (licensing/registry, sanctions/PEP, jurisdiction risk, on-chain analytics risk), all derived from checks Didit runs in-house. Empty for Didit-customer rows."
          },
          "dd_assessed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the due-diligence assessment last ran. Null for Didit-customer rows."
          }
        }
      },
      "TravelRulePickupInfo": {
        "type": "object",
        "properties": {
          "originator_vasp_name": {
            "type": "string"
          },
          "amount": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "beneficiary_wallet": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "TravelRulePickupRespondRequest": {
        "type": "object",
        "required": [
          "decision"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "enum": [
              "accept",
              "decline"
            ]
          },
          "beneficiary_name": {
            "type": "string",
            "description": "Required in practice for decision=accept; run through the originator's name_matching_strictness policy."
          }
        }
      },
      "TravelRuleInboundRequest": {
        "type": "object",
        "required": [
          "chain",
          "txid",
          "wallet_address",
          "amount",
          "currency"
        ],
        "properties": {
          "chain": {
            "type": "string",
            "description": "Chain the deposit settled on, e.g. \"ethereum\"."
          },
          "txid": {
            "type": "string",
            "description": "On-chain transaction hash. Deduped together with wallet_address."
          },
          "wallet_address": {
            "type": "string",
            "description": "The destination wallet you received the deposit on."
          },
          "amount": {
            "type": "string",
            "description": "Deposit amount as a decimal string."
          },
          "currency": {
            "type": "string",
            "description": "Deposit asset, e.g. \"USDC\"."
          },
          "originator_data": {
            "type": "object",
            "description": "IVMS-101 originator payload from the sending VASP, if known.",
            "additionalProperties": true
          },
          "beneficiary_data": {
            "type": "object",
            "description": "IVMS-101 beneficiary payload (your customer).",
            "additionalProperties": true
          },
          "originating_vasp": {
            "type": "object",
            "description": "Optional description of the sending VASP.",
            "properties": {
              "name": {
                "type": "string"
              },
              "lei": {
                "type": "string"
              },
              "travel_address": {
                "type": "string",
                "description": "Travel address that lets Didit reach the sender on the TRP rail."
              }
            }
          }
        }
      },
      "TravelRuleInboundResponse": {
        "type": "object",
        "properties": {
          "transaction_id": {
            "type": "string",
            "format": "uuid",
            "description": "Didit transaction UUID for the inbound deposit."
          },
          "txn_id": {
            "type": "string",
            "description": "Didit-generated txn_id for the sunrise transaction."
          },
          "created": {
            "type": "boolean",
            "description": "true when a new transaction was minted (HTTP 201); false when an existing unclaimed deposit was reused (HTTP 200)."
          },
          "travel_rule": {
            "$ref": "#/components/schemas/TravelRuleTransferDetail"
          }
        }
      },
      "TravelRuleWidgetSessionCreate": {
        "type": "object",
        "required": [
          "wallet_address",
          "chain"
        ],
        "properties": {
          "wallet_address": {
            "type": "string",
            "description": "The wallet address to verify."
          },
          "chain": {
            "type": "string",
            "description": "Chain identifier for the address, e.g. \"ethereum\", \"bitcoin\", \"solana\"."
          },
          "holder_name": {
            "type": "string",
            "description": "Name of the wallet holder, used for the beneficiary name match."
          },
          "vendor_data": {
            "type": "string",
            "description": "Your internal identifier for the holder, carried onto the created address-book entry."
          },
          "transaction_id": {
            "type": "string",
            "format": "uuid",
            "description": "Optional. Didit transaction UUID of a Travel Rule transfer to advance when the proof verifies."
          },
          "satoshi_deposit_address": {
            "type": "string",
            "description": "Optional. A deposit address you control; supplying it enables the SATOSHI_TEST proof method."
          },
          "callback_url": {
            "type": "string",
            "description": "Optional. Where the widget returns the customer after completion."
          },
          "expires_in_minutes": {
            "type": "integer",
            "description": "Optional. Lifetime of the minted link, in minutes. Automatically extended to cover the Satoshi test window when SATOSHI_TEST is offered."
          }
        }
      },
      "TravelRuleWidgetSessionResponse": {
        "type": "object",
        "properties": {
          "widget_session_id": {
            "type": "string",
            "format": "uuid"
          },
          "token": {
            "type": "string",
            "description": "Opaque session token embedded in the widget URL."
          },
          "url": {
            "type": "string",
            "description": "The hosted wallet-ownership widget URL. Open it verbatim in the system browser (never inside a mobile SDK webview)."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TravelRuleWidgetContext": {
        "type": "object",
        "properties": {
          "vasp_name": {
            "type": "string",
            "description": "Legal name from your VASP profile, shown to the customer in the widget. Empty when no profile exists."
          },
          "wallet_address": {
            "type": "string"
          },
          "chain": {
            "type": "string"
          },
          "holder_name": {
            "type": "string"
          },
          "allowed_methods": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "MESSAGE_SIGNING",
                "SCREENSHOT",
                "SATOSHI_TEST",
                "SELF_DECLARATION"
              ]
            },
            "description": "Proof methods available for this session. MESSAGE_SIGNING requires a supported chain family, SATOSHI_TEST requires a satoshi_deposit_address on the session, SCREENSHOT requires the allow_screenshot_proof setting, and SELF_DECLARATION requires the allow_self_declaration setting."
          },
          "transfer_status": {
            "type": "string",
            "nullable": true,
            "description": "Status of the linked Travel Rule transfer. Null when the session was minted without a transaction_id."
          },
          "callback_url": {
            "type": "string",
            "description": "Where the widget returns the customer after completion. Empty when not set."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Non-null once a proof has been verified."
          },
          "proofs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TravelRuleWidgetProofSummary"
            }
          },
          "customization": {
            "type": "object",
            "nullable": true,
            "description": "The application's whitelabel customization (colors, logo, font family) when white label is enabled - the widget renders with the same branding as the verification flow. Null otherwise."
          }
        }
      },
      "TravelRuleWidgetProofSummary": {
        "type": "object",
        "properties": {
          "proof_id": {
            "type": "string",
            "format": "uuid"
          },
          "method": {
            "type": "string",
            "enum": [
              "MESSAGE_SIGNING",
              "SATOSHI_TEST",
              "SCREENSHOT",
              "SELF_DECLARATION"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "VERIFIED",
              "REJECTED",
              "EXPIRED"
            ],
            "description": "PENDING on a SATOSHI_TEST proof means the deposit has been seen on-chain but has not yet reached enough confirmations; a background job automatically rechecks it and moves it to VERIFIED once it confirms, with no resubmission needed. REJECTED means a genuinely wrong deposit was submitted (absent, wrong sender, or wrong amount). EXPIRED means the proof's own test window closed before a valid deposit was seen."
          },
          "wallet_address": {
            "type": "string"
          },
          "chain": {
            "type": "string"
          },
          "deposit_address": {
            "type": "string",
            "nullable": true,
            "description": "Deposit address the customer must send the Satoshi test amount to. Present only on a SATOSHI_TEST proof."
          },
          "expected_amount": {
            "type": "string",
            "nullable": true,
            "description": "Exact on-chain amount, in the deposit's native currency, the Satoshi test deposit must match. Present only on a SATOSHI_TEST proof."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Deadline for this proof's own Satoshi test window. Present only on a SATOSHI_TEST proof; the widget session's own expires_at is extended to cover it when SATOSHI_TEST is offered."
          },
          "challenge": {
            "type": "string",
            "nullable": true,
            "description": "Didit-issued message the customer signs with their wallet. Present only on a MESSAGE_SIGNING proof."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CaseSubject": {
        "type": "object",
        "nullable": true,
        "description": "The single user or business the case is anchored to.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "user",
              "business"
            ]
          },
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "nullable": true,
            "description": "The subject's vendor_data."
          }
        }
      },
      "CaseAssignee": {
        "type": "object",
        "nullable": true,
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "full_name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "CaseBlueprintSummary": {
        "type": "object",
        "nullable": true,
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "maxLength": 24
          }
        }
      },
      "CaseContentConfig": {
        "type": "object",
        "description": "The six togglable sections that drive which tabs and fields appear on the case page. Unknown sections or keys are rejected.",
        "properties": {
          "checklist": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "optional": {
                "type": "boolean",
                "description": "When true, a case can be resolved with incomplete checklist items."
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": "string",
                      "maxLength": 255
                    },
                    "order": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "aml_control": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "financial": {
                "type": "boolean"
              },
              "identity": {
                "type": "boolean"
              }
            }
          },
          "identity": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "personal_information": {
                "type": "boolean"
              },
              "applicant_tags": {
                "type": "boolean"
              },
              "contact_information": {
                "type": "boolean"
              },
              "risk_overview": {
                "type": "boolean"
              },
              "poi_documents": {
                "type": "boolean"
              },
              "poa_documents": {
                "type": "boolean"
              }
            }
          },
          "verifications": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "summary": {
                "type": "boolean"
              }
            }
          },
          "reporting": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "fiu_reports": {
                "type": "boolean"
              }
            }
          },
          "financial": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "payment_methods": {
                "type": "boolean"
              },
              "transactions": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "CaseNote": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "comment": {
            "type": "string"
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "actor_name": {
            "type": "string",
            "nullable": true
          },
          "mentioned_emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "is_internal": {
            "type": "boolean"
          },
          "attachments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "s3_key": {
                  "type": "string"
                },
                "filename": {
                  "type": "string"
                },
                "file_size": {
                  "type": "integer"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CaseEvent": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "event_type": {
            "type": "string",
            "enum": [
              "CREATED",
              "STATUS_CHANGED",
              "ASSIGNED",
              "UNASSIGNED",
              "RESOLVED",
              "REOPENED",
              "LINK_ADDED",
              "LINK_REMOVED",
              "NOTE_ADDED",
              "PRIORITY_CHANGED",
              "DUE_DATE_CHANGED",
              "TAG_ADDED",
              "TAG_REMOVED",
              "ESCALATED",
              "TRANSFERRED",
              "CHECKLIST_COMPLETED",
              "REPORT_CREATED",
              "REPORT_FINALIZED",
              "SUBMITTED_FOR_APPROVAL",
              "APPROVAL_GRANTED",
              "APPROVAL_REJECTED",
              "ENTITY_ACTION",
              "APPROVAL_INVALIDATED"
            ]
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "actor_name": {
            "type": "string",
            "nullable": true
          },
          "previous_status": {
            "type": "string",
            "enum": [
              "OPEN",
              "AWAITING_USER",
              "RESOLVED"
            ],
            "nullable": true
          },
          "new_status": {
            "type": "string",
            "enum": [
              "OPEN",
              "AWAITING_USER",
              "RESOLVED"
            ],
            "nullable": true
          },
          "metadata": {
            "type": "object"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CaseLink": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "linked_entity_type": {
            "type": "string",
            "enum": [
              "session",
              "business_session",
              "transaction"
            ],
            "nullable": true
          },
          "linked_entity_uuid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "linked_entity_summary": {
            "type": "object",
            "nullable": true,
            "description": "session_id/session_number/status for session and business_session links; uuid/txn_id/status for transaction links."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CaseChecklistItem": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "label": {
            "type": "string",
            "maxLength": 255
          },
          "is_completed": {
            "type": "boolean"
          },
          "completed_by": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "order": {
            "type": "integer"
          }
        }
      },
      "CaseBlueprintListItem": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "maxLength": 24
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "assignment_method": {
            "type": "string",
            "enum": [
              "MANUAL",
              "AUTOMATIC"
            ]
          },
          "assignee_pool": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "max_active_cases": {
            "type": "integer",
            "nullable": true
          },
          "escalation_enabled": {
            "type": "boolean"
          },
          "transfer_enabled": {
            "type": "boolean"
          },
          "require_resolution_note": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          },
          "preset_key": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "readOnly": true
          },
          "default_deadline_hours": {
            "type": "integer",
            "nullable": true,
            "minimum": 1,
            "maximum": 8760
          }
        }
      },
      "CaseBlueprintDetail": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "maxLength": 24
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "assignment_method": {
            "type": "string",
            "enum": [
              "MANUAL",
              "AUTOMATIC"
            ]
          },
          "assignee_pool": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "max_active_cases": {
            "type": "integer",
            "nullable": true
          },
          "escalation_enabled": {
            "type": "boolean"
          },
          "transfer_enabled": {
            "type": "boolean"
          },
          "require_resolution_note": {
            "type": "boolean"
          },
          "is_active": {
            "type": "boolean"
          },
          "preset_key": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "escalation_blueprint": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "escalation_blueprint_name": {
            "type": "string",
            "nullable": true
          },
          "four_eyes_checker_blueprint": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "four_eyes_checker_blueprint_name": {
            "type": "string",
            "nullable": true
          },
          "content_config": {
            "type": "object",
            "description": "The six togglable sections that drive which tabs and fields appear on the case page. Unknown sections or keys are rejected.",
            "properties": {
              "checklist": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "optional": {
                    "type": "boolean",
                    "description": "When true, a case can be resolved with incomplete checklist items."
                  },
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "label": {
                          "type": "string",
                          "maxLength": 255
                        },
                        "order": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              },
              "aml_control": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "financial": {
                    "type": "boolean"
                  },
                  "identity": {
                    "type": "boolean"
                  }
                }
              },
              "identity": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "personal_information": {
                    "type": "boolean"
                  },
                  "applicant_tags": {
                    "type": "boolean"
                  },
                  "contact_information": {
                    "type": "boolean"
                  },
                  "risk_overview": {
                    "type": "boolean"
                  },
                  "poi_documents": {
                    "type": "boolean"
                  },
                  "poa_documents": {
                    "type": "boolean"
                  }
                }
              },
              "verifications": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "summary": {
                    "type": "boolean"
                  }
                }
              },
              "reporting": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "fiu_reports": {
                    "type": "boolean"
                  }
                }
              },
              "financial": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "payment_methods": {
                    "type": "boolean"
                  },
                  "transactions": {
                    "type": "boolean"
                  }
                }
              }
            }
          },
          "creation_sources": {
            "type": "array",
            "description": "Connectors currently routing new cases into this blueprint.",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "aml",
                    "rule",
                    "workflow"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "receives_escalation_from": {
            "type": "array",
            "description": "Other blueprints whose Escalation target points at this one.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "readOnly": true
          },
          "default_deadline_hours": {
            "type": "integer",
            "nullable": true,
            "minimum": 1,
            "maximum": 8760
          }
        }
      },
      "CaseListItem": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "case_number": {
            "type": "string",
            "nullable": true,
            "description": "Auto-assigned, e.g. CS-0001."
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "AWAITING_USER",
              "RESOLVED"
            ]
          },
          "resolution": {
            "type": "string",
            "enum": [
              "FALSE_POSITIVE",
              "VALID_THREAT"
            ],
            "nullable": true
          },
          "priority": {
            "type": "string",
            "enum": [
              "LOW",
              "MEDIUM",
              "HIGH"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "MANUAL",
              "AML_SCREENING",
              "TRANSACTION_RULE",
              "WORKFLOW_BUILDER"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "subject": {
            "$ref": "#/components/schemas/CaseSubject"
          },
          "assigned_to": {
            "$ref": "#/components/schemas/CaseAssignee"
          },
          "assigned_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_by_email": {
            "type": "string",
            "nullable": true
          },
          "created_by_name": {
            "type": "string",
            "nullable": true
          },
          "blueprint": {
            "$ref": "#/components/schemas/CaseBlueprintSummary"
          },
          "links_count": {
            "type": "integer"
          },
          "notes_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "application_id": {
            "type": "string",
            "format": "uuid"
          },
          "application_name": {
            "type": "string"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_name": {
            "type": "string"
          }
        }
      },
      "CaseDetail": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "case_number": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "AWAITING_USER",
              "RESOLVED"
            ]
          },
          "resolution": {
            "type": "string",
            "enum": [
              "FALSE_POSITIVE",
              "VALID_THREAT"
            ],
            "nullable": true
          },
          "resolution_notes": {
            "type": "string",
            "nullable": true
          },
          "priority": {
            "type": "string",
            "enum": [
              "LOW",
              "MEDIUM",
              "HIGH"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "MANUAL",
              "AML_SCREENING",
              "TRANSACTION_RULE",
              "WORKFLOW_BUILDER"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "subject": {
            "$ref": "#/components/schemas/CaseSubject"
          },
          "assigned_to": {
            "$ref": "#/components/schemas/CaseAssignee"
          },
          "assigned_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolved_by_email": {
            "type": "string",
            "nullable": true
          },
          "pending_resolution": {
            "type": "object",
            "nullable": true,
            "description": "Set only while a 4-eyes resolution is staged on the checker blueprint, awaiting approve or reject-approval.",
            "properties": {
              "resolution": {
                "type": "string",
                "enum": [
                  "FALSE_POSITIVE",
                  "VALID_THREAT"
                ]
              },
              "resolution_notes": {
                "type": "string",
                "nullable": true
              },
              "maker_email": {
                "type": "string",
                "format": "email"
              },
              "maker_name": {
                "type": "string",
                "nullable": true
              },
              "maker_blueprint_id": {
                "type": "string",
                "format": "uuid"
              },
              "staged_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "metadata": {
            "type": "object"
          },
          "blueprint": {
            "$ref": "#/components/schemas/CaseBlueprintDetail"
          },
          "notes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseNote"
            },
            "description": "Newest 50 notes."
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseEvent"
            },
            "description": "Newest 100 events."
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseLink"
            }
          },
          "links_count": {
            "type": "integer"
          },
          "notes_count": {
            "type": "integer"
          },
          "checklist_items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseChecklistItem"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ReportTemplateDetail": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "jurisdiction": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO 3166-1 alpha-2 country code."
          },
          "report_type": {
            "type": "string",
            "enum": [
              "SAR",
              "STR",
              "CTR",
              "TTR",
              "UTR",
              "IFT",
              "CBR",
              "TFR"
            ]
          },
          "report_type_display": {
            "type": "string"
          },
          "field_config": {
            "type": "object",
            "description": "Reusable goAML header defaults. Template-level obligatory fields: rentity_id, submission_code, and currency_code_local (3-letter). Optional: enabled_fields (which optional report blocks to include) plus reporting_person, location, reason, and action defaults. Per-filing header fields (action, submission_date, transactions, jurisdiction) are enforced when the report is validated or finalized, not on the template."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RegulatoryReportDetail": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "case_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "case_number": {
            "type": "string",
            "nullable": true
          },
          "report_type": {
            "type": "string",
            "enum": [
              "SAR",
              "STR",
              "CTR",
              "TTR",
              "UTR",
              "IFT",
              "CBR",
              "TFR"
            ]
          },
          "report_type_display": {
            "type": "string"
          },
          "report_code": {
            "type": "string",
            "description": "goAML report code derived from report_type, e.g. STR, CTR, BCR."
          },
          "report_number": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "VALIDATED",
              "FINALIZED"
            ]
          },
          "status_display": {
            "type": "string"
          },
          "jurisdiction": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2
          },
          "rentity_id": {
            "type": "string",
            "nullable": true,
            "description": "Reporting entity ID issued by the FIU."
          },
          "rentity_branch": {
            "type": "string",
            "nullable": true
          },
          "submission_code": {
            "type": "string",
            "enum": [
              "E",
              "M"
            ]
          },
          "entity_reference": {
            "type": "string",
            "nullable": true
          },
          "fiu_ref_number": {
            "type": "string",
            "nullable": true
          },
          "currency_code_local": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3,
            "nullable": true
          },
          "submission_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "reporting_person": {
            "type": "object"
          },
          "location": {
            "type": "object"
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "action": {
            "type": "string",
            "nullable": true
          },
          "activity": {
            "type": "string",
            "nullable": true
          },
          "narrative": {
            "type": "object",
            "description": "Five Ws narrative sections.",
            "properties": {
              "who": {
                "type": "string"
              },
              "what": {
                "type": "string"
              },
              "when": {
                "type": "string"
              },
              "where": {
                "type": "string"
              },
              "why": {
                "type": "string"
              },
              "how": {
                "type": "string"
              }
            }
          },
          "report_indicators": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "included_fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "transactions": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "validation_errors": {
            "type": "array",
            "description": "Result of the most recent validation; each entry is a {field, message} object.",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "validated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finalized_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_by_email": {
            "type": "string",
            "nullable": true
          },
          "created_by_name": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TransactionRuleCondition": {
        "type": "object",
        "required": [
          "field",
          "operator"
        ],
        "properties": {
          "field": {
            "type": "string",
            "description": "Transaction field path to evaluate. Core fields: amount, currency, direction, action_type, score, severity, transaction_type, payment_details, preferred_currency_amount (falls back to amount_in_default_currency), default_currency_code, subject_country, counterparty_country, subject_vendor_data, counterparty_vendor_data, subject_device_fingerprint, counterparty_device_fingerprint, subject_browser_family, subject_browser_version, subject_platform, subject_accept_language, subject_session_age_ms, subject_ip_country, counterparty_ip_country, subject_ip_address, counterparty_ip_address, subject_payment_method_type, subject_payment_method_country, subject_payment_method_fingerprint, subject_payment_method_account_id (and the counterparty_payment_method_* equivalents), travel_rule_status, travel_rule_required, travel_rule_obligations_count, subject_days_since_previous_transaction, tags, and custom_values.<key> for any key submitted in custom_properties on transaction create. Country-code fields accept ISO-2 or ISO-3; both sides are normalized to ISO-3 before comparison."
          },
          "operator": {
            "type": "string",
            "enum": [
              "eq",
              "ne",
              "gt",
              "gte",
              "lt",
              "lte",
              "in",
              "not_in",
              "contains",
              "not_contains",
              "contains_any",
              "regex",
              "fuzzy_match",
              "exists",
              "is_not_empty",
              "is_not_null",
              "not_exists",
              "is_empty",
              "is_null"
            ],
            "description": "Comparison operator. in/not_in test membership (value may be a list or a single scalar). contains/not_contains are case-insensitive substring checks against a string value. contains_any takes a list of strings and matches when any is a case-insensitive substring of the field value. regex matches the value pattern against the field. fuzzy_match compares against the value string with the required `score` threshold (0-100). gt/gte/lt/lte never match when either side is missing. exists/is_not_empty/is_not_null (aliases) and not_exists/is_empty/is_null (aliases) are presence checks that ignore `value`."
          },
          "value": {
            "description": "Comparison value. Its shape depends on the operator and value_type; omit for the presence-check operators."
          },
          "value_type": {
            "type": "string",
            "enum": [
              "list",
              "field",
              "relative_date"
            ],
            "description": "Optional value interpretation. `list`: value is a List UUID and the list's entries become the comparison value. `field`: value is another field path, compared field-to-field. `relative_date`: value is a relative-date object, e.g. {\"direction\": \"past\", \"unit\": \"days\", \"amount\": 30}."
          },
          "score": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Required when operator is fuzzy_match: the 0-100 similarity threshold."
          },
          "group_index": {
            "type": "integer",
            "description": "Optional grouped logic. When any condition carries group_index, conditions sharing an index form a group and grouped evaluation replaces evaluation_mode."
          },
          "group_logic": {
            "type": "string",
            "enum": [
              "AND",
              "OR"
            ],
            "default": "AND",
            "description": "How conditions combine WITHIN a group."
          },
          "groups_logic": {
            "type": "string",
            "enum": [
              "AND",
              "OR"
            ],
            "default": "OR",
            "description": "How group outcomes combine ACROSS groups. Read from the first condition."
          }
        },
        "description": "A condition reads only the transaction being evaluated - it never filters the aggregation window."
      },
      "TransactionRuleAggregation": {
        "type": "object",
        "required": [
          "value"
        ],
        "properties": {
          "metric": {
            "type": "string",
            "enum": [
              "count",
              "sum",
              "max",
              "min",
              "avg",
              "distinct_count"
            ],
            "default": "count",
            "description": "How the matching historical transactions are aggregated. unique_count is accepted as an alias of distinct_count."
          },
          "field": {
            "type": "string",
            "default": "amount",
            "description": "Field aggregated by sum/max/min/avg/distinct_count. Ignored for count."
          },
          "operator": {
            "type": "string",
            "enum": [
              "eq",
              "ne",
              "gt",
              "gte",
              "lt",
              "lte"
            ],
            "default": "eq",
            "description": "Comparison applied to the computed metric."
          },
          "value": {
            "type": "number",
            "description": "Threshold the computed metric is compared against."
          },
          "window": {
            "type": "string",
            "pattern": "^\\d+(m|h|d)$",
            "default": "1d",
            "description": "Look-back window ending at the transaction's txn_date: <N>m (MINUTES, not months), <N>h (hours) or <N>d (days), e.g. 30m, 24h, 7d, 30d."
          },
          "filters": {
            "type": "object",
            "additionalProperties": true,
            "description": "Narrows which historical transactions are aggregated. Keys are field paths from the condition field catalog; a value of \"__current__\" resolves to the same field's value on the transaction being evaluated (e.g. {\"subject_vendor_data\": \"__current__\"} scopes the window to the same subject), and a list value means membership. Filters compare by equality or membership ONLY - there is no lt/gte filter, so a range such as \"historical transactions under 10,000\" cannot be expressed here. Put the range on the metric instead (metric max with operator lt keeps every transaction in the window below the threshold)."
          }
        },
        "description": "Velocity check over the application's historical transactions inside the window. Every aggregation entry must match for the rule to match, regardless of evaluation_mode. An aggregation constrains only the window; the transaction being evaluated is constrained by scope and conditions, so repeat direction, currency or transaction_type on both halves when the rule promises them."
      },
      "TransactionRuleScope": {
        "type": "object",
        "properties": {
          "transaction_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict to transaction types, e.g. finance, kyc, travel_rule, user_event. Empty or missing = no restriction."
          },
          "directions": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "INBOUND",
                "OUTBOUND"
              ]
            },
            "description": "Restrict to transaction directions (case-insensitive on write)."
          },
          "action_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict to your action_type values, e.g. withdrawal, deposit."
          }
        },
        "description": "Which transactions the rule applies to. Only these three keys are accepted."
      },
      "TransactionRuleAction": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "type",
              "value"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "add_score"
                ]
              },
              "value": {
                "type": "integer",
                "description": "Points added to the transaction's risk score. May be negative."
              }
            },
            "description": "Add points to the transaction's cumulative risk score; the total decides the status via the application's review/decline thresholds."
          },
          {
            "type": "object",
            "required": [
              "type",
              "value"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "change_status"
                ]
              },
              "value": {
                "type": "string",
                "enum": [
                  "APPROVED",
                  "IN_REVIEW",
                  "DECLINED",
                  "AWAITING_USER"
                ],
                "description": "Status to set immediately, regardless of score. Alias key: status."
              },
              "workflow_id": {
                "type": "string",
                "format": "uuid",
                "description": "REQUIRED when value is AWAITING_USER: the verification workflow the subject is asked to complete. Alias key: remediation_workflow_id. Didit creates a hosted remediation session for the subject when the rule fires."
              }
            },
            "description": "Directly set the transaction status. DECLINED always wins across matched rules."
          },
          {
            "type": "object",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "add_tags"
                ]
              },
              "tag_uuid": {
                "type": "string",
                "format": "uuid",
                "description": "Existing application tag to attach."
              },
              "tag_name": {
                "type": "string",
                "description": "Tag name to attach; created on first use (stored uppercased). Provide tag_uuid or tag_name."
              },
              "tag_color": {
                "type": "string",
                "description": "Hex color used when tag_name creates a new tag, e.g. #007AFE."
              }
            },
            "description": "Attach an application tag to the matched transaction."
          },
          {
            "type": "object",
            "required": [
              "type",
              "note"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "add_note"
                ]
              },
              "note": {
                "type": "string",
                "description": "Note text attached to the transaction (author: Rule Engine). Alias key: value."
              }
            },
            "description": "Attach an automated analyst note to the matched transaction."
          },
          {
            "type": "object",
            "required": [
              "type",
              "list_id"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "add_to_list"
                ]
              },
              "list_id": {
                "type": "string",
                "format": "uuid",
                "description": "List to add the subject's vendor_data to."
              }
            },
            "description": "Add the subject's vendor_data to a blocklist, allowlist or custom list."
          },
          {
            "type": "object",
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "open_case"
                ]
              },
              "blueprint": {
                "type": "string",
                "format": "uuid",
                "description": "Case blueprint UUID; defaults to the application's default blueprint."
              },
              "grouping": {
                "type": "string",
                "enum": [
                  "by_applicant",
                  "by_rule_and_applicant"
                ],
                "description": "Whether repeat matches join one case per applicant or one per rule+applicant."
              },
              "attach_matched_transaction": {
                "type": "boolean",
                "description": "Attach the matched transaction to the case."
              }
            },
            "description": "Open (or add to) an investigation case. Only the first open_case action on a rule is applied."
          }
        ],
        "description": "One rule action. A rule can carry several; all are applied together when it matches. Rules in TEST mode record what they would have done without applying any action."
      },
      "TransactionRuleCreateRequest": {
        "type": "object",
        "required": [
          "title",
          "category",
          "mode"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Rule name. Unique per application among non-deleted rules; duplicates return 400."
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "description": "Risk theme used for grouping and reporting, e.g. finance, aml_ctf, anomaly_detection, fatf, device_intelligence, crypto_monitoring, travel_rule, responsible_gaming, e_commerce."
          },
          "mode": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "DISABLED",
              "TEST"
            ],
            "description": "ACTIVE evaluates live. TEST evaluates and records rule runs but never touches score or status - the recommended starting mode. DISABLED is skipped."
          },
          "evaluation_mode": {
            "type": "string",
            "enum": [
              "ALL",
              "ANY"
            ],
            "default": "ALL",
            "description": "Whether every condition must match (ALL) or at least one (ANY). Ignored when conditions use group_index."
          },
          "scope": {
            "$ref": "#/components/schemas/TransactionRuleScope"
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleCondition"
            }
          },
          "aggregation": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAggregation"
            }
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAction"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Free-form metadata stored on the rule."
          }
        },
        "description": "Creates a CUSTOM rule. Rules in ACTIVE mode take effect immediately for new transactions - create in TEST mode and backtest first."
      },
      "TransactionRuleUpdateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Rule name. Unique per application among non-deleted rules; duplicates return 400."
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "description": "Risk theme used for grouping and reporting, e.g. finance, aml_ctf, anomaly_detection, fatf, device_intelligence, crypto_monitoring, travel_rule, responsible_gaming, e_commerce."
          },
          "mode": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "DISABLED",
              "TEST"
            ],
            "description": "ACTIVE evaluates live. TEST evaluates and records rule runs but never touches score or status - the recommended starting mode. DISABLED is skipped."
          },
          "evaluation_mode": {
            "type": "string",
            "enum": [
              "ALL",
              "ANY"
            ],
            "default": "ALL",
            "description": "Whether every condition must match (ALL) or at least one (ANY). Ignored when conditions use group_index."
          },
          "scope": {
            "$ref": "#/components/schemas/TransactionRuleScope"
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleCondition"
            }
          },
          "aggregation": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAggregation"
            }
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAction"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Free-form metadata stored on the rule."
          }
        },
        "description": "Partial update. Custom rules accept every field; library (PRESET) rules accept only mode - anything else returns 400."
      },
      "TransactionRuleDetail": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string",
            "description": "Rule name. Unique per application among non-deleted rules; duplicates return 400."
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "description": "Risk theme used for grouping and reporting, e.g. finance, aml_ctf, anomaly_detection, fatf, device_intelligence, crypto_monitoring, travel_rule, responsible_gaming, e_commerce."
          },
          "mode": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "DISABLED",
              "TEST"
            ],
            "description": "ACTIVE evaluates live. TEST evaluates and records rule runs but never touches score or status - the recommended starting mode. DISABLED is skipped."
          },
          "evaluation_mode": {
            "type": "string",
            "enum": [
              "ALL",
              "ANY"
            ],
            "default": "ALL",
            "description": "Whether every condition must match (ALL) or at least one (ANY). Ignored when conditions use group_index."
          },
          "scope": {
            "$ref": "#/components/schemas/TransactionRuleScope"
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleCondition"
            }
          },
          "aggregation": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAggregation"
            }
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAction"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Free-form metadata stored on the rule."
          },
          "severity": {
            "type": "string",
            "enum": [
              "UNKNOWN",
              "LOW",
              "MEDIUM",
              "HIGH",
              "CRITICAL"
            ],
            "nullable": true,
            "description": "Informational severity carried by library rules; not settable on custom rules."
          },
          "source": {
            "type": "string",
            "enum": [
              "PRESET",
              "CUSTOM"
            ],
            "description": "PRESET rules come from the library (install/uninstall, mode-only edits); CUSTOM rules are fully yours."
          },
          "library_key": {
            "type": "string",
            "nullable": true,
            "description": "Stable library identifier; null for custom rules."
          },
          "latest_triggered_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "run_count": {
            "type": "integer",
            "description": "How many transactions matched this rule."
          },
          "approved_count": {
            "type": "integer"
          },
          "reviewed_count": {
            "type": "integer"
          },
          "declined_count": {
            "type": "integer"
          },
          "awaiting_user_count": {
            "type": "integer"
          },
          "approved_pct": {
            "type": "number"
          },
          "reviewed_pct": {
            "type": "number"
          },
          "declined_pct": {
            "type": "number"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TransactionRuleBacktestRequest": {
        "type": "object",
        "properties": {
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleCondition"
            },
            "default": []
          },
          "aggregation": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAggregation"
            },
            "default": []
          },
          "evaluation_mode": {
            "type": "string",
            "enum": [
              "ALL",
              "ANY"
            ],
            "default": "ALL"
          },
          "scope": {
            "$ref": "#/components/schemas/TransactionRuleScope"
          },
          "period_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "default": 90
          }
        },
        "description": "Hypothetical rule configuration to evaluate against recent transactions. Read-only and free: nothing is created or modified. Send the same conditions, aggregation, evaluation_mode AND scope as the rule you intend to activate. Omitted conditions, aggregation and scope add no constraints of their own; dropping scope can include directions or transaction types the saved rule skips. Omitted evaluation_mode defaults to ALL (which can reduce matches for an ANY rule), and omitted period_days defaults to 90 days, not unlimited history."
      },
      "TransactionRuleBacktestResult": {
        "type": "object",
        "properties": {
          "evaluated": {
            "type": "integer",
            "description": "Transactions evaluated (most recent first, capped)."
          },
          "matched": {
            "type": "integer",
            "description": "Transactions the configuration would have matched."
          },
          "affected_entities": {
            "type": "integer",
            "description": "Distinct subjects (by vendor_data) among the matches."
          },
          "period_days": {
            "type": "integer"
          }
        }
      },
      "TransactionRuleLibraryEntry": {
        "type": "object",
        "properties": {
          "library_key": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string"
          },
          "evaluation_mode": {
            "type": "string",
            "enum": [
              "ALL",
              "ANY"
            ]
          },
          "scope": {
            "$ref": "#/components/schemas/TransactionRuleScope"
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleCondition"
            }
          },
          "aggregation": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAggregation"
            }
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransactionRuleAction"
            }
          },
          "metadata": {
            "type": "object"
          },
          "bundle": {
            "type": "string",
            "nullable": true,
            "description": "Functional family, e.g. finance, aml_ctf, crypto_monitoring, travel_rule, responsible_gaming."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "industries": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string"
          },
          "is_installed": {
            "type": "boolean",
            "description": "Whether this preset is currently installed on the application."
          }
        }
      },
      "TransactionRuleInstallRequest": {
        "type": "object",
        "properties": {
          "library_keys": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Specific presets to install or uninstall."
          },
          "bundle": {
            "type": "string",
            "description": "Install or uninstall every preset in this bundle instead."
          }
        },
        "description": "Provide library_keys OR bundle."
      },
      "TransactionRuleInstallResult": {
        "type": "object",
        "properties": {
          "installed_library_keys": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "POST (install) only: presets installed by this call."
          },
          "installed_count": {
            "type": "integer",
            "description": "POST (install) only."
          },
          "uninstalled_count": {
            "type": "integer",
            "description": "DELETE (uninstall) only: presets removed by this call."
          }
        }
      },
      "WalletScreeningResult": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "description": "Provider that performed the screening (e.g. `merklescience`, `crystal`)."
          },
          "screening_type": {
            "type": "string",
            "enum": [
              "WALLET_SCREENING"
            ],
            "description": "Always `WALLET_SCREENING` for this endpoint."
          },
          "risk_score": {
            "type": "integer",
            "description": "Normalised 0-100 risk score. Higher means greater exposure to risky entities. Merkle Science grades an address 0-5, which maps to 0, 15, 35, 55, 75 or 95."
          },
          "severity": {
            "type": "string",
            "enum": [
              "UNKNOWN",
              "LOW",
              "MEDIUM",
              "HIGH",
              "CRITICAL"
            ],
            "description": "Risk bucket derived from `risk_score`: `0-9` UNKNOWN, `10-39` LOW, `40-69` MEDIUM, `70-89` HIGH, `90-100` CRITICAL. `UNKNOWN` is the lowest band, not a separate no-data state: `risk_score` 0 (the common clean-address case) means no adverse assessment, while a non-zero score in the 1-9 range is a real but sub-LOW signal - read the `risk_score`, not just the band. Never treat `UNKNOWN` as an affirmative low-risk or clear rating; do not display it as a pass."
          },
          "status": {
            "type": "string",
            "enum": [
              "SCREENED",
              "PENDING",
              "ERROR"
            ],
            "description": "Screening outcome status."
          },
          "summary": {
            "type": "string",
            "description": "Human-readable summary of the screening result."
          },
          "wallet_address": {
            "type": "string",
            "description": "The screened address, echoed back."
          },
          "transaction_hash": {
            "type": "string",
            "nullable": true,
            "description": "Transaction screening field, shared with the result shape. Always `null` on a wallet screening result."
          },
          "blockchain": {
            "type": "string",
            "description": "The blockchain that was screened."
          },
          "block_timestamp": {
            "type": "string",
            "nullable": true,
            "description": "Transaction screening field, shared with the result shape. Always `null` on a wallet screening result."
          },
          "total_value_usd": {
            "type": "number",
            "nullable": true,
            "description": "Transaction screening field, shared with the result shape. Always `null` on a wallet screening result."
          },
          "fee_usd": {
            "type": "number",
            "nullable": true,
            "description": "Transaction screening field, shared with the result shape. Always `null` on a wallet screening result."
          },
          "sender_rows": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Transaction screening field, shared with the result shape. Always empty on a wallet screening result."
          },
          "receiver_rows": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Transaction screening field, shared with the result shape. Always empty on a wallet screening result."
          },
          "transaction_flows": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Transaction screening field, shared with the result shape. Always empty on a wallet screening result."
          },
          "transaction_flows_status": {
            "type": "string",
            "nullable": true,
            "description": "Transaction screening field, shared with the result shape. Always `null` on a wallet screening result."
          },
          "transaction_flows_error": {
            "type": "string",
            "nullable": true,
            "description": "Transaction screening field, shared with the result shape. Always `null` on a wallet screening result."
          },
          "source_of_funds": {
            "type": "array",
            "description": "Where the address received funds from, attributed by entity. Each entry is an exposure breakdown.",
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": "string",
                  "description": "Normalised risk category, e.g. `exchange_licensed`, `dex`, `defi`, `payment_processor`, `mixer`, `darknet_market`, `sanctioned`, `stolen_funds`, `high_risk_exchange`."
                },
                "percentage": {
                  "type": "number",
                  "description": "Share of the direction's total exposure, 0-100."
                },
                "amount_usd": {
                  "type": "number",
                  "nullable": true,
                  "description": "USD value attributed to this entity."
                },
                "entity_name": {
                  "type": "string",
                  "nullable": true,
                  "description": "Name of the attributed entity, for example an exchange, a mixer or a sanctioned group."
                },
                "entity_type": {
                  "type": "string",
                  "nullable": true,
                  "description": "Provider entity type (e.g. `Exchange`, `DeFi`, `Sanctions`, `Theft`)."
                },
                "entity_subtype": {
                  "type": "string",
                  "nullable": true,
                  "description": "More granular subtype (e.g. `Mandatory KYC and AML`, `OFAC`, `Yield Aggregator`)."
                },
                "hops": {
                  "type": "integer",
                  "nullable": true,
                  "description": "Number of hops to the entity (1 for a direct counterparty), when the provider reports one. Always `null` for Merkle Science, which reports only whether exposure is direct or indirect: use `exposure_type`."
                },
                "description": {
                  "type": "string",
                  "nullable": true,
                  "description": "`entity_type / entity_subtype`, as the provider labels the entity."
                },
                "is_direct": {
                  "type": "boolean",
                  "description": "True when `exposure_type` is `direct`."
                },
                "exposure_direction": {
                  "type": "string",
                  "enum": [
                    "incoming",
                    "outgoing",
                    "connected"
                  ],
                  "description": "Whether the funds came from (`incoming`) or went to (`outgoing`) this entity."
                },
                "exposure_type": {
                  "type": "string",
                  "enum": [
                    "direct",
                    "indirect"
                  ],
                  "description": "`direct` (1 hop) or `indirect` (multi-hop) exposure."
                },
                "provider_entity_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for the entity."
                },
                "provider_entity_type_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for `entity_type`."
                },
                "provider_entity_subtype_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for `entity_subtype`."
                },
                "country": {
                  "type": "string",
                  "nullable": true,
                  "description": "Primary ISO 3166-1 alpha-2 country of the entity. Empty or `null` when the provider does not know it."
                },
                "raw_amount": {
                  "type": "number",
                  "nullable": true,
                  "description": "Amount in the asset's own unit, when the provider reports it."
                },
                "raw_currency": {
                  "type": "string",
                  "nullable": true,
                  "description": "Unit of `raw_amount`, when the provider reports it."
                }
              }
            }
          },
          "destination_of_funds": {
            "type": "array",
            "description": "Where the address sent funds to, attributed by entity. Same item shape as `source_of_funds` with `exposure_direction` = `outgoing`.",
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": "string",
                  "description": "Normalised risk category, e.g. `exchange_licensed`, `dex`, `defi`, `payment_processor`, `mixer`, `darknet_market`, `sanctioned`, `stolen_funds`, `high_risk_exchange`."
                },
                "percentage": {
                  "type": "number",
                  "description": "Share of the direction's total exposure, 0-100."
                },
                "amount_usd": {
                  "type": "number",
                  "nullable": true,
                  "description": "USD value attributed to this entity."
                },
                "entity_name": {
                  "type": "string",
                  "nullable": true,
                  "description": "Name of the attributed entity, for example an exchange, a mixer or a sanctioned group."
                },
                "entity_type": {
                  "type": "string",
                  "nullable": true,
                  "description": "Provider entity type (e.g. `Exchange`, `DeFi`, `Sanctions`, `Theft`)."
                },
                "entity_subtype": {
                  "type": "string",
                  "nullable": true,
                  "description": "More granular subtype (e.g. `Mandatory KYC and AML`, `OFAC`, `Yield Aggregator`)."
                },
                "hops": {
                  "type": "integer",
                  "nullable": true,
                  "description": "Number of hops to the entity (1 for a direct counterparty), when the provider reports one. Always `null` for Merkle Science, which reports only whether exposure is direct or indirect: use `exposure_type`."
                },
                "description": {
                  "type": "string",
                  "nullable": true,
                  "description": "`entity_type / entity_subtype`, as the provider labels the entity."
                },
                "is_direct": {
                  "type": "boolean",
                  "description": "True when `exposure_type` is `direct`."
                },
                "exposure_direction": {
                  "type": "string",
                  "enum": [
                    "incoming",
                    "outgoing",
                    "connected"
                  ],
                  "description": "Whether the funds came from (`incoming`) or went to (`outgoing`) this entity."
                },
                "exposure_type": {
                  "type": "string",
                  "enum": [
                    "direct",
                    "indirect"
                  ],
                  "description": "`direct` (1 hop) or `indirect` (multi-hop) exposure."
                },
                "provider_entity_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for the entity."
                },
                "provider_entity_type_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for `entity_type`."
                },
                "provider_entity_subtype_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for `entity_subtype`."
                },
                "country": {
                  "type": "string",
                  "nullable": true,
                  "description": "Primary ISO 3166-1 alpha-2 country of the entity. Empty or `null` when the provider does not know it."
                },
                "raw_amount": {
                  "type": "number",
                  "nullable": true,
                  "description": "Amount in the asset's own unit, when the provider reports it."
                },
                "raw_currency": {
                  "type": "string",
                  "nullable": true,
                  "description": "Unit of `raw_amount`, when the provider reports it."
                }
              }
            }
          },
          "counterparty_connections": {
            "type": "array",
            "description": "Entities the provider attributes the screened address to. For Merkle Science these come from the address's own owner and user tags, so the same entity can appear twice, and they carry no fund flows: `received_usd`, `sent_usd`, `received_hops` and `sent_hops` are `null` and `percentage` is 0. Do not route on `risk_level` or `is_direct` here: use `sanctions_hit`, `dominant_risk_category` and `risk_factors[].is_high_risk` for the verdict, and `exposure_type` in `source_of_funds`/`destination_of_funds` for directness.",
            "items": {
              "type": "object",
              "properties": {
                "entity_name": {
                  "type": "string",
                  "nullable": true,
                  "description": "Attributed entity name."
                },
                "entity_type": {
                  "type": "string",
                  "nullable": true,
                  "description": "Provider entity type."
                },
                "entity_subtype": {
                  "type": "string",
                  "nullable": true,
                  "description": "Provider entity subtype."
                },
                "risk_level": {
                  "type": "string",
                  "description": "Lowercase and provider-dependent. For Merkle Science it is the address's own 0-5 risk grade (`no_risk`, `low`, `medium_low`, `medium`, `high`, `critical`), raised to `high` when the entity's category is high risk; it is not a separate grade of the entity."
                },
                "categories": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Normalised risk categories of the entity."
                },
                "received_usd": {
                  "type": "number",
                  "nullable": true,
                  "description": "USD received from the entity, when the provider reports it."
                },
                "sent_usd": {
                  "type": "number",
                  "nullable": true,
                  "description": "USD sent to the entity, when the provider reports it."
                },
                "received_hops": {
                  "type": "integer",
                  "nullable": true,
                  "description": "Hops to the entity on the receiving side, when the provider reports them."
                },
                "sent_hops": {
                  "type": "integer",
                  "nullable": true,
                  "description": "Hops to the entity on the sending side, when the provider reports them."
                },
                "percentage": {
                  "type": "number",
                  "description": "Share of the address's exposure, when the provider reports it; otherwise 0."
                },
                "is_direct": {
                  "type": "boolean",
                  "description": "Always `true` for Merkle Science, whose connections are attributions rather than counterparties."
                },
                "country": {
                  "type": "string",
                  "nullable": true,
                  "description": "Country of the entity, when known."
                },
                "provider_entity_id": {
                  "type": "string",
                  "nullable": true,
                  "description": "The provider's own identifier for the entity."
                }
              }
            }
          },
          "network_nodes": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Exposure graph nodes for transaction screening. Empty on a wallet screening result."
          },
          "network_edges": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Exposure graph edges for transaction screening. Empty on a wallet screening result."
          },
          "sanctions_hit": {
            "type": "boolean",
            "description": "True if the address has direct or indirect sanctions exposure."
          },
          "pep_counterparty": {
            "type": "boolean",
            "description": "Politically exposed person exposure. `null` when no PEP finding is available, which is every result today because no provider reports one; `false` only for an explicit negative screening result. Do not read `null` as a completed PEP check.",
            "nullable": true
          },
          "dominant_risk_category": {
            "type": "string",
            "nullable": true,
            "description": "Highest-weighted high-risk category, or `null` when none is dominant (e.g. `sanctioned`, `mixer`, `stolen_funds`)."
          },
          "risk_factors": {
            "type": "array",
            "description": "Ranked explanation of `risk_score`: what produced this verdict. Providers grade an address on their own model and return only a verdict (Merkle Science returns an integer 0-5), so the score alone is not actionable. Ordered high-risk first, then by the value that moved through each driver, capped at the five strongest; `source_of_funds` and `destination_of_funds` always carry the complete breakdown. A high `risk_score` with no `is_high_risk` entry means the provider reported no sanctions or attributed-entity match and graded the address purely on its own exposure model - `summary` states this explicitly.",
            "items": {
              "type": "object",
              "properties": {
                "source": {
                  "type": "string",
                  "enum": [
                    "attribution",
                    "exposure"
                  ],
                  "description": "`attribution` is what the provider says the address itself is (its own tag or cluster); `exposure` is where its funds actually moved."
                },
                "category": {
                  "type": "string",
                  "description": "Normalised risk category, same vocabulary as the exposure breakdown."
                },
                "label": {
                  "type": "string",
                  "description": "The provider's own wording for the driver (e.g. `Gambling / Crypto only`), which is what you would also see in the provider's console."
                },
                "entity_name": {
                  "type": "string",
                  "nullable": true,
                  "description": "Attributed entity behind the driver, for example a gambling site or an exchange."
                },
                "direction": {
                  "type": "string",
                  "enum": [
                    "incoming",
                    "outgoing",
                    "connected",
                    "unknown",
                    "attribution"
                  ],
                  "description": "Direction of the fund flow, `attribution` when the driver is the address's own tag, or `unknown` when the provider did not report a direction."
                },
                "exposure_type": {
                  "type": "string",
                  "enum": [
                    "direct",
                    "indirect",
                    "unknown",
                    "attribution"
                  ],
                  "description": "`direct` (1 hop) or `indirect` (multi-hop), `attribution` for the address's own tag, or `unknown` when the provider did not state how many hops away the counterparty is. Treat `unknown` as unclassified, not as `direct`."
                },
                "amount_usd": {
                  "type": "number",
                  "format": "float",
                  "nullable": true,
                  "description": "USD value attributed to this driver."
                },
                "percentage": {
                  "type": "number",
                  "format": "float",
                  "description": "Share of the address's TOTAL screened volume, both directions combined - unlike `percentage` inside `source_of_funds`/`destination_of_funds`, which is normalised per direction. Comparable and summable across the whole list."
                },
                "is_high_risk": {
                  "type": "boolean",
                  "description": "Whether the category is one Didit treats as high risk (`sanctioned`, `mixer`, `stolen_funds`, `ransomware`, `scam`, `darknet_market`, `terrorist_financing`, `child_exploitation`, `hacked_exchange`, `high_risk_exchange`, `seized_funds`)."
                },
                "description": {
                  "type": "string",
                  "description": "One-line rendering of the driver, e.g. `9.01% indirect outgoing exposure to Gambling / Crypto only (Example Gambling)`."
                }
              }
            }
          },
          "raw_response": {
            "type": "object",
            "additionalProperties": true,
            "description": "The provider's own payload. Its shape is provider-specific and can change without notice: read the normalised fields instead of parsing it."
          },
          "report_signature": {
            "type": "string",
            "description": "Opaque HMAC-SHA256 signature over this exact result, scoped to your application. Not meaningful on its own — repost the full response body, unmodified and including this field, to `POST /v3/wallet-screening/pdf/` to render it as a PDF. The PDF endpoint rejects the request with `400` if `report_signature` is missing or if any signed field (e.g. `risk_score`, `severity`, `sanctions_hit`) was edited before repost."
          }
        },
        "required": [
          "provider",
          "screening_type",
          "risk_score",
          "severity",
          "status",
          "summary",
          "wallet_address",
          "blockchain",
          "sanctions_hit",
          "dominant_risk_category",
          "source_of_funds",
          "destination_of_funds",
          "counterparty_connections",
          "report_signature"
        ]
      },
      "NetworkRiskDisplay": {
        "type": "object",
        "properties": {
          "score": {
            "type": "integer",
            "description": "Risk score, 0-100."
          },
          "band": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "description": "Band the score renders as. high >= 70, medium >= 40, otherwise low."
          },
          "bar": {
            "type": "number",
            "format": "float",
            "description": "Normalized 0-1 value for rendering a risk bar."
          }
        }
      },
      "NetworkNodeTag": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string",
            "nullable": true,
            "description": "Null for guard tags, whose color token the renderer owns."
          },
          "source": {
            "type": "string",
            "enum": [
              "subject_tag",
              "session_tag",
              "transaction_tag",
              "signal_guard"
            ],
            "description": "Where the tag came from: a tag on the user/business, a tag on a session in this network, a tag on a transaction a party belongs to, or a signal guard condition (e.g. hub, datacenter IP)."
          },
          "category": {
            "type": "string",
            "enum": [
              "customer",
              "quality"
            ],
            "nullable": true,
            "description": "customer for customer-defined tags, quality for signal-quality guard tags. Null when not applicable."
          }
        }
      },
      "NetworkListItem": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "network_id": {
            "type": "string",
            "description": "Human-readable per-organization sequential id, e.g. N-0001."
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "in_review",
              "resolved",
              "dismissed"
            ],
            "description": "Network lifecycle status. Distinct from the per-applicant outcome_status inside a network (approved/in_review/declined/not_completed)."
          },
          "risk": {
            "$ref": "#/components/schemas/NetworkRiskDisplay"
          },
          "pattern_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "exact_same_device",
                "similar_device",
                "same_ip_address",
                "same_address",
                "similar_selfie_backgrounds",
                "similar_poa_documents",
                "same_document_number",
                "same_phone_number",
                "same_email"
              ]
            },
            "description": "The clustering patterns detected in this network."
          },
          "signal_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ip_address",
                "device",
                "face",
                "document_number",
                "phone",
                "email",
                "address"
              ]
            },
            "description": "The distinct signal types present in this network."
          },
          "member_counts": {
            "type": "object",
            "description": "Counts of members by category (e.g. total, per outcome_status)."
          },
          "member_status": {
            "type": "object",
            "description": "Breakdown of members by outcome_status."
          },
          "signal_coverage": {
            "type": "object",
            "description": "Per signal_type coverage of this network's members."
          },
          "first_activity_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "NetworkDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/NetworkListItem"
          },
          {
            "type": "object",
            "properties": {
              "stats": {
                "type": "object",
                "description": "Aggregate stats for the network (e.g. member totals)."
              },
              "fraud_tags": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "description": "Fraud-pattern tags surfaced on the network."
              },
              "risk_signals": {
                "type": "object",
                "description": "Risk-signal summaries: residential_proxy_reuse, email_intelligence, phone_intelligence."
              },
              "reviewed_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "reviewed_by": {
                "type": "string",
                "nullable": true
              },
              "review_reason": {
                "type": "string",
                "nullable": true
              }
            }
          }
        ],
        "properties": {
          "notes_count": {
            "type": "integer",
            "minimum": 0,
            "readOnly": true,
            "description": "Number of private analyst notes in this investigation."
          }
        }
      },
      "NetworkGraphNode": {
        "type": "object",
        "description": "A subject node or a signal node, distinguished by kind. Subject nodes (kind: vendor_user | vendor_business | transaction_party) carry id, kind, subject, node_status (approved | in_review | declined | not_completed), and tags. Signal nodes (kind: signal) carry id, kind, uuid, signal_type, subject_count, coverage, is_hub, is_datacenter_ip, is_high_collision_device, node_status (signal_active | signal_guarded), tags, risk_evidence, first_seen_at, and last_seen_at.",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "vendor_user",
              "vendor_business",
              "transaction_party",
              "signal"
            ]
          }
        }
      },
      "NetworkGraphEdge": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "source": {
            "type": "string",
            "description": "Subject node id."
          },
          "target": {
            "type": "string",
            "description": "Signal node id."
          },
          "subject_kind": {
            "type": "string",
            "enum": [
              "vendor_user",
              "vendor_business",
              "transaction_party"
            ]
          },
          "signal_type": {
            "type": "string",
            "enum": [
              "ip_address",
              "device",
              "face",
              "document_number",
              "phone",
              "email",
              "address"
            ]
          },
          "confidence": {
            "type": "number",
            "format": "float",
            "description": "1.0 for an exact match."
          },
          "observation_count": {
            "type": "integer"
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "NetworkGraph": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/NetworkDetail"
          },
          "depth": {
            "type": "integer",
            "nullable": true,
            "description": "Effective depth applied, or null when unbounded (depth=all)."
          },
          "truncated": {
            "type": "boolean",
            "description": "True if the neighborhood was cut off by depth."
          },
          "nodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NetworkGraphNode"
            }
          },
          "edges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NetworkGraphEdge"
            }
          },
          "metrics": {
            "type": "object",
            "properties": {
              "node_count": {
                "type": "integer"
              },
              "edge_count": {
                "type": "integer"
              },
              "hub_signal_count": {
                "type": "integer"
              }
            }
          }
        }
      },
      "NetworkMember": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "object",
            "description": "The vendor_user, vendor_business, or transaction_party this member represents."
          },
          "outcome_status": {
            "type": "string",
            "description": "The subject's verification/decision outcome."
          },
          "node_status": {
            "type": "string",
            "enum": [
              "approved",
              "in_review",
              "declined",
              "not_completed",
              "signal_active",
              "signal_guarded"
            ],
            "description": "For a member row this is always one of the subject-outcome values: approved, in_review, declined, or not_completed."
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NetworkNodeTag"
            }
          },
          "risk": {
            "$ref": "#/components/schemas/NetworkRiskDisplay"
          },
          "signal_coverage": {
            "type": "object"
          },
          "shared_infrastructure": {
            "type": "object"
          },
          "joined_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "provenance": {
            "type": "object",
            "properties": {
              "session_ids": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "business_session_ids": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "transaction_ids": {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            }
          }
        }
      },
      "NetworkSignal": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "signal_type": {
            "type": "string",
            "enum": [
              "ip_address",
              "device",
              "face",
              "document_number",
              "phone",
              "email",
              "address"
            ]
          },
          "subject_count": {
            "type": "integer"
          },
          "coverage": {
            "type": "number",
            "format": "float"
          },
          "is_hub": {
            "type": "boolean",
            "description": "True when this signal links an unusually large number of subjects."
          },
          "is_datacenter_ip": {
            "type": "boolean"
          },
          "is_high_collision_device": {
            "type": "boolean"
          },
          "node_status": {
            "type": "string",
            "enum": [
              "signal_active",
              "signal_guarded"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NetworkNodeTag"
            }
          },
          "risk_evidence": {
            "type": "object"
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "NetworkTimelineEvent": {
        "type": "object",
        "properties": {
          "event_type": {
            "type": "string",
            "description": "e.g. network_detected, signal_observed, network_in_review, network_resolved, network_dismissed."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "label": {
            "type": "string"
          },
          "metadata": {
            "type": "object"
          }
        }
      },
      "NetworkMap": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/NetworkDetail"
          },
          "convergence_count": {
            "type": "integer",
            "description": "Number of distinct address/location points members converge on."
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "points": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "country": {
                  "type": "string",
                  "nullable": true
                },
                "country_code": {
                  "type": "string",
                  "nullable": true
                },
                "city": {
                  "type": "string",
                  "nullable": true
                },
                "latitude": {
                  "type": "number",
                  "format": "float",
                  "nullable": true
                },
                "longitude": {
                  "type": "number",
                  "format": "float",
                  "nullable": true
                },
                "observed_at": {
                  "type": "string",
                  "format": "date-time",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "EntityNetworkMembership": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/NetworkListItem"
          },
          "subject": {
            "type": "object"
          },
          "signal_types": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ip_address",
                "device",
                "face",
                "document_number",
                "phone",
                "email",
                "address"
              ]
            }
          },
          "signal_count": {
            "type": "integer"
          },
          "joined_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "RiskSignals": {
        "type": "object",
        "description": "Optional device and network context observed by your application. All fields are optional. Passing them feeds cross-session match detection in Networks.",
        "properties": {
          "ip": {
            "type": "string",
            "format": "ip",
            "description": "IPv4 or IPv6 address observed for the end user.",
            "example": "192.0.2.1"
          },
          "device_id": {
            "type": "string",
            "maxLength": 255,
            "description": "Stable device identifier collected by your application (Android `ANDROID_ID`, iOS `identifierForVendor`)."
          },
          "device_platform": {
            "type": "string",
            "enum": [
              "android",
              "ios",
              "ipados",
              "tvos",
              "web"
            ],
            "description": "Platform of the end user's device."
          },
          "device_model": {
            "type": "string",
            "maxLength": 255,
            "description": "Device model reported by your application."
          },
          "os_version": {
            "type": "string",
            "maxLength": 64,
            "description": "Operating-system version."
          },
          "app_version": {
            "type": "string",
            "maxLength": 64,
            "description": "Version of your application."
          },
          "user_agent": {
            "type": "string",
            "maxLength": 512,
            "description": "Browser or app user agent."
          }
        }
      },
      "PhoneRiskRequest": {
        "type": "object",
        "required": [
          "phone_number"
        ],
        "properties": {
          "phone_number": {
            "type": "string",
            "maxLength": 20,
            "description": "Phone number to score. It is validated and normalized to E.164.",
            "example": "+14155552671"
          },
          "country_code": {
            "type": "string",
            "maxLength": 3,
            "description": "Optional ISO 3166-1 alpha-2 or alpha-3 country hint for intelligence coverage.",
            "example": "US"
          },
          "signals": {
            "$ref": "#/components/schemas/RiskSignals"
          },
          "vendor_data": {
            "type": "string",
            "description": "Your stable reference for this request. Stored on the API session and echoed in the response."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Your non-sensitive JSON metadata. Stored on the API session and echoed in the response."
          },
          "enable_social": {
            "type": "boolean",
            "default": false,
            "description": "When true, also look up the social footprint of the number - the messaging, social, e-commerce and professional platforms it is registered on. Billed as one `phone_social` unit per request in addition to this endpoint's own price.",
            "example": true
          }
        }
      },
      "EmailRiskRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address to score.",
            "example": "alice@example.com"
          },
          "country_code": {
            "type": "string",
            "maxLength": 3,
            "description": "Optional ISO 3166-1 alpha-2 or alpha-3 country hint for intelligence coverage.",
            "example": "US"
          },
          "signals": {
            "$ref": "#/components/schemas/RiskSignals"
          },
          "vendor_data": {
            "type": "string",
            "description": "Your stable reference for this request. Stored on the API session and echoed in the response."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Your non-sensitive JSON metadata. Stored on the API session and echoed in the response."
          },
          "enable_social": {
            "type": "boolean",
            "default": false,
            "description": "When true, also look up the social footprint of the address - the email, social, professional, e-commerce and entertainment platforms it is registered on. Billed as one `email_social` unit per request in addition to this endpoint's own price.",
            "example": true
          }
        }
      },
      "IPRiskRequest": {
        "type": "object",
        "required": [
          "ip_address"
        ],
        "properties": {
          "ip_address": {
            "type": "string",
            "format": "ip",
            "description": "IPv4 or IPv6 address to score.",
            "example": "8.8.8.8"
          },
          "claimed_country": {
            "type": "string",
            "maxLength": 3,
            "description": "Optional ISO 3166-1 alpha-2 or alpha-3 country claimed by the user or session. Used to calculate `country_mismatch`.",
            "example": "ESP"
          },
          "user_agent": {
            "type": "string",
            "maxLength": 512,
            "description": "User agent observed by your backend. Stored as request context; it does not provide device fingerprinting."
          },
          "vendor_data": {
            "type": "string",
            "description": "Your stable reference for this request. Stored on the API session and echoed in the response."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Your non-sensitive JSON metadata. Stored on the API session and echoed in the response."
          }
        }
      },
      "RiskWarning": {
        "type": "object",
        "required": [
          "feature",
          "risk",
          "log_type",
          "short_description",
          "long_description"
        ],
        "properties": {
          "feature": {
            "type": "string",
            "description": "Feature that produced the warning."
          },
          "risk": {
            "type": "string",
            "description": "Machine-readable risk code. New values can be added over time."
          },
          "additional_data": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Risk-specific context, or `null`."
          },
          "log_type": {
            "type": "string",
            "enum": [
              "error",
              "warning",
              "information"
            ],
            "description": "Severity used by the decision rules."
          },
          "short_description": {
            "type": "string",
            "description": "Human-readable one-line summary."
          },
          "long_description": {
            "type": "string",
            "description": "Human-readable explanation."
          }
        }
      },
      "RiskLifecycleEvent": {
        "type": "object",
        "required": [
          "type",
          "timestamp",
          "details",
          "fee"
        ],
        "properties": {
          "type": {
            "type": "string",
            "description": "Machine-readable event type. New values can be added over time."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the event happened."
          },
          "details": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Event-specific payload, or `null`."
          },
          "fee": {
            "type": "number",
            "description": "USD amount billed for this event."
          }
        }
      },
      "PhoneMatchItem": {
        "type": "object",
        "description": "Another session of your application that used the same phone number with a different `vendor_data`.",
        "properties": {
          "session_id": {
            "type": "string",
            "format": "uuid",
            "description": "Session id of the other verification that used this phone number."
          },
          "session_number": {
            "type": "integer",
            "description": "Human-friendly sequential number of that session."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "`vendor_data` of that session."
          },
          "verification_date": {
            "type": "string",
            "description": "When that session was created (`YYYY-MM-DDTHH:MM:SSZ`)."
          },
          "phone_number": {
            "type": "string",
            "description": "The matched phone number."
          },
          "status": {
            "type": "string",
            "description": "Status of that session (e.g., `Approved`, `Declined`, `In Progress`)."
          },
          "is_blocklisted": {
            "type": "boolean",
            "description": "Whether the phone number is on your application's blocklist."
          },
          "api_service": {
            "type": "string",
            "nullable": true,
            "description": "For API-type sessions, the standalone API that created it; `null` for regular verification sessions."
          },
          "source": {
            "type": "string",
            "description": "Where the match was found. Usually `session`; a blocklist hit via an organization list entry uses `list_entry`."
          }
        }
      },
      "EmailMatchItem": {
        "type": "object",
        "description": "Another session of your application that used the same email address with a different `vendor_data`.",
        "properties": {
          "session_id": {
            "type": "string",
            "format": "uuid",
            "description": "Session id of the other verification that used this email address."
          },
          "session_number": {
            "type": "integer",
            "description": "Human-friendly sequential number of that session."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "`vendor_data` of that session."
          },
          "verification_date": {
            "type": "string",
            "description": "When that session was created (`YYYY-MM-DDTHH:MM:SSZ`)."
          },
          "email": {
            "type": "string",
            "description": "The matched email address."
          },
          "status": {
            "type": "string",
            "description": "Status of that session (e.g., `Approved`, `Declined`, `In Progress`)."
          },
          "is_blocklisted": {
            "type": "boolean",
            "description": "Whether the email address is on your application's blocklist."
          },
          "api_service": {
            "type": "string",
            "nullable": true,
            "description": "For API-type sessions, the standalone API that created it; `null` for regular verification sessions."
          },
          "source": {
            "type": "string",
            "description": "Where the match was found. Usually `session`; a blocklist hit via an organization list entry uses `list_entry`."
          }
        }
      },
      "PhoneIntelligence": {
        "type": "object",
        "description": "Normalized phone-intelligence block. Present only when the intelligence add-on ran for this lookup; when present it is also exposed under the `enrichment` alias with identical values.",
        "properties": {
          "score": {
            "type": "number",
            "nullable": true,
            "description": "Normalized 0-100 risk score. Higher is riskier."
          },
          "phone_type_risk": {
            "type": "string",
            "nullable": true,
            "description": "`Low`, `Medium` or `High`, derived from the score."
          },
          "phone_trust_index": {
            "type": "number",
            "nullable": true,
            "description": "Inverse of the score, for dashboards that prefer higher is better."
          },
          "network_stability_index": {
            "type": "number",
            "nullable": true,
            "description": "Stability of the line's network."
          },
          "is_disposable": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the number looks disposable or virtual."
          },
          "is_ported": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the number has moved carrier."
          },
          "is_recently_ported": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the port happened recently."
          },
          "carrier_type": {
            "type": "string",
            "nullable": true,
            "description": "Line classification reported by the lookup (e.g., `mobile`)."
          },
          "reason_codes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Machine-readable codes explaining the score. Values can grow over time, so do not reject unknown codes."
          }
        }
      },
      "EmailIntelligence": {
        "type": "object",
        "description": "Normalized email-intelligence block. Present only when the intelligence add-on ran for this email; when present it is also exposed as the `enrichment` alias with identical values.",
        "properties": {
          "score": {
            "type": "number",
            "nullable": true,
            "description": "Normalized 0-100 risk score. Higher is riskier."
          },
          "deliverable": {
            "type": "string",
            "nullable": true,
            "description": "Deliverability band (e.g., `high`)."
          },
          "breach_risk_level": {
            "type": "string",
            "nullable": true,
            "description": "`Low`, `Medium` or `High`."
          },
          "breach_risk_index": {
            "type": "number",
            "nullable": true,
            "description": "Numeric breach-risk index."
          },
          "is_recent_breach": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the address appears in a recent breach."
          },
          "is_frequent_breached": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the address appears in many breaches."
          },
          "is_disposable": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the domain is a throwaway provider."
          },
          "is_free_domain": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the domain is a free mail provider."
          },
          "is_breached": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the address appears in known breaches."
          },
          "no_of_breaches": {
            "type": "number",
            "nullable": true,
            "description": "Number of known breaches containing the address."
          },
          "reason_codes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Machine-readable codes explaining the score. Values can grow over time, so do not reject unknown codes."
          }
        }
      },
      "IPRiskResult": {
        "type": "object",
        "description": "IP risk result. Individual enrichment fields can be `null` when the lookup returned no usable data.",
        "required": [
          "status",
          "threat"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "Approved",
              "In Review"
            ],
            "description": "`In Review` when the resolved country conflicts with `claimed_country`, or when the address is associated with VPN, Tor, or data-center infrastructure. Otherwise `Approved`."
          },
          "ip_address": {
            "type": "string",
            "nullable": true,
            "description": "The scored address. `null` when no enrichment source returned usable data."
          },
          "ip_country": {
            "type": "string",
            "nullable": true,
            "description": "Resolved country name."
          },
          "ip_country_code": {
            "type": "string",
            "nullable": true,
            "description": "Resolved country code. Compare countries through `country_mismatch` instead of comparing raw country strings yourself."
          },
          "ip_state": {
            "type": "string",
            "nullable": true,
            "description": "Resolved state or region."
          },
          "ip_city": {
            "type": "string",
            "nullable": true,
            "description": "Resolved city."
          },
          "latitude": {
            "type": "number",
            "nullable": true,
            "description": "Approximate network geolocation, not a precise device location."
          },
          "longitude": {
            "type": "number",
            "nullable": true,
            "description": "Approximate network geolocation, not a precise device location."
          },
          "isp": {
            "type": "string",
            "nullable": true,
            "description": "Internet service provider serving the address."
          },
          "organization": {
            "type": "string",
            "nullable": true,
            "description": "Organization owning the address block."
          },
          "is_vpn_or_tor": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the address is associated with VPN or Tor infrastructure."
          },
          "is_data_center": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the address belongs to a hosting or data-center network."
          },
          "time_zone": {
            "type": "string",
            "nullable": true,
            "description": "Time zone of the resolved location."
          },
          "time_zone_offset": {
            "type": "string",
            "nullable": true,
            "description": "UTC offset of the resolved location."
          },
          "asn_number": {
            "type": "number",
            "nullable": true,
            "description": "Autonomous system number."
          },
          "asn_organization": {
            "type": "string",
            "nullable": true,
            "description": "Organization operating the autonomous system."
          },
          "connection_type": {
            "type": "string",
            "nullable": true,
            "description": "Connection classification (e.g., `cellular`, `hosting`)."
          },
          "carrier": {
            "type": "string",
            "nullable": true,
            "description": "Mobile carrier when the address is on a mobile network."
          },
          "proxy_type": {
            "type": "string",
            "nullable": true,
            "description": "Proxy classification when the address is behind a proxy."
          },
          "claimed_country": {
            "type": "string",
            "nullable": true,
            "description": "Echo of the `claimed_country` you sent."
          },
          "country_mismatch": {
            "type": "boolean",
            "nullable": true,
            "description": "`true` when the resolved country differs from `claimed_country`. `null` when no enrichment data or no claimed country is available."
          },
          "threat": {
            "type": "object",
            "additionalProperties": true,
            "description": "Free-form network-threat evidence from the enrichment source (e.g., `is_proxy`, `is_tor`). Empty object when no enrichment data is available. Treat as diagnostic detail, not a stable contract."
          }
        }
      },
      "PhoneRiskResponse": {
        "type": "object",
        "required": [
          "request_id",
          "status",
          "created_at"
        ],
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Id of the API session created for this request. Store it with `vendor_data` if you need to correlate the result with later webhooks or console activity."
          },
          "status": {
            "type": "string",
            "enum": [
              "Approved",
              "In Review",
              "Declined"
            ],
            "description": "Final decision for this API session. Normally `Approved`; the risk evaluation can produce `In Review` or `Declined`."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Echo of the `vendor_data` you sent, `null` when you did not send one."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Echo of the `metadata` you sent, `null` when you did not send one."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of this response."
          },
          "phone": {
            "type": "object",
            "description": "Normalized phone report, the same block used by Phone Verification responses.",
            "required": [
              "status"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "Approved",
                  "In Review",
                  "Declined"
                ],
                "description": "Decision for this phone number. Mirrors the top-level `status`."
              },
              "phone_number_prefix": {
                "type": "string",
                "description": "Country calling code with leading `+` (e.g., `+1`).",
                "example": "+1"
              },
              "phone_number": {
                "type": "string",
                "description": "National number without the country calling code.",
                "example": "4155552671"
              },
              "full_number": {
                "type": "string",
                "description": "Complete number in E.164 format.",
                "example": "+14155552671"
              },
              "country_code": {
                "type": "string",
                "nullable": true,
                "description": "ISO 3166-1 alpha-2 country of the number.",
                "example": "US"
              },
              "country_name": {
                "type": "string",
                "description": "Full country name derived from `country_code`.",
                "example": "United States"
              },
              "carrier": {
                "type": "object",
                "nullable": true,
                "description": "Current network serving the number. `null` when the lookup could not resolve a carrier.",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Carrier name. Empty string when the lookup could not identify it."
                  },
                  "type": {
                    "type": "string",
                    "description": "Line type reported by the lookup: `mobile`, `fixed_line`, `voip`, `isp`, `vpn`, `toll_free`, `premium_rate`, or similar."
                  }
                }
              },
              "is_disposable": {
                "type": "boolean",
                "description": "`true` when the number belongs to a temporary or burner number service."
              },
              "is_virtual": {
                "type": "boolean",
                "description": "`true` when the line type is virtual (`voip`, `isp`, or `vpn`)."
              },
              "verification_method": {
                "type": "string",
                "nullable": true,
                "description": "OTP channel of the underlying verification. `null` for risk lookups, which never send a code."
              },
              "verification_attempts": {
                "type": "integer",
                "description": "OTP sends for this number. `0` for risk lookups."
              },
              "verified_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true,
                "description": "When the number was last verified by an OTP. `null` for risk lookups."
              },
              "warnings": {
                "type": "array",
                "description": "Risk warnings recorded for this request. Empty array when there are none.",
                "items": {
                  "$ref": "#/components/schemas/RiskWarning"
                }
              },
              "lifecycle": {
                "type": "array",
                "description": "Chronological audit trail of the request. Empty array for risk lookups without send events.",
                "items": {
                  "$ref": "#/components/schemas/RiskLifecycleEvent"
                }
              },
              "matches": {
                "type": "array",
                "description": "Other sessions of your application where the same phone number was used by a different user (different `vendor_data`). Up to 5 entries. Empty array when there are no matches.",
                "items": {
                  "$ref": "#/components/schemas/PhoneMatchItem"
                }
              },
              "phone_intelligence": {
                "$ref": "#/components/schemas/PhoneIntelligence"
              },
              "enrichment": {
                "$ref": "#/components/schemas/PhoneIntelligence"
              },
              "phone_social": {
                "$ref": "#/components/schemas/PhoneSocialFootprint"
              }
            }
          }
        }
      },
      "EmailRiskResponse": {
        "type": "object",
        "required": [
          "request_id",
          "status",
          "created_at"
        ],
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Id of the API session created for this request. Store it with `vendor_data` if you need to correlate the result with later webhooks or console activity."
          },
          "status": {
            "type": "string",
            "enum": [
              "Approved",
              "In Review",
              "Declined"
            ],
            "description": "Final decision for this API session. Normally `Approved`; the risk evaluation can produce `In Review` or `Declined`."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Echo of the `vendor_data` you sent, `null` when you did not send one."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Echo of the `metadata` you sent, `null` when you did not send one."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of this response."
          },
          "email": {
            "type": "object",
            "description": "Normalized email report, the same block used by Email Verification responses.",
            "required": [
              "status",
              "email",
              "is_breached",
              "breaches",
              "is_disposable",
              "is_undeliverable"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "Approved",
                  "In Review",
                  "Declined"
                ],
                "description": "Decision for this email address. Mirrors the top-level `status`."
              },
              "email": {
                "type": "string",
                "description": "The scored address.",
                "example": "alice@example.com"
              },
              "is_breached": {
                "type": "boolean",
                "description": "Whether the address appears in a known credential breach."
              },
              "breaches": {
                "type": "array",
                "description": "Up to 5 most recent known breaches containing this address. Empty array when `is_breached` is `false`.",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Breach identifier."
                    },
                    "domain": {
                      "type": "string",
                      "description": "Domain of the breached service."
                    },
                    "breach_date": {
                      "type": "string",
                      "format": "date",
                      "description": "Date the breach occurred."
                    },
                    "breach_emails_count": {
                      "type": "integer",
                      "description": "Total number of accounts exposed in the breach."
                    },
                    "description": {
                      "type": "string",
                      "description": "Human-readable description of the breach (may contain HTML markup)."
                    },
                    "logo_path": {
                      "type": "string",
                      "description": "URL of the breached service's logo."
                    },
                    "data_classes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Categories of data exposed, in snake_case (e.g., `email_addresses`, `passwords`)."
                    },
                    "is_verified": {
                      "type": "boolean",
                      "description": "Whether the breach has been verified as legitimate."
                    }
                  }
                }
              },
              "is_disposable": {
                "type": "boolean",
                "description": "Whether the domain belongs to a throwaway provider."
              },
              "is_undeliverable": {
                "type": "boolean",
                "description": "Whether the address was found undeliverable."
              },
              "verification_attempts": {
                "type": "integer",
                "description": "OTP sends for this address. `0` for risk lookups."
              },
              "verified_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true,
                "description": "When the address was last verified by an OTP. `null` for risk lookups."
              },
              "warnings": {
                "type": "array",
                "description": "Risk warnings recorded for this request. Empty array when there are none.",
                "items": {
                  "$ref": "#/components/schemas/RiskWarning"
                }
              },
              "lifecycle": {
                "type": "array",
                "description": "Chronological audit trail of the request. Empty array for risk lookups without sends.",
                "items": {
                  "$ref": "#/components/schemas/RiskLifecycleEvent"
                }
              },
              "matches": {
                "type": "array",
                "description": "Other sessions of your application where the same email address was used by a different user (different `vendor_data`). Up to 5 entries. Empty array when there are no matches.",
                "items": {
                  "$ref": "#/components/schemas/EmailMatchItem"
                }
              },
              "email_intelligence": {
                "$ref": "#/components/schemas/EmailIntelligence"
              },
              "enrichment": {
                "$ref": "#/components/schemas/EmailIntelligence"
              },
              "email_social": {
                "$ref": "#/components/schemas/EmailSocialFootprint"
              }
            }
          }
        }
      },
      "IPRiskResponse": {
        "type": "object",
        "required": [
          "request_id",
          "status",
          "created_at"
        ],
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Id of the API session created for this request. Store it with `vendor_data` if you need to correlate the result with later webhooks or console activity."
          },
          "status": {
            "type": "string",
            "enum": [
              "Approved",
              "In Review"
            ],
            "description": "Decision for this API session: `In Review` on network or country-mismatch risk, otherwise `Approved`."
          },
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Echo of the `vendor_data` you sent, `null` when you did not send one."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Echo of the `metadata` you sent, `null` when you did not send one."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of this response."
          },
          "ip": {
            "type": "object",
            "description": "IP risk result. Individual enrichment fields can be `null` when the lookup returned no usable data.",
            "required": [
              "status",
              "threat"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "Approved",
                  "In Review"
                ],
                "description": "`In Review` when the resolved country conflicts with `claimed_country`, or when the address is associated with VPN, Tor, or data-center infrastructure. Otherwise `Approved`."
              },
              "ip_address": {
                "type": "string",
                "nullable": true,
                "description": "The scored address. `null` when no enrichment source returned usable data."
              },
              "ip_country": {
                "type": "string",
                "nullable": true,
                "description": "Resolved country name."
              },
              "ip_country_code": {
                "type": "string",
                "nullable": true,
                "description": "Resolved country code. Compare countries through `country_mismatch` instead of comparing raw country strings yourself."
              },
              "ip_state": {
                "type": "string",
                "nullable": true,
                "description": "Resolved state or region."
              },
              "ip_city": {
                "type": "string",
                "nullable": true,
                "description": "Resolved city."
              },
              "latitude": {
                "type": "number",
                "nullable": true,
                "description": "Approximate network geolocation, not a precise device location."
              },
              "longitude": {
                "type": "number",
                "nullable": true,
                "description": "Approximate network geolocation, not a precise device location."
              },
              "isp": {
                "type": "string",
                "nullable": true,
                "description": "Internet service provider serving the address."
              },
              "organization": {
                "type": "string",
                "nullable": true,
                "description": "Organization owning the address block."
              },
              "is_vpn_or_tor": {
                "type": "boolean",
                "nullable": true,
                "description": "`true` when the address is associated with VPN or Tor infrastructure."
              },
              "is_data_center": {
                "type": "boolean",
                "nullable": true,
                "description": "`true` when the address belongs to a hosting or data-center network."
              },
              "time_zone": {
                "type": "string",
                "nullable": true,
                "description": "Time zone of the resolved location."
              },
              "time_zone_offset": {
                "type": "string",
                "nullable": true,
                "description": "UTC offset of the resolved location."
              },
              "asn_number": {
                "type": "number",
                "nullable": true,
                "description": "Autonomous system number."
              },
              "asn_organization": {
                "type": "string",
                "nullable": true,
                "description": "Organization operating the autonomous system."
              },
              "connection_type": {
                "type": "string",
                "nullable": true,
                "description": "Connection classification (e.g., `cellular`, `hosting`)."
              },
              "carrier": {
                "type": "string",
                "nullable": true,
                "description": "Mobile carrier when the address is on a mobile network."
              },
              "proxy_type": {
                "type": "string",
                "nullable": true,
                "description": "Proxy classification when the address is behind a proxy."
              },
              "claimed_country": {
                "type": "string",
                "nullable": true,
                "description": "Echo of the `claimed_country` you sent."
              },
              "country_mismatch": {
                "type": "boolean",
                "nullable": true,
                "description": "`true` when the resolved country differs from `claimed_country`. `null` when no enrichment data or no claimed country is available."
              },
              "threat": {
                "type": "object",
                "additionalProperties": true,
                "description": "Free-form network-threat evidence from the enrichment source (e.g., `is_proxy`, `is_tor`). Empty object when no enrichment data is available. Treat as diagnostic detail, not a stable contract."
              }
            }
          }
        }
      },
      "SocialFootprintPlatform": {
        "type": "object",
        "properties": {
          "platform": {
            "type": "string",
            "description": "Platform identifier.",
            "example": "whatsapp"
          },
          "category": {
            "type": "string",
            "description": "Platform category, e.g. MESSAGING, SOCIAL_MEDIA, ECOMMERCE, PROFESSIONAL, EMAIL_PROVIDER.",
            "example": "MESSAGING"
          },
          "scope": {
            "type": "string",
            "enum": [
              "global",
              "local"
            ],
            "description": "`global` for worldwide platforms, `local` for region-specific ones.",
            "example": "global"
          }
        }
      },
      "SocialFootprintCategorySummary": {
        "type": "object",
        "properties": {
          "registered": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms in this category where registration is confirmed.",
            "example": 2
          },
          "ratio": {
            "type": "number",
            "format": "float",
            "nullable": true,
            "description": "Share of the category's checked platforms with a registration, 0.0-1.0.",
            "example": 0.6667
          }
        }
      },
      "SocialFootprintProfile": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Profile name, when the platform exposes one."
          },
          "photo": {
            "type": "string",
            "nullable": true,
            "description": "Profile photo URL, when the platform exposes one."
          },
          "about": {
            "type": "string",
            "nullable": true,
            "description": "Profile about/bio text, when the platform exposes one."
          },
          "privacy_status": {
            "type": "string",
            "nullable": true,
            "enum": [
              "PUBLIC",
              "PRIVATE",
              null
            ],
            "description": "Profile visibility, when the platform exposes it."
          },
          "business_account": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the profile is a business account, when the platform exposes it."
          }
        }
      },
      "PhoneSocialFootprint": {
        "type": "object",
        "nullable": true,
        "description": "Social footprint of the phone number: the online platforms it is registered on. Present only when `enable_social` was set and the check completed. Every count may be null when no data was returned for it. `profiles_registered: 0` means the platforms were checked and the phone number was found on none of them - a valid, billable answer and a common synthetic-identity signal.",
        "properties": {
          "profiles_registered": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms where the phone number is confirmed registered.",
            "example": 5
          },
          "profiles_checked": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms evaluated for registration.",
            "example": 14
          },
          "names_found": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms that returned an associated name.",
            "example": 0
          },
          "photos_found": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms that returned a profile photo.",
            "example": 0
          },
          "communication_breadth": {
            "type": "integer",
            "nullable": true,
            "description": "Communication platforms with detected presence.",
            "example": 2
          },
          "digital_footprint_diversity": {
            "type": "integer",
            "nullable": true,
            "description": "Distinct platform categories with detected presence.",
            "example": 5
          },
          "digital_sophistication_index": {
            "type": "integer",
            "nullable": true,
            "description": "Composite digital-maturity indicator, 0-10.",
            "example": 5
          },
          "engagement_depth_index": {
            "type": "integer",
            "nullable": true,
            "description": "Profile-richness indicator, 0-10.",
            "example": 3
          },
          "subscription_affordability_index": {
            "type": "integer",
            "nullable": true,
            "description": "Free vs paid platform mix, 0-10.",
            "example": 2
          },
          "free_platforms": {
            "type": "integer",
            "nullable": true,
            "description": "Registrations on free platforms.",
            "example": 4
          },
          "full_paid_platforms": {
            "type": "integer",
            "nullable": true,
            "description": "Registrations on fully paid platforms.",
            "example": 0
          },
          "partial_paid_platforms": {
            "type": "integer",
            "nullable": true,
            "description": "Registrations on freemium platforms.",
            "example": 1
          },
          "whatsapp_profile_completeness": {
            "type": "string",
            "nullable": true,
            "enum": [
              "Basic",
              "Partial",
              "Complete",
              "Not Present",
              null
            ],
            "description": "Completeness of the WhatsApp profile. Phone only; null for email.",
            "example": "Partial"
          },
          "registered_platforms": {
            "type": "array",
            "description": "Platforms where registration is confirmed.",
            "items": {
              "$ref": "#/components/schemas/SocialFootprintPlatform"
            }
          },
          "not_registered_platforms": {
            "type": "array",
            "description": "Platforms checked with a negative result.",
            "items": {
              "$ref": "#/components/schemas/SocialFootprintPlatform"
            }
          },
          "categories": {
            "type": "object",
            "description": "Registered count and ratio per platform category.",
            "additionalProperties": {
              "$ref": "#/components/schemas/SocialFootprintCategorySummary"
            }
          },
          "profiles": {
            "type": "object",
            "description": "Per-platform profile details, keyed by platform, when the platform exposes them.",
            "additionalProperties": {
              "$ref": "#/components/schemas/SocialFootprintProfile"
            }
          }
        }
      },
      "EmailSocialFootprint": {
        "type": "object",
        "nullable": true,
        "description": "Social footprint of the email address: the online platforms it is registered on. Present only when `enable_social` was set and the check completed. Every count may be null when no data was returned for it. `profiles_registered: 0` means the platforms were checked and the email address was found on none of them - a valid, billable answer and a common synthetic-identity signal.",
        "properties": {
          "profiles_registered": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms where the email address is confirmed registered.",
            "example": 5
          },
          "profiles_checked": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms evaluated for registration.",
            "example": 14
          },
          "names_found": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms that returned an associated name.",
            "example": 0
          },
          "photos_found": {
            "type": "integer",
            "nullable": true,
            "description": "Platforms that returned a profile photo.",
            "example": 0
          },
          "communication_breadth": {
            "type": "integer",
            "nullable": true,
            "description": "Communication platforms with detected presence.",
            "example": 2
          },
          "digital_footprint_diversity": {
            "type": "integer",
            "nullable": true,
            "description": "Distinct platform categories with detected presence.",
            "example": 5
          },
          "digital_sophistication_index": {
            "type": "integer",
            "nullable": true,
            "description": "Composite digital-maturity indicator, 0-10.",
            "example": 5
          },
          "engagement_depth_index": {
            "type": "integer",
            "nullable": true,
            "description": "Profile-richness indicator, 0-10.",
            "example": 3
          },
          "subscription_affordability_index": {
            "type": "integer",
            "nullable": true,
            "description": "Free vs paid platform mix, 0-10.",
            "example": 2
          },
          "free_platforms": {
            "type": "integer",
            "nullable": true,
            "description": "Registrations on free platforms.",
            "example": 4
          },
          "full_paid_platforms": {
            "type": "integer",
            "nullable": true,
            "description": "Registrations on fully paid platforms.",
            "example": 0
          },
          "partial_paid_platforms": {
            "type": "integer",
            "nullable": true,
            "description": "Registrations on freemium platforms.",
            "example": 1
          },
          "whatsapp_profile_completeness": {
            "type": "string",
            "nullable": true,
            "enum": [
              "Basic",
              "Partial",
              "Complete",
              "Not Present",
              null
            ],
            "description": "Completeness of the WhatsApp profile. Phone only; null for email.",
            "example": "Partial"
          },
          "registered_platforms": {
            "type": "array",
            "description": "Platforms where registration is confirmed.",
            "items": {
              "$ref": "#/components/schemas/SocialFootprintPlatform"
            }
          },
          "not_registered_platforms": {
            "type": "array",
            "description": "Platforms checked with a negative result.",
            "items": {
              "$ref": "#/components/schemas/SocialFootprintPlatform"
            }
          },
          "categories": {
            "type": "object",
            "description": "Registered count and ratio per platform category.",
            "additionalProperties": {
              "$ref": "#/components/schemas/SocialFootprintCategorySummary"
            }
          },
          "profiles": {
            "type": "object",
            "description": "Per-platform profile details, keyed by platform, when the platform exposes them.",
            "additionalProperties": {
              "$ref": "#/components/schemas/SocialFootprintProfile"
            }
          }
        }
      },
      "KYBRegistryAddress": {
        "type": "object",
        "description": "An address the registry states, in the same shape for every country and registry source. Every key is always present; a part the registry does not publish is null.",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true,
            "description": "Address type in lower case: `registered` for the registered office; other types as the registry names them (for example `postal`, `office`). `null` when the registry does not say what the address is."
          },
          "address": {
            "type": "string",
            "description": "The full address as one line. Always present on every address."
          },
          "street": {
            "type": "string",
            "nullable": true,
            "description": "Street and number."
          },
          "city": {
            "type": "string",
            "nullable": true,
            "description": "City or locality."
          },
          "postal_code": {
            "type": "string",
            "nullable": true,
            "description": "Postal code."
          },
          "region": {
            "type": "string",
            "nullable": true,
            "description": "Region, state or province."
          },
          "country_code": {
            "type": "string",
            "nullable": true,
            "description": "ISO 3166-1 alpha-2 country code."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "The registry's own label for the address, when it gives one."
          }
        },
        "required": [
          "type",
          "address",
          "street",
          "city",
          "postal_code",
          "region",
          "country_code",
          "description"
        ]
      },
      "KYBRegistryIndustry": {
        "type": "object",
        "description": "An activity the registry classifies the company under, in the same shape for every country and registry source.",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true,
            "description": "Activity code as the registry prints it (for example `73110`)."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Activity label, when the registry publishes one."
          },
          "scheme": {
            "type": "string",
            "nullable": true,
            "description": "Classification system, one name per system whichever source reported it: `UK SIC 2007`, `US SIC`, `NACE Rev. 2`, `NACE Rev. 2.1`, `NAF Rev. 2`, `CNAE`, `SBI`, `NOGA 2008`, `CAE Rev. 4`, `Canada SIC 1977`; other national systems keep the registry's own name. Null when the registry does not name the system."
          },
          "is_primary": {
            "type": "boolean",
            "description": "True for the company's main activity. Exactly one entry is primary when the list is not empty."
          }
        },
        "required": [
          "code",
          "description",
          "scheme",
          "is_primary"
        ]
      },
      "KYBRegistryShareholding": {
        "type": "object",
        "nullable": true,
        "description": "What an owner holds, in the same shape for every country and registry source. Null when the registry states no holding. A band (for example a UK PSC's 25-50%) is not a stake: `percentage` is null and the band stays in `ownership_min_shares` / `ownership_max_shares`.",
        "properties": {
          "share_class": {
            "type": "string",
            "nullable": true,
            "description": "Share class or type as the registry names it."
          },
          "number_of_shares": {
            "type": "number",
            "nullable": true,
            "description": "Number of shares held."
          },
          "currency": {
            "type": "string",
            "nullable": true,
            "description": "ISO 4217 currency of the values below."
          },
          "nominal_value": {
            "type": "number",
            "nullable": true,
            "description": "Nominal value per share."
          },
          "total_value": {
            "type": "number",
            "nullable": true,
            "description": "Total value of the holding."
          },
          "percentage": {
            "type": "number",
            "nullable": true,
            "description": "Exact stake in percent, to four decimal places."
          }
        },
        "required": [
          "share_class",
          "number_of_shares",
          "currency",
          "nominal_value",
          "total_value",
          "percentage"
        ]
      },
      "KYBRegistryOwnership": {
        "type": "object",
        "description": "The outcome of the ownership (Shareholders / UBO) tier, in the same shape for every country and registry source.",
        "properties": {
          "status": {
            "type": "string",
            "nullable": true,
            "enum": [
              "not_requested",
              "pending",
              "delivered",
              "unavailable",
              null
            ],
            "description": "`delivered` when the registry published ownership; `unavailable` when it did not (see `unavailable_reason`); `pending` while the registry is still fetching it; `not_requested` for the Basic tier."
          },
          "tier_requested": {
            "type": "string",
            "nullable": true,
            "enum": [
              "basic",
              "shareholders",
              "ubo",
              null
            ],
            "description": "The tier the workflow ordered."
          },
          "tier_delivered": {
            "type": "string",
            "nullable": true,
            "enum": [
              "basic",
              "shareholders",
              "ubo",
              null
            ],
            "description": "The tier the registry delivered (and that is billed). A UBO request answered with direct shareholders only is `shareholders`."
          },
          "unavailable_reason": {
            "type": "string",
            "nullable": true,
            "enum": [
              "no_owners_on_record",
              "no_natural_person_owner",
              "ownership_section_unavailable",
              "company_not_found",
              "ambiguous_company_match",
              "missing_registration_number",
              "entity_type_not_covered",
              "provider_unavailable",
              "other",
              null
            ],
            "description": "Why a requested ownership tier was not delivered. Null unless `status` is `unavailable` or `pending`."
          },
          "direct_ownership_complete": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the direct shareholders' stated stakes add up to 100% (within one percentage point of rounding); false when they do not; null when ownership was not delivered or a stake is not stated."
          },
          "unresolved": {
            "type": "array",
            "description": "Parts of the ownership chain the registry could not resolve, for example no group structure on record above the direct owners.",
            "items": {
              "type": "object",
              "properties": {
                "reason": {
                  "type": "string"
                },
                "section": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        },
        "required": [
          "status",
          "tier_requested",
          "tier_delivered",
          "unavailable_reason",
          "direct_ownership_complete",
          "unresolved"
        ]
      },
      "DigitalIdWalletApiWalletVerificationError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable machine-readable code, e.g. wallet_unavailable."
          },
          "detail": {
            "type": "string"
          }
        },
        "required": [
          "detail",
          "error"
        ]
      },
      "DigitalIdWalletApiWalletVerificationStartForbidden": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/DigitalIdWalletApiClientCredentialsForbiddenErrorMessage"
          },
          {
            "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
          }
        ]
      },
      "DigitalIdWalletApiClientCredentialsForbiddenErrorMessage": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "default": "Forbidden - User doesn't have permission"
          }
        }
      },
      "DigitalIdWalletApiWalletVerificationStartBadRequest": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationError"
          },
          {
            "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationFieldErrors"
          }
        ]
      },
      "DigitalIdWalletApiWalletVerificationFieldErrors": {
        "type": "object",
        "description": "Request validation errors: each rejected field with its messages.",
        "additionalProperties": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "DigitalIdWalletApiWalletVerificationResponse": {
        "type": "object",
        "description": "One standalone wallet verification, as every wallet endpoint answers it.",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "wallet_verification": {
            "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResult"
          },
          "vendor_data": {
            "type": "string",
            "nullable": true
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "The metadata object sent at start, or null."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "created_at",
          "metadata",
          "request_id",
          "vendor_data",
          "wallet_verification"
        ]
      },
      "DigitalIdWalletApiWalletVerificationResult": {
        "type": "object",
        "properties": {
          "wallet": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiWallet"
              }
            ],
            "readOnly": true
          },
          "country": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Not Finished while pending, then Approved (verified) or Declined."
          },
          "outcome": {
            "$ref": "#/components/schemas/DigitalIdWalletApiWalletVerificationResultOutcomeEnum"
          },
          "error": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          },
          "interaction": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiInteractionEnum"
              }
            ],
            "readOnly": true
          },
          "simulated": {
            "type": "boolean",
            "readOnly": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "next_action": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiWalletNextAction"
              }
            ],
            "nullable": true,
            "readOnly": true
          },
          "identity": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiWalletIdentity"
              }
            ],
            "nullable": true,
            "readOnly": true
          },
          "attributes": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "readOnly": true
          },
          "level_of_assurance": {
            "type": "string",
            "nullable": true
          },
          "verified_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "signature_valid": {
            "type": "boolean",
            "nullable": true,
            "description": "True once the credential's signature was verified; null for a simulated one."
          },
          "credential_type": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "attributes",
          "country",
          "credential_type",
          "error",
          "expires_at",
          "identity",
          "interaction",
          "level_of_assurance",
          "next_action",
          "outcome",
          "signature_valid",
          "simulated",
          "status",
          "verified_at",
          "wallet"
        ]
      },
      "DigitalIdWalletApiWalletIdentity": {
        "type": "object",
        "properties": {
          "full_name": {
            "type": "string",
            "nullable": true
          },
          "first_name": {
            "type": "string",
            "nullable": true
          },
          "last_name": {
            "type": "string",
            "nullable": true
          },
          "date_of_birth": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nationality": {
            "type": "string",
            "nullable": true,
            "description": "ISO3 nationality, only when the wallet asserts one (never inferred)."
          },
          "issuing_state": {
            "type": "string",
            "description": "ISO3 country whose scheme issued the identity."
          }
        },
        "required": [
          "date_of_birth",
          "first_name",
          "full_name",
          "issuing_state",
          "last_name",
          "nationality"
        ]
      },
      "DigitalIdWalletApiWalletNextAction": {
        "type": "object",
        "properties": {
          "type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiWalletNextActionTypeEnum"
              }
            ],
            "description": "redirect: send the user's browser to url. confirm_in_app: show verification_code to the user, who checks it matches the code in their wallet app and confirms there; then poll.\n\n* `redirect` - redirect\n* `confirm_in_app` - confirm_in_app"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "redirect only: where the user signs in with the wallet."
          },
          "verification_code": {
            "type": "string",
            "description": "confirm_in_app only: the 4-digit comparison code the wallet app shows too."
          },
          "poll_interval_seconds": {
            "type": "integer",
            "description": "confirm_in_app only: how often to call POST .../verifications/{request_id}/poll/ for prompt feedback. Didit also polls pending sign-ins in the background, so the webhook reports the outcome even when you do not poll."
          }
        },
        "required": [
          "type"
        ]
      },
      "DigitalIdWalletApiWalletNextActionTypeEnum": {
        "enum": [
          "redirect",
          "confirm_in_app"
        ],
        "type": "string",
        "description": "* `redirect` - redirect\n* `confirm_in_app` - confirm_in_app"
      },
      "DigitalIdWalletApiInteractionEnum": {
        "enum": [
          "redirect",
          "in_app"
        ],
        "type": "string",
        "description": "* `redirect` - redirect\n* `in_app` - in_app"
      },
      "DigitalIdWalletApiWalletVerificationResultOutcomeEnum": {
        "enum": [
          "pending",
          "verified",
          "cancelled",
          "timeout",
          "failed"
        ],
        "type": "string",
        "description": "* `pending` - Pending\n* `verified` - Verified\n* `cancelled` - Cancelled by the user\n* `timeout` - Timed out\n* `failed` - Failed"
      },
      "DigitalIdWalletApiWallet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Catalog id of the wallet, e.g. bankid_se."
          },
          "name": {
            "type": "string"
          },
          "issuing_authority": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "issuing_authority",
          "name"
        ]
      },
      "DigitalIdWalletApiEudiWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a EUDI Wallet verification (AUT, BEL, BGR, HRV, CYP, CZE, DNK, EST, FIN, FRA, DEU, GRC, HUN, IRL, ITA, LVA, LTU, LUX, MLT, NLD, POL, PRT, ROU, SVK, SVN, ESP, SWE, ISL, LIE, NOR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiEudiWalletVerificationStartCountryEnum"
              }
            ],
            "description": "ISO 3166-1 alpha-3 country of the EUDI Wallet identity.\n\n* `AUT` - AUT\n* `BEL` - BEL\n* `BGR` - BGR\n* `HRV` - HRV\n* `CYP` - CYP\n* `CZE` - CZE\n* `DNK` - DNK\n* `EST` - EST\n* `FIN` - FIN\n* `FRA` - FRA\n* `DEU` - DEU\n* `GRC` - GRC\n* `HUN` - HUN\n* `IRL` - IRL\n* `ITA` - ITA\n* `LVA` - LVA\n* `LTU` - LTU\n* `LUX` - LUX\n* `MLT` - MLT\n* `NLD` - NLD\n* `POL` - POL\n* `PRT` - PRT\n* `ROU` - ROU\n* `SVK` - SVK\n* `SVN` - SVN\n* `ESP` - ESP\n* `SWE` - SWE\n* `ISL` - ISL\n* `LIE` - LIE\n* `NOR` - NOR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "country",
          "return_url"
        ]
      },
      "DigitalIdWalletApiDeviceEnum": {
        "enum": [
          "same_device",
          "cross_device"
        ],
        "type": "string",
        "description": "* `same_device` - same_device\n* `cross_device` - cross_device"
      },
      "DigitalIdWalletApiEudiWalletVerificationStartCountryEnum": {
        "enum": [
          "AUT",
          "BEL",
          "BGR",
          "HRV",
          "CYP",
          "CZE",
          "DNK",
          "EST",
          "FIN",
          "FRA",
          "DEU",
          "GRC",
          "HUN",
          "IRL",
          "ITA",
          "LVA",
          "LTU",
          "LUX",
          "MLT",
          "NLD",
          "POL",
          "PRT",
          "ROU",
          "SVK",
          "SVN",
          "ESP",
          "SWE",
          "ISL",
          "LIE",
          "NOR"
        ],
        "type": "string",
        "description": "* `AUT` - AUT\n* `BEL` - BEL\n* `BGR` - BGR\n* `HRV` - HRV\n* `CYP` - CYP\n* `CZE` - CZE\n* `DNK` - DNK\n* `EST` - EST\n* `FIN` - FIN\n* `FRA` - FRA\n* `DEU` - DEU\n* `GRC` - GRC\n* `HUN` - HUN\n* `IRL` - IRL\n* `ITA` - ITA\n* `LVA` - LVA\n* `LTU` - LTU\n* `LUX` - LUX\n* `MLT` - MLT\n* `NLD` - NLD\n* `POL` - POL\n* `PRT` - PRT\n* `ROU` - ROU\n* `SVK` - SVK\n* `SVN` - SVN\n* `ESP` - ESP\n* `SWE` - SWE\n* `ISL` - ISL\n* `LIE` - LIE\n* `NOR` - NOR"
      },
      "DigitalIdWalletApiConnectidWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a ConnectID verification (AUS).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiConnectidWalletVerificationStartCountryEnum"
              }
            ],
            "default": "AUS",
            "description": "ISO 3166-1 alpha-3 country of the ConnectID identity. Defaults to AUS, the only country it serves.\n\n* `AUS` - AUS"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiConnectidWalletVerificationStartCountryEnum": {
        "enum": [
          "AUS"
        ],
        "type": "string",
        "description": "* `AUS` - AUS"
      },
      "DigitalIdWalletApiAudkenniWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Auðkenni verification (ISL).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiAudkenniWalletVerificationStartCountryEnum"
              }
            ],
            "default": "ISL",
            "description": "ISO 3166-1 alpha-3 country of the Auðkenni identity. Defaults to ISL, the only country it serves.\n\n* `ISL` - ISL"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiAudkenniWalletVerificationStartCountryEnum": {
        "enum": [
          "ISL"
        ],
        "type": "string",
        "description": "* `ISL` - ISL"
      },
      "DigitalIdWalletApiFranceconnectWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a FranceConnect verification (FRA).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiFranceconnectWalletVerificationStartCountryEnum"
              }
            ],
            "default": "FRA",
            "description": "ISO 3166-1 alpha-3 country of the FranceConnect identity. Defaults to FRA, the only country it serves.\n\n* `FRA` - FRA"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiFranceconnectWalletVerificationStartCountryEnum": {
        "enum": [
          "FRA"
        ],
        "type": "string",
        "description": "* `FRA` - FRA"
      },
      "DigitalIdWalletApiDiiaWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Diia verification (UKR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDiiaWalletVerificationStartCountryEnum"
              }
            ],
            "default": "UKR",
            "description": "ISO 3166-1 alpha-3 country of the Diia identity. Defaults to UKR, the only country it serves.\n\n* `UKR` - UKR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiDiiaWalletVerificationStartCountryEnum": {
        "enum": [
          "UKR"
        ],
        "type": "string",
        "description": "* `UKR` - UKR"
      },
      "DigitalIdWalletApiMojeidWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a MojeID verification (CZE).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryE2dEnum"
              }
            ],
            "default": "CZE",
            "description": "ISO 3166-1 alpha-3 country of the MojeID identity. Defaults to CZE, the only country it serves.\n\n* `CZE` - CZE"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiCountryE2dEnum": {
        "enum": [
          "CZE"
        ],
        "type": "string",
        "description": "* `CZE` - CZE"
      },
      "DigitalIdWalletApiBankidCzWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Bank iD verification (CZE).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryE2dEnum"
              }
            ],
            "default": "CZE",
            "description": "ISO 3166-1 alpha-3 country of the Bank iD identity. Defaults to CZE, the only country it serves.\n\n* `CZE` - CZE"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiEparakstsMobileWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a eParaksts mobile verification (LVA).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiEparakstsMobileWalletVerificationStartCountryEnum"
              }
            ],
            "default": "LVA",
            "description": "ISO 3166-1 alpha-3 country of the eParaksts mobile identity. Defaults to LVA, the only country it serves.\n\n* `LVA` - LVA"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiEparakstsMobileWalletVerificationStartCountryEnum": {
        "enum": [
          "LVA"
        ],
        "type": "string",
        "description": "* `LVA` - LVA"
      },
      "DigitalIdWalletApiIdcardEeWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Estonian ID-card verification (EST).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdcardEeWalletVerificationStartCountryEnum"
              }
            ],
            "default": "EST",
            "description": "ISO 3166-1 alpha-3 country of the Estonian ID-card identity. Defaults to EST, the only country it serves.\n\n* `EST` - EST"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiIdcardEeWalletVerificationStartCountryEnum": {
        "enum": [
          "EST"
        ],
        "type": "string",
        "description": "* `EST` - EST"
      },
      "DigitalIdWalletApiMobileIdWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Mobile-ID verification (EST, LTU).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiMobileIdWalletVerificationStartCountryEnum"
              }
            ],
            "description": "ISO 3166-1 alpha-3 country of the Mobile-ID identity.\n\n* `EST` - EST\n* `LTU` - LTU"
          },
          "personal_code": {
            "type": "string",
            "minLength": 1,
            "description": "The user's national personal identification code. It addresses the user's Mobile-ID app; the user confirms the comparison code and enters their PIN in the app. Never collect the PIN.",
            "pattern": "^[0-9-]{6,20}$"
          },
          "phone_number": {
            "type": "string",
            "minLength": 1,
            "description": "The Mobile-ID phone number in E.164 format (+372... or +370...).",
            "maxLength": 16
          }
        },
        "required": [
          "country",
          "personal_code",
          "phone_number"
        ]
      },
      "DigitalIdWalletApiMobileIdWalletVerificationStartCountryEnum": {
        "enum": [
          "EST",
          "LTU"
        ],
        "type": "string",
        "description": "* `EST` - EST\n* `LTU` - LTU"
      },
      "DigitalIdWalletApiSmartIdWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Smart-ID verification (EST, LVA, LTU, BEL).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiSmartIdWalletVerificationStartCountryEnum"
              }
            ],
            "description": "ISO 3166-1 alpha-3 country of the Smart-ID identity.\n\n* `EST` - EST\n* `LVA` - LVA\n* `LTU` - LTU\n* `BEL` - BEL"
          },
          "personal_code": {
            "type": "string",
            "minLength": 1,
            "description": "The user's national personal identification code. It addresses the user's Smart-ID app; the user confirms the comparison code and enters their PIN in the app. Never collect the PIN.",
            "pattern": "^[0-9-]{6,20}$"
          }
        },
        "required": [
          "country",
          "personal_code"
        ]
      },
      "DigitalIdWalletApiSmartIdWalletVerificationStartCountryEnum": {
        "enum": [
          "EST",
          "LVA",
          "LTU",
          "BEL"
        ],
        "type": "string",
        "description": "* `EST` - EST\n* `LVA` - LVA\n* `LTU` - LTU\n* `BEL` - BEL"
      },
      "DigitalIdWalletApiGovukWalletWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a GOV.UK Wallet verification (GBR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountry520Enum"
              }
            ],
            "default": "GBR",
            "description": "ISO 3166-1 alpha-3 country of the GOV.UK Wallet identity. Defaults to GBR, the only country it serves.\n\n* `GBR` - GBR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiCountry520Enum": {
        "enum": [
          "GBR"
        ],
        "type": "string",
        "description": "* `GBR` - GBR"
      },
      "DigitalIdWalletApiOneidWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a OneID verification (GBR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountry520Enum"
              }
            ],
            "default": "GBR",
            "description": "ISO 3166-1 alpha-3 country of the OneID identity. Defaults to GBR, the only country it serves.\n\n* `GBR` - GBR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiGovbrWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a gov.br verification (BRA).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiGovbrWalletVerificationStartCountryEnum"
              }
            ],
            "default": "BRA",
            "description": "ISO 3166-1 alpha-3 country of the gov.br identity. Defaults to BRA, the only country it serves.\n\n* `BRA` - BRA"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiGovbrWalletVerificationStartCountryEnum": {
        "enum": [
          "BRA"
        ],
        "type": "string",
        "description": "* `BRA` - BRA"
      },
      "DigitalIdWalletApiUaePassWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a UAE PASS verification (ARE).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiUaePassWalletVerificationStartCountryEnum"
              }
            ],
            "default": "ARE",
            "description": "ISO 3166-1 alpha-3 country of the UAE PASS identity. Defaults to ARE, the only country it serves.\n\n* `ARE` - ARE"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiUaePassWalletVerificationStartCountryEnum": {
        "enum": [
          "ARE"
        ],
        "type": "string",
        "description": "* `ARE` - ARE"
      },
      "DigitalIdWalletApiFrejaidWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Freja eID verification (SWE).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryEe9Enum"
              }
            ],
            "default": "SWE",
            "description": "ISO 3166-1 alpha-3 country of the Freja eID identity. Defaults to SWE, the only country it serves.\n\n* `SWE` - SWE"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiCountryEe9Enum": {
        "enum": [
          "SWE"
        ],
        "type": "string",
        "description": "* `SWE` - SWE"
      },
      "DigitalIdWalletApiPersonalausweisWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Personalausweis verification (DEU).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiPersonalausweisWalletVerificationStartCountryEnum"
              }
            ],
            "default": "DEU",
            "description": "ISO 3166-1 alpha-3 country of the Personalausweis identity. Defaults to DEU, the only country it serves.\n\n* `DEU` - DEU"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiPersonalausweisWalletVerificationStartCountryEnum": {
        "enum": [
          "DEU"
        ],
        "type": "string",
        "description": "* `DEU` - DEU"
      },
      "DigitalIdWalletApiFtnWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Finnish Trust Network verification (FIN).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiFtnWalletVerificationStartCountryEnum"
              }
            ],
            "default": "FIN",
            "description": "ISO 3166-1 alpha-3 country of the Finnish Trust Network identity. Defaults to FIN, the only country it serves.\n\n* `FIN` - FIN"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiFtnWalletVerificationStartCountryEnum": {
        "enum": [
          "FIN"
        ],
        "type": "string",
        "description": "* `FIN` - FIN"
      },
      "DigitalIdWalletApiIdinWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a iDIN verification (NLD).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiIdinWalletVerificationStartCountryEnum"
              }
            ],
            "default": "NLD",
            "description": "ISO 3166-1 alpha-3 country of the iDIN identity. Defaults to NLD, the only country it serves.\n\n* `NLD` - NLD"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiIdinWalletVerificationStartCountryEnum": {
        "enum": [
          "NLD"
        ],
        "type": "string",
        "description": "* `NLD` - NLD"
      },
      "DigitalIdWalletApiItsmeWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a itsme verification (BEL, LUX, NLD).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiItsmeWalletVerificationStartCountryEnum"
              }
            ],
            "description": "ISO 3166-1 alpha-3 country of the itsme identity.\n\n* `BEL` - BEL\n* `LUX` - LUX\n* `NLD` - NLD"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "country",
          "return_url"
        ]
      },
      "DigitalIdWalletApiItsmeWalletVerificationStartCountryEnum": {
        "enum": [
          "BEL",
          "LUX",
          "NLD"
        ],
        "type": "string",
        "description": "* `BEL` - BEL\n* `LUX` - LUX\n* `NLD` - NLD"
      },
      "DigitalIdWalletApiBuypassWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Buypass ID verification (NOR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryAfcEnum"
              }
            ],
            "default": "NOR",
            "description": "ISO 3166-1 alpha-3 country of the Buypass ID identity. Defaults to NOR, the only country it serves.\n\n* `NOR` - NOR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiCountryAfcEnum": {
        "enum": [
          "NOR"
        ],
        "type": "string",
        "description": "* `NOR` - NOR"
      },
      "DigitalIdWalletApiVippsWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a Vipps verification (NOR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryAfcEnum"
              }
            ],
            "default": "NOR",
            "description": "ISO 3166-1 alpha-3 country of the Vipps identity. Defaults to NOR, the only country it serves.\n\n* `NOR` - NOR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiBankidNoWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a BankID verification (NOR).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryAfcEnum"
              }
            ],
            "default": "NOR",
            "description": "ISO 3166-1 alpha-3 country of the BankID identity. Defaults to NOR, the only country it serves.\n\n* `NOR` - NOR"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiBankidSeWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a BankID verification (SWE).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiCountryEe9Enum"
              }
            ],
            "default": "SWE",
            "description": "ISO 3166-1 alpha-3 country of the BankID identity. Defaults to SWE, the only country it serves.\n\n* `SWE` - SWE"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiMitidWalletVerificationStartRequest": {
        "type": "object",
        "description": "Start a MitID verification (DNK).",
        "properties": {
          "vendor_data": {
            "type": "string",
            "nullable": true,
            "description": "Your own reference for this verification (e.g. your user id). Returned in results and webhooks."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true,
            "description": "Optional JSON object stored with the verification and returned in results and webhooks."
          },
          "sandbox_scenario": {
            "type": "string",
            "minLength": 1,
            "description": "Sandbox applications only: the simulated outcome - 'wallet_cancelled', 'wallet_timeout' or 'wallet_provider_error'; any other scenario (or none) verifies. Rejected on live applications. The full catalog is available at GET /v1/sandbox/scenarios/."
          },
          "country": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiMitidWalletVerificationStartCountryEnum"
              }
            ],
            "default": "DNK",
            "description": "ISO 3166-1 alpha-3 country of the MitID identity. Defaults to DNK, the only country it serves.\n\n* `DNK` - DNK"
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "description": "https URL the user's browser returns to after the wallet, with request_id and result appended. Its host must be registered in the application's allowed_return_hosts (or be its white-label domain). Never trust result on its own: read the outcome with GET .../verifications/{request_id}/ or the webhook.",
            "maxLength": 2048
          },
          "device": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DigitalIdWalletApiDeviceEnum"
              }
            ],
            "default": "same_device",
            "description": "same_device when the user signs in on the device showing your page, cross_device when they use another one (e.g. BankID's QR code).\n\n* `same_device` - same_device\n* `cross_device` - cross_device"
          }
        },
        "required": [
          "return_url"
        ]
      },
      "DigitalIdWalletApiMitidWalletVerificationStartCountryEnum": {
        "enum": [
          "DNK"
        ],
        "type": "string",
        "description": "* `DNK` - DNK"
      },
      "DigitalIdWalletApiWalletCatalogResponse": {
        "type": "object",
        "properties": {
          "wallets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DigitalIdWalletApiWalletCatalogEntry"
            }
          }
        },
        "required": [
          "wallets"
        ]
      },
      "DigitalIdWalletApiWalletCatalogEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "path": {
            "type": "string",
            "description": "The wallet's own start endpoint."
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "issuing_authority": {
            "type": "string"
          },
          "level_of_assurance": {
            "type": "string",
            "nullable": true
          },
          "interaction": {
            "$ref": "#/components/schemas/DigitalIdWalletApiInteractionEnum"
          },
          "required_fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "available": {
            "type": "boolean",
            "description": "Whether this application can start it in this environment now. Listed does not mean live."
          }
        },
        "required": [
          "available",
          "countries",
          "id",
          "interaction",
          "issuing_authority",
          "level_of_assurance",
          "name",
          "path",
          "required_fields"
        ]
      },
      "CaseDuplicateCaseDuplicate": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "case_number": {
            "type": "string",
            "nullable": true,
            "maxLength": 32
          },
          "title": {
            "type": "string",
            "maxLength": 255
          },
          "status": {
            "$ref": "#/components/schemas/CaseDuplicateStatusEnum"
          },
          "priority": {
            "$ref": "#/components/schemas/CaseDuplicatePriorityEnum"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "created_at",
          "title",
          "uuid"
        ]
      },
      "CaseDuplicateCaseDuplicatePage": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "next_offset": {
            "type": "integer",
            "nullable": true
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseDuplicateCaseDuplicate"
            }
          }
        },
        "required": [
          "count",
          "next_offset",
          "results"
        ]
      },
      "RoutingPublicationPolicyDraftResponse": {
        "type": "object",
        "properties": {
          "draft": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RoutingPublicationPolicyDraft"
              }
            ],
            "nullable": true
          }
        },
        "required": [
          "draft"
        ]
      },
      "RoutingPublicationPolicyDraftWriteRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "minimum": 0
          },
          "expected_revision": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "changes": {
            "type": "object",
            "additionalProperties": {}
          }
        },
        "required": [
          "changes",
          "expected_revision",
          "expected_version"
        ]
      },
      "CasePublicationPolicyDraft": {
        "type": "object",
        "properties": {
          "revision": {
            "type": "string",
            "format": "uuid"
          },
          "base_version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "changes": {},
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 254
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "base_version",
          "updated_at"
        ]
      },
      "CasePublicationPolicyDraftPreconditionRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "minimum": 0
          },
          "expected_revision": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        },
        "required": [
          "expected_revision",
          "expected_version"
        ]
      },
      "CaseCollaborationCaseNote": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "comment": {
            "type": "string"
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 255
          },
          "actor_name": {
            "type": "string",
            "nullable": true,
            "maxLength": 255
          },
          "mentioned_emails": {},
          "is_internal": {
            "type": "boolean"
          },
          "attachments": {},
          "tags": {},
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "reply_to": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CaseCollaborationCaseNoteReply"
              }
            ],
            "nullable": true,
            "readOnly": true
          },
          "is_pinned": {
            "type": "boolean"
          },
          "client_reference": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        },
        "required": [
          "comment",
          "created_at",
          "reply_to",
          "uuid"
        ]
      },
      "CustomerMessagingPaginatedCaseRequestList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=400&limit=100"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=200&limit=100"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerMessagingCaseRequest"
            }
          }
        }
      },
      "FraudCheckResponse": {
        "type": "object",
        "properties": {
          "check_id": {
            "type": "string",
            "format": "uuid"
          },
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Native verification session created for this check."
          },
          "client_reference": {
            "type": "string",
            "nullable": true
          },
          "processing_status": {
            "$ref": "#/components/schemas/FraudProcessingStatusEnum"
          },
          "profile_id": {
            "type": "string"
          },
          "profile_version": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "inputs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudCheckInput"
            }
          },
          "modules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudCheckModuleReport"
            }
          },
          "attribute_evidence": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            }
          },
          "compound_evidence": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            }
          },
          "risk": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudCheckRisk"
            }
          },
          "network": {
            "type": "object",
            "additionalProperties": {}
          },
          "enrichment": {
            "type": "object",
            "additionalProperties": {}
          },
          "identity_relationship": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FraudCheckIdentityRelationship"
              }
            ],
            "nullable": true
          },
          "recommendation": {
            "$ref": "#/components/schemas/FraudRecommendationEnum"
          },
          "next_action": {
            "$ref": "#/components/schemas/FraudNextActionEnum"
          },
          "decision_reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "coverage": {
            "type": "object",
            "additionalProperties": {}
          },
          "usage": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            }
          },
          "vendor_data": {
            "type": "string",
            "nullable": true
          },
          "metadata": {
            "nullable": true
          }
        },
        "required": [
          "attribute_evidence",
          "check_id",
          "client_reference",
          "completed_at",
          "compound_evidence",
          "coverage",
          "created_at",
          "decision_reasons",
          "inputs",
          "modules",
          "network",
          "next_action",
          "processing_status",
          "profile_id",
          "profile_version",
          "recommendation",
          "risk",
          "usage"
        ]
      },
      "CaseReviewTeam": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseReviewTeamMember"
            },
            "maxItems": 250
          },
          "is_active": {
            "type": "boolean"
          },
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        }
      },
      "CaseActionCaseEntityActionRequest": {
        "type": "object",
        "properties": {
          "client_reference": {
            "type": "string",
            "format": "uuid"
          },
          "retry": {
            "type": "boolean",
            "default": false
          },
          "action": {
            "$ref": "#/components/schemas/CaseActionActionEnum"
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "note": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "action"
        ]
      },
      "RoutingPublicationPaginatedPolicyRevisionList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=400&limit=100"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=200&limit=100"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RoutingPublicationPolicyRevision"
            }
          }
        }
      },
      "FraudRecommendationEnum": {
        "enum": [
          "approve",
          "review",
          "reject"
        ],
        "type": "string",
        "description": "* `approve` - Approve\n* `review` - Review\n* `reject` - Reject"
      },
      "CustomerMessagingCaseRequestPreviewResponse": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "recipient": {
            "type": "string",
            "format": "email"
          },
          "sender": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "requires_user_action": {
            "type": "boolean"
          },
          "preview_token": {
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "html",
          "preview_token",
          "recipient",
          "request_id",
          "requires_user_action",
          "sender",
          "subject"
        ]
      },
      "CustomerMessagingCaseCustomerResponseRequest": {
        "type": "object",
        "properties": {
          "full_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "date_of_birth": {
            "type": "string",
            "format": "date"
          },
          "file": {
            "type": "string",
            "format": "binary",
            "writeOnly": true
          }
        }
      },
      "CaseCollaborationCaseNoteReply": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "actor_name": {
            "type": "string",
            "nullable": true
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true
          },
          "comment": {
            "type": "string",
            "maxLength": 300
          }
        },
        "required": [
          "actor_email",
          "actor_name",
          "comment",
          "uuid"
        ]
      },
      "FraudCheckModuleReport": {
        "type": "object",
        "properties": {
          "module": {
            "$ref": "#/components/schemas/FraudExcludeEnum"
          },
          "status": {
            "$ref": "#/components/schemas/FraudStatusEnum"
          },
          "reason": {
            "type": "string",
            "nullable": true
          },
          "latency_ms": {
            "type": "integer"
          },
          "freshness": {
            "type": "string",
            "nullable": true
          },
          "billable_units": {
            "type": "integer"
          }
        },
        "required": [
          "billable_units",
          "freshness",
          "latency_ms",
          "module",
          "reason",
          "status"
        ]
      },
      "CaseDuplicateEntityTypeEnum": {
        "enum": [
          "session",
          "business_session",
          "transaction"
        ],
        "type": "string",
        "description": "* `session` - Session\n* `business_session` - Business Session\n* `transaction` - Transaction"
      },
      "FraudClientCredentialsErrorMessage": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "default": "Authentication failed: Invalid client access token."
          }
        }
      },
      "FraudAvailabilityEnum": {
        "enum": [
          "available",
          "not_requested",
          "no_reference",
          "insufficient_history",
          "unsupported_region",
          "source_unavailable"
        ],
        "type": "string",
        "description": "* `available` - Available\n* `not_requested` - Not Requested\n* `no_reference` - No Reference\n* `insufficient_history` - Insufficient History\n* `unsupported_region` - Unsupported Region\n* `source_unavailable` - Source Unavailable"
      },
      "CasePublicationPolicyDraftResponse": {
        "type": "object",
        "properties": {
          "draft": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CasePublicationPolicyDraft"
              }
            ],
            "nullable": true
          }
        },
        "required": [
          "draft"
        ]
      },
      "FraudCheckAttributesRequest": {
        "type": "object",
        "description": "Corroborating attributes. All optional; they widen module coverage.",
        "properties": {
          "first_name": {
            "type": "string",
            "maxLength": 128
          },
          "last_name": {
            "type": "string",
            "maxLength": 128
          },
          "full_name": {
            "type": "string",
            "maxLength": 256
          },
          "date_of_birth": {
            "type": "string",
            "format": "date"
          },
          "nationality": {
            "type": "string",
            "maxLength": 3
          },
          "gender": {
            "type": "string",
            "maxLength": 16
          },
          "address": {
            "type": "string",
            "maxLength": 512
          },
          "city": {
            "type": "string",
            "maxLength": 128
          },
          "state": {
            "type": "string",
            "maxLength": 128
          },
          "postal_code": {
            "type": "string",
            "maxLength": 32
          }
        }
      },
      "NetworkNote": {
        "type": "object",
        "required": [
          "uuid",
          "actor_email",
          "comment",
          "client_reference",
          "created_at"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "readOnly": true,
            "description": "Authenticated author, assigned by the server."
          },
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10000
          },
          "client_reference": {
            "type": "string",
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        }
      },
      "CaseActionEntityTypeEnum": {
        "enum": [
          "user",
          "business"
        ],
        "type": "string",
        "description": "* `user` - user\n* `business` - business"
      },
      "CaseRoutingCondition": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "enum": [
              "source",
              "priority",
              "tags"
            ]
          },
          "operator": {
            "type": "string",
            "enum": [
              "equals",
              "in",
              "contains"
            ]
          },
          "value": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          }
        },
        "required": [
          "field",
          "operator",
          "value"
        ],
        "description": "Source and priority support equals or in with supported values. Tags support contains with one non-empty tag."
      },
      "RoutingPublicationPolicyRevision": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "snapshot": {},
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 254
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "published_at",
          "snapshot",
          "version"
        ]
      },
      "CasePublicationPolicyRevision": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "snapshot": {},
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 254
          },
          "published_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "published_at",
          "snapshot",
          "version"
        ]
      },
      "FraudCheckIdentityRelationship": {
        "type": "object",
        "properties": {
          "result": {
            "$ref": "#/components/schemas/FraudResultEnum"
          },
          "reference_type": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "availability": {
            "$ref": "#/components/schemas/FraudAvailabilityEnum"
          },
          "reason_codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "availability",
          "country",
          "reason_codes",
          "reference_type",
          "result"
        ]
      },
      "CasePublicationPaginatedPolicyRevisionList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=400&limit=100"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=200&limit=100"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CasePublicationPolicyRevision"
            }
          }
        }
      },
      "CaseDuplicateBlankEnum": {
        "enum": [
          ""
        ]
      },
      "FraudCheckPlan": {
        "type": "object",
        "properties": {
          "profile_id": {
            "type": "string"
          },
          "profile_version": {
            "type": "string"
          },
          "modules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudCheckPlannedModule"
            }
          },
          "estimated_price": {
            "type": "string",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "is_sandbox": {
            "type": "boolean"
          },
          "can_afford": {
            "type": "boolean"
          }
        },
        "required": [
          "can_afford",
          "currency",
          "estimated_price",
          "is_sandbox",
          "modules",
          "profile_id",
          "profile_version"
        ]
      },
      "CaseReviewTeamUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseReviewTeamMember"
            },
            "maxItems": 250
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "RoutingPublicationPolicyDraft": {
        "type": "object",
        "properties": {
          "revision": {
            "type": "string",
            "format": "uuid"
          },
          "base_version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "changes": {},
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 254
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "base_version",
          "updated_at"
        ]
      },
      "FraudCheckRequestRequest": {
        "type": "object",
        "properties": {
          "client_reference": {
            "type": "string",
            "minLength": 1,
            "description": "Your own reference for this check. Doubles as the idempotency key: reusing it with the same body returns the original check without running or billing the modules again; reusing it with a different body returns 409.",
            "maxLength": 255
          },
          "profile": {
            "type": "string",
            "minLength": 1,
            "default": "standard",
            "description": "Orchestration profile id. Defaults to the Didit `standard` profile.",
            "maxLength": 64
          },
          "profile_version": {
            "type": "string",
            "minLength": 1,
            "description": "Pin a frozen profile version. Defaults to the current version of the profile.",
            "maxLength": 32
          },
          "subject": {
            "$ref": "#/components/schemas/FraudCheckSubjectRequest"
          },
          "context": {
            "$ref": "#/components/schemas/FraudCheckContextRequest"
          },
          "checks": {
            "$ref": "#/components/schemas/FraudCheckModuleSelectionRequest"
          },
          "vendor_data": {
            "type": "string",
            "maxLength": 1000
          },
          "metadata": {}
        },
        "required": [
          "subject"
        ]
      },
      "CaseDuplicateCaseSubjectInputRequest": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/CaseDuplicateTypeEnum"
          },
          "uuid": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "type",
          "uuid"
        ]
      },
      "CaseReviewTeamMember": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "availability": {
            "type": "string",
            "enum": [
              "available",
              "unavailable"
            ],
            "default": "available"
          },
          "capacity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "default": 10
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64
            },
            "maxItems": 25
          },
          "available_from": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "available_until": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "user_id"
        ]
      },
      "CaseRoutingPreviewRequest": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "MANUAL",
              "AML_SCREENING",
              "TRANSACTION_RULE",
              "WORKFLOW_BUILDER"
            ]
          },
          "priority": {
            "type": "string",
            "enum": [
              "LOW",
              "MEDIUM",
              "HIGH"
            ],
            "default": "MEDIUM"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64
            },
            "maxItems": 50
          },
          "rule_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "draft": {
            "$ref": "#/components/schemas/CaseRoutingRuleCreate"
          }
        },
        "required": [
          "source"
        ]
      },
      "FraudExcludeEnum": {
        "enum": [
          "normalization",
          "email_risk",
          "email_social",
          "phone_social",
          "phone_risk",
          "ip_risk",
          "database_validation",
          "networks_same_org",
          "networks_cross_org",
          "biometric_identity"
        ],
        "type": "string",
        "description": "* `normalization` - Normalization\n* `email_risk` - Email Risk\n* `email_social` - Email Social\n* `phone_social` - Phone Social\n* `phone_risk` - Phone Risk\n* `ip_risk` - Ip Risk\n* `database_validation` - Database Validation\n* `networks_same_org` - Networks Same Org\n* `networks_cross_org` - Networks Cross Org\n* `biometric_identity` - Biometric Identity"
      },
      "CaseDuplicateCaseLinkCreateRequest": {
        "type": "object",
        "properties": {
          "entity_type": {
            "$ref": "#/components/schemas/CaseDuplicateEntityTypeEnum"
          },
          "entity_uuid": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "entity_type",
          "entity_uuid"
        ]
      },
      "CaseDuplicateStatusEnum": {
        "enum": [
          "OPEN",
          "AWAITING_USER",
          "RESOLVED"
        ],
        "type": "string",
        "description": "* `OPEN` - Open\n* `AWAITING_USER` - Awaiting user\n* `RESOLVED` - Resolved"
      },
      "FraudBandEnum": {
        "enum": [
          "low",
          "medium",
          "high",
          "unknown"
        ],
        "type": "string",
        "description": "* `low` - Low\n* `medium` - Medium\n* `high` - High\n* `unknown` - Unknown"
      },
      "CaseDuplicatePriorityEnum": {
        "enum": [
          "LOW",
          "MEDIUM",
          "HIGH"
        ],
        "type": "string",
        "description": "* `LOW` - Low\n* `MEDIUM` - Medium\n* `HIGH` - High"
      },
      "FraudStatusEnum": {
        "enum": [
          "planned",
          "completed",
          "skipped",
          "failed"
        ],
        "type": "string",
        "description": "* `planned` - Planned\n* `completed` - Completed\n* `skipped` - Skipped\n* `failed` - Failed"
      },
      "FraudCheckInput": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string",
            "description": "Redacted handle for the submitted identifier."
          },
          "type": {
            "$ref": "#/components/schemas/FraudTypeEnum"
          },
          "namespace": {
            "type": "object",
            "additionalProperties": {}
          },
          "quality": {
            "type": "string"
          },
          "normalization": {
            "type": "object",
            "additionalProperties": {}
          },
          "availability": {
            "$ref": "#/components/schemas/FraudAvailabilityEnum"
          }
        },
        "required": [
          "availability",
          "namespace",
          "normalization",
          "quality",
          "reference",
          "type"
        ]
      },
      "CustomerMessagingPurposesEnum": {
        "enum": [
          "identity_document",
          "proof_of_address",
          "business_document",
          "confirm_details",
          "review_in_progress"
        ],
        "type": "string",
        "description": "* `identity_document` - identity_document\n* `proof_of_address` - proof_of_address\n* `business_document` - business_document\n* `confirm_details` - confirm_details\n* `review_in_progress` - review_in_progress"
      },
      "FraudTypeEnum": {
        "enum": [
          "email",
          "phone",
          "national_id",
          "tax_number",
          "passport_number",
          "driving_licence_number",
          "residence_permit_number",
          "voter_id",
          "external_id"
        ],
        "type": "string",
        "description": "* `email` - Email\n* `phone` - Phone\n* `national_id` - National Id\n* `tax_number` - Tax Number\n* `passport_number` - Passport Number\n* `driving_licence_number` - Driving Licence Number\n* `residence_permit_number` - Residence Permit Number\n* `voter_id` - Voter Id\n* `external_id` - External Id"
      },
      "CaseDuplicateCaseSubjectInput": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/CaseDuplicateTypeEnum"
          },
          "uuid": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "type",
          "uuid"
        ]
      },
      "CaseReviewTeamCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseReviewTeamMember"
            },
            "maxItems": 250
          },
          "is_active": {
            "type": "boolean"
          }
        },
        "required": [
          "name",
          "members"
        ]
      },
      "CaseDuplicateCaseDuplicateQueryRequest": {
        "type": "object",
        "properties": {
          "subject": {
            "$ref": "#/components/schemas/CaseDuplicateCaseSubjectInputRequest"
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseDuplicateCaseLinkCreateRequest"
            }
          },
          "offset": {
            "type": "integer",
            "maximum": 1000000,
            "minimum": 0,
            "default": 0
          }
        }
      },
      "CaseDuplicateResolutionEnum": {
        "enum": [
          "FALSE_POSITIVE",
          "VALID_THREAT"
        ],
        "type": "string",
        "description": "* `FALSE_POSITIVE` - False positive\n* `VALID_THREAT` - Valid threat"
      },
      "CasePublicationPolicyDraftWriteRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "minimum": 0
          },
          "expected_revision": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "changes": {
            "type": "object",
            "additionalProperties": {}
          }
        },
        "required": [
          "changes",
          "expected_revision",
          "expected_version"
        ]
      },
      "FraudCheckSubjectRequest": {
        "type": "object",
        "properties": {
          "selfie": {
            "type": "string",
            "minLength": 1,
            "description": "Base64 JPEG, PNG or WebP selfie, up to 6 MB. No reference image or URL.",
            "maxLength": 8388672
          },
          "identifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudCheckIdentifierRequest"
            },
            "description": "One or more typed identifiers. One is enough.",
            "maxItems": 10,
            "minItems": 1
          },
          "attributes": {
            "$ref": "#/components/schemas/FraudCheckAttributesRequest"
          }
        },
        "required": [
          "identifiers"
        ]
      },
      "RoutingPublicationRoutingCondition": {
        "type": "object",
        "properties": {
          "field": {
            "$ref": "#/components/schemas/RoutingPublicationFieldEnum"
          },
          "operator": {
            "$ref": "#/components/schemas/RoutingPublicationOperatorEnum"
          },
          "value": {}
        },
        "required": [
          "field",
          "operator",
          "value"
        ]
      },
      "CaseActionCaseActionReceipt": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "client_reference": {
            "type": "string",
            "format": "uuid"
          },
          "action": {
            "type": "string",
            "maxLength": 32
          },
          "status": {
            "$ref": "#/components/schemas/CaseActionStatusEnum"
          },
          "result": {},
          "error": {
            "type": "string",
            "maxLength": 255
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "maxLength": 254
          },
          "attempts": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "action",
          "client_reference",
          "created_at",
          "status",
          "updated_at",
          "uuid"
        ]
      },
      "FraudCheckContextRequest": {
        "type": "object",
        "properties": {
          "ip_address": {
            "type": "string",
            "minLength": 1
          },
          "user_agent": {
            "type": "string",
            "maxLength": 512
          },
          "country": {
            "type": "string",
            "description": "Country the subject claims to be in. Contextual only - never proof of identity ownership.",
            "maxLength": 3
          },
          "purpose": {
            "type": "string",
            "maxLength": 128
          },
          "consent_obtained": {
            "type": "boolean"
          }
        }
      },
      "CustomerMessagingCaseCustomerResponseResult": {
        "type": "object",
        "properties": {
          "responded_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "responded_at"
        ]
      },
      "CustomerMessagingCaseRequestContact": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "verified_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "email",
          "uuid",
          "verified_at"
        ]
      },
      "FraudClientCredentialsForbiddenErrorMessage": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "default": "Forbidden - User doesn't have permission"
          }
        }
      },
      "CasePublicationAssignmentMethodEnum": {
        "enum": [
          "MANUAL",
          "AUTOMATIC"
        ],
        "type": "string",
        "description": "* `MANUAL` - Manual\n* `AUTOMATIC` - Automatic"
      },
      "CaseDuplicateNullEnum": {
        "enum": [
          null
        ]
      },
      "CustomerMessagingLanguageEnum": {
        "enum": [
          "en",
          "es",
          "pt"
        ],
        "type": "string",
        "description": "* `en` - en\n* `es` - es\n* `pt` - pt"
      },
      "CaseDuplicateCaseFraudSourceContextRequest": {
        "type": "object",
        "properties": {
          "check_id": {
            "type": "string",
            "format": "uuid"
          },
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "source_section": {
            "type": "string",
            "minLength": 1,
            "pattern": "^[A-Z][A-Z0-9_:-]{0,63}$"
          }
        },
        "required": [
          "check_id",
          "request_id",
          "source_section"
        ]
      },
      "FraudCheckPlannedModule": {
        "type": "object",
        "properties": {
          "module": {
            "$ref": "#/components/schemas/FraudExcludeEnum"
          },
          "available": {
            "type": "boolean"
          },
          "availability_reason": {
            "type": "string",
            "nullable": true
          },
          "will_run": {
            "type": "boolean"
          },
          "selection_reason": {
            "type": "string",
            "nullable": true
          },
          "estimated_price": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "availability_reason",
          "available",
          "estimated_price",
          "module",
          "selection_reason",
          "will_run"
        ]
      },
      "CustomerMessagingCaseRequestOptions": {
        "type": "object",
        "properties": {
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerMessagingCaseRequestContact"
            }
          },
          "purposes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerMessagingPurposesEnum"
            }
          },
          "languages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerMessagingLanguagesEnum"
            }
          }
        },
        "required": [
          "contacts",
          "languages",
          "purposes"
        ]
      },
      "CaseCollaborationPaginatedCaseNoteList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=400&limit=100"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?offset=200&limit=100"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseCollaborationCaseNote"
            }
          }
        }
      },
      "FraudProcessingStatusEnum": {
        "enum": [
          "pending",
          "running",
          "completed",
          "failed"
        ],
        "type": "string",
        "description": "* `pending` - Pending\n* `running` - Running\n* `completed` - Completed\n* `failed` - Failed"
      },
      "CasePublicationCaseBlueprint": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "maxLength": 24
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "assignment_method": {
            "$ref": "#/components/schemas/CasePublicationAssignmentMethodEnum"
          },
          "assignee_pool": {},
          "max_active_cases": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0,
            "nullable": true
          },
          "escalation_enabled": {
            "type": "boolean"
          },
          "escalation_blueprint": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "escalation_blueprint_name": {
            "type": "string",
            "readOnly": true
          },
          "transfer_enabled": {
            "type": "boolean"
          },
          "four_eyes_checker_blueprint": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "four_eyes_checker_blueprint_name": {
            "type": "string",
            "readOnly": true
          },
          "require_resolution_note": {
            "type": "boolean"
          },
          "content_config": {},
          "version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "default_deadline_hours": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0,
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "preset_key": {
            "type": "string",
            "nullable": true,
            "maxLength": 64
          },
          "creation_sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "readOnly": true
          },
          "receives_escalation_from": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            },
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "created_at",
          "creation_sources",
          "escalation_blueprint_name",
          "four_eyes_checker_blueprint_name",
          "name",
          "receives_escalation_from",
          "updated_at",
          "uuid"
        ]
      },
      "CaseRoutingRuleUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "priority": {
            "type": "integer",
            "minimum": 0
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseRoutingCondition"
            },
            "maxItems": 20
          },
          "required_skills": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64
            },
            "maxItems": 25
          },
          "blueprint": {
            "type": "string",
            "format": "uuid"
          },
          "team": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "expected_version": {
            "type": "integer",
            "minimum": 1,
            "writeOnly": true,
            "description": "Version opened by the editor. When supplied, stale writes return 409 without changing the rule."
          }
        }
      },
      "CustomerMessagingCaseRequestPreviewRequest": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "string",
            "format": "uuid"
          },
          "purpose": {
            "$ref": "#/components/schemas/CustomerMessagingPurposeEnum"
          },
          "language": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CustomerMessagingLanguageEnum"
              }
            ],
            "default": "en"
          }
        },
        "required": [
          "contact_id",
          "purpose"
        ]
      },
      "CaseDuplicateCaseFraudSourceContext": {
        "type": "object",
        "properties": {
          "check_id": {
            "type": "string",
            "format": "uuid"
          },
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "source_section": {
            "type": "string",
            "pattern": "^[A-Z][A-Z0-9_:-]{0,63}$"
          }
        },
        "required": [
          "check_id",
          "request_id",
          "source_section"
        ]
      },
      "RoutingPublicationOperatorEnum": {
        "enum": [
          "equals",
          "in",
          "contains"
        ],
        "type": "string",
        "description": "* `equals` - equals\n* `in` - in\n* `contains` - contains"
      },
      "CaseRoutingPreview": {
        "type": "object",
        "properties": {
          "rule_uuid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "rule_name": {
            "type": "string",
            "nullable": true
          },
          "rule_version": {
            "type": "integer",
            "nullable": true
          },
          "blueprint_uuid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "team_uuid": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "assignee_user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "reason": {
            "type": "string"
          },
          "candidates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "user_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "eligible": {
                  "type": "boolean"
                },
                "active_cases": {
                  "type": "integer",
                  "nullable": true
                },
                "reason": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          },
          "matched_rules": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "priority": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "FraudDimensionEnum": {
        "enum": [
          "identity",
          "contact",
          "device_network",
          "behavioral",
          "fraud_network"
        ],
        "type": "string",
        "description": "* `identity` - Identity\n* `contact` - Contact\n* `device_network` - Device Network\n* `behavioral` - Behavioral\n* `fraud_network` - Fraud Network"
      },
      "FraudBadRequestErrorMessage": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "default": "Bad Request - Invalid request data"
          }
        }
      },
      "FraudNextActionEnum": {
        "enum": [
          "none",
          "manual_review",
          "step_up",
          "resubmit_capture"
        ],
        "type": "string",
        "description": "* `none` - None\n* `manual_review` - Manual Review\n* `step_up` - Step Up\n* `resubmit_capture` - Resubmit Capture"
      },
      "RoutingPublicationPolicyDraftPreconditionRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "minimum": 0
          },
          "expected_revision": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        },
        "required": [
          "expected_revision",
          "expected_version"
        ]
      },
      "FraudCheckRisk": {
        "type": "object",
        "properties": {
          "dimension": {
            "$ref": "#/components/schemas/FraudDimensionEnum"
          },
          "score": {
            "type": "integer",
            "nullable": true
          },
          "band": {
            "$ref": "#/components/schemas/FraudBandEnum"
          },
          "availability": {
            "$ref": "#/components/schemas/FraudAvailabilityEnum"
          },
          "requested_but_unavailable": {
            "type": "boolean",
            "description": "True when the request supplied everything this dimension needed and the platform still could not answer it. Such a check is never recommended for approval on the strength of the dimensions that did answer."
          },
          "reason_codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "evidence_indexes": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        },
        "required": [
          "availability",
          "band",
          "dimension",
          "evidence_indexes",
          "reason_codes",
          "requested_but_unavailable",
          "score"
        ]
      },
      "CaseDuplicateSourceEnum": {
        "enum": [
          "MANUAL",
          "AML_SCREENING",
          "TRANSACTION_RULE",
          "WORKFLOW_BUILDER"
        ],
        "type": "string",
        "description": "* `MANUAL` - Manual\n* `AML_SCREENING` - AML screening\n* `TRANSACTION_RULE` - Transaction rule\n* `WORKFLOW_BUILDER` - Workflow builder"
      },
      "CaseCollaborationPatchedCaseNoteUpdateRequest": {
        "type": "object",
        "properties": {
          "is_pinned": {
            "type": "boolean"
          }
        }
      },
      "CustomerMessagingPurposeEnum": {
        "enum": [
          "identity_document",
          "proof_of_address",
          "business_document",
          "confirm_details",
          "review_in_progress"
        ],
        "type": "string",
        "description": "* `identity_document` - identity_document\n* `proof_of_address` - proof_of_address\n* `business_document` - business_document\n* `confirm_details` - confirm_details\n* `review_in_progress` - review_in_progress"
      },
      "CaseDuplicateTypeEnum": {
        "enum": [
          "user",
          "business"
        ],
        "type": "string",
        "description": "* `user` - user\n* `business` - business"
      },
      "CaseCollaborationCaseNoteCreateRequest": {
        "type": "object",
        "properties": {
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10000
          },
          "reply_to": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "client_reference": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "mentioned_emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "minLength": 1
            }
          },
          "is_internal": {
            "type": "boolean",
            "default": false
          },
          "attachments": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {}
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "comment"
        ]
      },
      "CustomerMessagingLanguagesEnum": {
        "enum": [
          "en",
          "es",
          "pt"
        ],
        "type": "string",
        "description": "* `en` - en\n* `es` - es\n* `pt` - pt"
      },
      "CustomerMessagingCaseRequestConfirmRequest": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "string",
            "format": "uuid"
          },
          "purpose": {
            "$ref": "#/components/schemas/CustomerMessagingPurposeEnum"
          },
          "language": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CustomerMessagingLanguageEnum"
              }
            ],
            "default": "en"
          },
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "preview_token": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          }
        },
        "required": [
          "contact_id",
          "expires_at",
          "preview_token",
          "purpose",
          "request_id"
        ]
      },
      "CaseRoutingRule": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "priority": {
            "type": "integer",
            "minimum": 0
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseRoutingCondition"
            },
            "maxItems": 20
          },
          "required_skills": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64
            },
            "maxItems": 25
          },
          "blueprint": {
            "type": "string",
            "format": "uuid"
          },
          "team": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "version": {
            "type": "integer",
            "readOnly": true
          },
          "blueprint_name": {
            "type": "string",
            "readOnly": true
          },
          "team_name": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          }
        }
      },
      "FraudResultEnum": {
        "enum": [
          "match",
          "mismatch",
          "inconclusive",
          "no_reference"
        ],
        "type": "string",
        "description": "* `match` - Match\n* `mismatch` - Mismatch\n* `inconclusive` - Inconclusive\n* `no_reference` - No Reference"
      },
      "CaseRoutingRuleCreate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "priority": {
            "type": "integer",
            "minimum": 0
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseRoutingCondition"
            },
            "maxItems": 20
          },
          "required_skills": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64
            },
            "maxItems": 25
          },
          "blueprint": {
            "type": "string",
            "format": "uuid"
          },
          "team": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "is_active": {
            "type": "boolean"
          },
          "publish": {
            "type": "boolean",
            "writeOnly": true,
            "description": "Set false to save a never-published draft. The record remains inactive at version 0 until the draft is explicitly published. Omitting this field preserves immediate creation for existing integrations."
          }
        },
        "required": [
          "name",
          "conditions",
          "blueprint"
        ]
      },
      "FraudCheckIdentifierRequest": {
        "type": "object",
        "properties": {
          "type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FraudTypeEnum"
              }
            ],
            "description": "Identifier type. Determines which namespace fields are required.\n\n* `email` - Email\n* `phone` - Phone\n* `national_id` - National Id\n* `tax_number` - Tax Number\n* `passport_number` - Passport Number\n* `driving_licence_number` - Driving Licence Number\n* `residence_permit_number` - Residence Permit Number\n* `voter_id` - Voter Id\n* `external_id` - External Id"
          },
          "value": {
            "type": "string",
            "minLength": 1,
            "description": "The identifier value, in any customary format.",
            "maxLength": 255
          },
          "country": {
            "type": "string",
            "description": "ISO-3166 alpha-2 or alpha-3 issuing country. Required for government identifier types: the same digits mean different people in different countries.",
            "maxLength": 3
          },
          "issuer": {
            "type": "string",
            "description": "Optional issuing authority or sub-national issuer, when the country alone is not unique.",
            "maxLength": 128
          }
        },
        "required": [
          "type",
          "value"
        ]
      },
      "CaseActionActionEnum": {
        "enum": [
          "set_status",
          "add_tags",
          "add_note",
          "add_to_blocklist"
        ],
        "type": "string",
        "description": "* `set_status` - set_status\n* `add_tags` - add_tags\n* `add_note` - add_note\n* `add_to_blocklist` - add_to_blocklist"
      },
      "CaseActionCaseActionReceiptPage": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "next_offset": {
            "type": "integer",
            "nullable": true
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseActionCaseActionReceipt"
            }
          }
        },
        "required": [
          "count",
          "next_offset",
          "results"
        ]
      },
      "CaseActionCaseEntityActionResult": {
        "type": "object",
        "properties": {
          "receipt": {
            "$ref": "#/components/schemas/CaseActionCaseActionReceipt"
          },
          "entity_type": {
            "$ref": "#/components/schemas/CaseActionEntityTypeEnum"
          },
          "entity_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "action": {
            "type": "string"
          },
          "previous_status": {
            "type": "string"
          },
          "new_status": {
            "type": "string"
          },
          "tags_added": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "comment_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "blocklisted": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CustomerMessagingCaseRequest": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "purpose": {
            "type": "string",
            "readOnly": true
          },
          "language": {
            "type": "string",
            "readOnly": true
          },
          "recipient": {
            "type": "string",
            "format": "email",
            "readOnly": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "actor_email": {
            "type": "string",
            "format": "email",
            "readOnly": true,
            "nullable": true
          },
          "delivery_status": {
            "type": "string",
            "readOnly": true
          },
          "delivered_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "nullable": true
          },
          "cancelled_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "nullable": true
          },
          "responded_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "nullable": true
          },
          "response": {
            "readOnly": true,
            "nullable": true
          },
          "has_attachment": {
            "type": "boolean",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "actor_email",
          "cancelled_at",
          "created_at",
          "delivered_at",
          "delivery_status",
          "expires_at",
          "has_attachment",
          "language",
          "purpose",
          "recipient",
          "responded_at",
          "response",
          "uuid"
        ]
      },
      "CustomerMessagingCaseRequestPublic": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "purpose": {
            "$ref": "#/components/schemas/CustomerMessagingPurposeEnum"
          },
          "language": {
            "$ref": "#/components/schemas/CustomerMessagingLanguageEnum"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "responded_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "copy": {
            "type": "object",
            "additionalProperties": {}
          },
          "organization_name": {
            "type": "string"
          },
          "is_white_label": {
            "type": "boolean"
          },
          "customization": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          }
        },
        "required": [
          "copy",
          "customization",
          "expires_at",
          "is_white_label",
          "language",
          "organization_name",
          "purpose",
          "request_id",
          "responded_at"
        ]
      },
      "RoutingPublicationFieldEnum": {
        "enum": [
          "source",
          "priority",
          "tags"
        ],
        "type": "string",
        "description": "* `source` - source\n* `priority` - priority\n* `tags` - tags"
      },
      "RoutingPublicationCaseRoutingRule": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "priority": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RoutingPublicationRoutingCondition"
            }
          },
          "required_skills": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64
            },
            "maxItems": 25
          },
          "blueprint": {
            "type": "string",
            "format": "uuid"
          },
          "blueprint_name": {
            "type": "string",
            "readOnly": true
          },
          "team": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "team_name": {
            "type": "string",
            "readOnly": true
          },
          "is_active": {
            "type": "boolean"
          },
          "version": {
            "type": "integer",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "blueprint",
          "blueprint_name",
          "conditions",
          "created_at",
          "name",
          "team_name",
          "updated_at",
          "uuid",
          "version"
        ]
      },
      "CaseActionStatusEnum": {
        "enum": [
          "APPLIED",
          "FAILED"
        ],
        "type": "string",
        "description": "* `APPLIED` - Applied\n* `FAILED` - Failed"
      },
      "FraudCheckModuleSelectionRequest": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudExcludeEnum"
            }
          },
          "exclude": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FraudExcludeEnum"
            }
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Your application's API key, from Developers -> API keys in the Business Console. The primary key has full access. A named key can be scoped: none, read or write per resource, limited to some workflows or to approved sessions, to a list of IP addresses, and to an expiry date. 401 means the key is missing, wrong, revoked or expired; 403 means the key has no access to this resource or action, or the request came from an address outside its IP list; 404 on a session route means the session is outside the key's workflows or statuses. A key without media access receives image, video and PDF URLs as null, and a key without sessions write receives session links and tokens as null. See https://docs.didit.me/console/api-keys."
      },
      "TransactionTokenAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Transaction-Token",
        "description": "Short-lived scoped token minted by your backend via POST /v3/transactions/sdk-token/. Used by the Didit SDKs on the device-facing /v1/transactions/ endpoints."
      },
      "SessionTokenAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Session-Token",
        "description": "Short-lived token returned in the `session_token` field of POST /v3/session/. Used by the hosted verification flow (and custom sandbox UIs) to call session-scoped endpoints on behalf of the verifying user, without your server-side API key."
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "The application's client-credentials access token."
      },
      "CaseRequestToken": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Case-Request-Token",
        "description": "Request-specific credential from the secure link. Grants access only to this request."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Unauthorized",
        "content": {
          "application/json": {
            "examples": {
              "Invalid API Key": {
                "summary": "Invalid API Key",
                "value": {
                  "detail": "Invalid API Key."
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Forbidden",
        "content": {
          "application/json": {
            "examples": {
              "No Permission": {
                "summary": "No Permission",
                "value": {
                  "detail": "You do not have permission to perform this action."
                }
              },
              "Not Enough Credits": {
                "summary": "Not Enough Credits",
                "value": {
                  "error": "You don't have enough credits to perform this request. Please top up at https://business.didit.me"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Not Found",
        "content": {
          "application/json": {
            "examples": {
              "Not Found": {
                "summary": "Not Found",
                "value": {
                  "detail": "Resource not found."
                }
              }
            }
          }
        }
      },
      "PhoneRiskValidationError": {
        "description": "Request validation failed.",
        "content": {
          "application/json": {
            "examples": {
              "Missing phone number": {
                "summary": "Missing phone number",
                "value": {
                  "phone_number": [
                    "This field is required."
                  ]
                }
              },
              "Invalid phone number": {
                "summary": "Invalid phone number",
                "value": {
                  "phone_number": [
                    "Invalid phone number provided."
                  ]
                }
              },
              "Invalid signal IP": {
                "summary": "Invalid signal IP",
                "value": {
                  "signals": {
                    "ip": [
                      "Enter a valid IPv4 or IPv6 address."
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "EmailRiskValidationError": {
        "description": "Request validation failed.",
        "content": {
          "application/json": {
            "examples": {
              "Missing email": {
                "summary": "Missing email",
                "value": {
                  "email": [
                    "This field is required."
                  ]
                }
              },
              "Invalid email": {
                "summary": "Invalid email",
                "value": {
                  "email": [
                    "Enter a valid email address."
                  ]
                }
              },
              "Invalid country hint": {
                "summary": "Invalid country hint",
                "value": {
                  "country_code": [
                    "Ensure this field has no more than 3 characters."
                  ]
                }
              }
            }
          }
        }
      },
      "IPRiskValidationError": {
        "description": "Request validation failed.",
        "content": {
          "application/json": {
            "examples": {
              "Missing IP address": {
                "summary": "Missing IP address",
                "value": {
                  "ip_address": [
                    "This field is required."
                  ]
                }
              },
              "Invalid IP address": {
                "summary": "Invalid IP address",
                "value": {
                  "ip_address": [
                    "Enter a valid IPv4 or IPv6 address."
                  ]
                }
              },
              "Country hint too long": {
                "summary": "Country hint too long",
                "value": {
                  "claimed_country": [
                    "Ensure this field has no more than 3 characters."
                  ]
                }
              }
            }
          }
        }
      },
      "RiskPermissionDenied": {
        "description": "The API key is missing or invalid, or the organization cannot cover the live lookup. This API never returns `401`.",
        "content": {
          "application/json": {
            "examples": {
              "Missing or invalid API key": {
                "summary": "No `x-api-key` header, or the key is invalid or revoked",
                "value": {
                  "detail": "You do not have permission to perform this action."
                }
              },
              "Not enough credits": {
                "summary": "Organization balance cannot cover the lookup price",
                "value": {
                  "error": "You don't have enough credits to perform this request."
                }
              }
            }
          }
        }
      },
      "RateLimitedWrite": {
        "description": "The shared write limit of 300 requests per minute per API key was exceeded. Honor `Retry-After` before retrying.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "detail"
              ],
              "properties": {
                "detail": {
                  "type": "string"
                }
              }
            },
            "example": {
              "detail": "Write request rate limit exceeded. You can make up to 300 requests per minute."
            }
          }
        }
      }
    }
  }
}
