skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
didit-protocol/skills220 installs

didit-verification-management

Full Didit identity verification platform management — account creation, API keys, sessions, bulk imports, workflows, questionnaires, users (KYC), businesses (KYB), transactions, billing, branding, lists (block/allow), and webhooks. Use when someone needs to create a Didit account, get API keys, set up verification workflows, create or retrieve verification sessions, approve or decline sessions, manage users or businesses, monitor transactions, check credit balance, top up credits, configure lists, configure webhooks programmatically, handle webhook signatures, or perform any platform administration. 60+ endpoints across 13 categories.

How do I install this agent skill?

npx skills add https://github.com/didit-protocol/skills --skill didit-verification-management
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The skill provides a comprehensive interface for managing the Didit identity verification platform, including account setup, workflow configuration, and session management. A low-risk vulnerability related to indirect prompt injection is present via the bulk import feature which processes data from external URLs.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

  • Runlayerfail

    3/4 files flagged

What does this agent skill do?

Didit Identity Verification Platform

The single skill for the entire Didit verification platform. Covers account creation, session management, bulk imports, workflow configuration, questionnaires, user (KYC) and business (KYB) management, transaction monitoring, billing, branding customization, lists (block/allow), and webhook configuration — 60+ endpoints across 13 categories.

For standalone verification APIs (ID scan, liveness, face match, AML, etc.), see the individual didit-* skills.

API Reference Links:


Getting Started — Zero to Verifying

Go from nothing to a live verification link in 4 API calls, no browser needed:

import requests

# 1. Register (any email, no business email required)
requests.post("https://apx.didit.me/auth/v2/programmatic/register/",
    json={"email": "you@gmail.com", "password": "MyStr0ng!Pass"})

# 2. Check email for 6-char OTP, then verify → get api_key
resp = requests.post("https://apx.didit.me/auth/v2/programmatic/verify-email/",
    json={"email": "you@gmail.com", "code": "A3K9F2"})
api_key = resp.json()["application"]["api_key"]
headers = {"x-api-key": api_key, "Content-Type": "application/json"}

# 3. Create a KYC workflow — pass an ordered `features` array (not is_*_enabled flags)
wf = requests.post("https://verification.didit.me/v3/workflows/",
    headers=headers,
    json={"workflow_label": "My KYC", "features": [
        {"feature": "OCR"},
        {"feature": "LIVENESS", "config": {"face_liveness_method": "PASSIVE"}},
        {"feature": "FACE_MATCH"},
    ]}).json()

# 4. Create a session → send user to the URL
session = requests.post("https://verification.didit.me/v3/session/",
    headers=headers,
    json={"workflow_id": wf["uuid"], "vendor_data": "user-123"}).json()
print(f"Send user to: {session['url']}")

To add credits: GET /v3/billing/balance/ to check, POST /v3/billing/top-up/ with {"amount_in_dollars": 50} for a Stripe checkout link.


Authentication

Two auth schemes are used across the platform:

EndpointsAuthHeader
Register, Verify Email, LoginNone(unauthenticated)
List Organizations, Get CredentialsBearerAuthorization: Bearer <access_token>
Everything else (sessions, workflows, etc.)API Keyx-api-key: <api_key>

Get your api_key via programmatic registration (above) or from Didit Business Console → API & Webhooks.


Account Setup

Base URL: https://apx.didit.me/auth/v2

1. Register

POST /programmatic/register/
BodyTypeRequiredDescription
emailstringYesAny email address
passwordstringYesMin 8 chars, 1 upper, 1 lower, 1 digit, 1 special

Response (201): {"message": "Registration successful...", "email": "..."}

Rate limit: 5 per IP per hour.

2. Verify Email & Get Credentials

POST /programmatic/verify-email/
BodyTypeRequiredDescription
emailstringYesSame email from register
codestringYes6-character alphanumeric OTP from email

Response (200):

{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "expires_in": 86400,
  "organization": {"uuid": "...", "name": "..."},
  "application": {"uuid": "...", "client_id": "...", "api_key": "YOUR_KEY_HERE"}
}

application.api_key is the x-api-key for all subsequent calls.

3. Login (Existing Accounts)

POST /programmatic/login/
BodyTypeRequiredDescription
emailstringYesAccount email
passwordstringYesAccount password

Response (200): {"access_token": "...", "refresh_token": "...", "expires_in": 86400}

Progressive lockout: 5 fails = 15min, 10 = 1hr, 20 = 24hr.

4. List Organizations

GET /organizations/me/

Auth: Authorization: Bearer <access_token>

Response (200): Array of {"uuid": "...", "name": "...", "contact_email": "..."}

5. Get Application Credentials

GET /organizations/me/{org_id}/applications/{app_id}/

Auth: Authorization: Bearer <access_token>

Response (200): {"uuid": "...", "client_id": "...", "api_key": "..."}


Workflows

Base URL: https://verification.didit.me/v3

Workflows define verification steps, thresholds, and accepted documents. Each has a UUID used as workflow_id when creating sessions. You compose a workflow by listing features in execution order — there is no workflow_type field on the create API (sending one returns 400). KYC vs KYB is determined by which features you include.

Feature values (use the exact uppercase strings in the features array): OCR, NFC, LIVENESS, FACE_MATCH, PROOF_OF_ADDRESS, QUESTIONNAIRE, PHONE_VERIFICATION, EMAIL_VERIFICATION, DATABASE_VALIDATION, AML, IP_ANALYSIS, AGE_ESTIMATION, KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE.

Common compositions:

GoalFeature list (in order)
Full KYC (ID + selfie)OCR, LIVENESS, FACE_MATCH, optionally AML, NFC
Age gatingAGE_ESTIMATION, LIVENESS (add OCR for an ID fallback)
Biometric re-auth (no document)LIVENESS, FACE_MATCH (against a stored portrait)
Proof of addressPROOF_OF_ADDRESS
QuestionnaireQUESTIONNAIRE (set config.questionnaire_uuid)
Email / phone onlyEMAIL_VERIFICATION / PHONE_VERIFICATION
KYB (business)KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE, optionally AML

Ordering rule: put dependency features first — OCR before FACE_MATCH, NFC, DATABASE_VALIDATION, or any AML check that relies on document data.

1. List Workflows

GET /v3/workflows/

Response (200): Array of workflow objects with uuid, workflow_label, workflow_type, is_default, features, total_price.

2. Create Workflow

POST /v3/workflows/

The body is a strict whitelist — only the fields below are accepted, and any unknown key (including workflow_type or flat is_*_enabled flags) is rejected with 400. The only required field is features.

BodyTypeDefaultDescription
featuresarray—Required. Verification features in execution order. Each item: { "feature": "<UPPERCASE>", "config": { ... }, "label": "optional" }.
workflow_labelstringID VerificationDisplay name (max 50 chars) — always set it
is_defaultbooleanfalseSet as default workflow for new sessions
statusstringpublished"published" (default when omitted) or "draft" to save without publishing
is_white_label_enabledbooleanfalseWhite-label the verification UI
is_desktop_allowedboolean—Allow desktop verification
max_retry_attemptsinteger—Max retries per session
retry_window_daysinteger—Days within which retries are allowed
face_liveness_max_attemptsinteger—Max liveness attempts
face_match_max_attemptsinteger—Max face-match attempts
session_expiration_timeinteger—Session lifetime (seconds)

Per-feature config (see the feature configs reference): e.g. LIVENESS → face_liveness_method ("PASSIVE", "ACTIVE_3D", "FLASHING"), face_liveness_score_decline_threshold; FACE_MATCH → face_match_score_decline_threshold, face_match_score_review_threshold; AML → aml_score_approve_threshold (default 80); OCR → duplicated_user_action (no_action/review/decline), documents_allowed (omit or {} to accept all); QUESTIONNAIRE → questionnaire_uuid.

Response (201): Workflow object with uuid.

wf = requests.post("https://verification.didit.me/v3/workflows/",
    headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
    json={"workflow_label": "KYC + AML", "features": [
        {"feature": "OCR"},
        {"feature": "LIVENESS", "config": {"face_liveness_method": "PASSIVE"}},
        {"feature": "FACE_MATCH", "config": {"face_match_score_decline_threshold": 40,
                                             "face_match_score_review_threshold": 60}},
        {"feature": "AML", "config": {"aml_score_approve_threshold": 80}},
    ]}).json()

3. Get Workflow

GET /v3/workflows/{settings_uuid}/

4. Update Workflow

PATCH /v3/workflows/{settings_uuid}/

Partial update — only send fields to change.

5. Delete Workflow

DELETE /v3/workflows/{settings_uuid}/

Response: 204 No Content. Existing sessions are not affected.


Sessions

Base URL: https://verification.didit.me/v3

Sessions are the core unit of verification. Every verification starts by creating a session linked to a workflow.

Lifecycle: Create → User verifies at URL → Webhook/poll decision → Optionally update status

Statuses: Not Started, In Progress, In Review, Approved, Declined, Expired, Abandoned, Kyc Expired, Resubmitted, Awaiting User (there is no Pending status)

Rate limits: generic GET and session creation 600/min; writes 300/min; decision polling 100/min; PDF generation 50/min.

1. Create Session

POST /v3/session/
BodyTypeRequiredDescription
workflow_iduuidYesWorkflow UUID
vendor_datastringNoYour user identifier
callbackurlNoRedirect URL (Didit appends verificationSessionId + status)
callback_methodstringNo"initiator", "completer", or "both"
metadataJSON stringNoCustom data stored with session
languagestringNoISO 639-1 UI language
contact_details.emailstringNoPre-fill email for email verification step
contact_details.phonestringNoPre-fill phone (E.164) for phone verification step
contact_details.send_notification_emailsbooleanNoSend status update emails to user
contact_details.email_langstringNoLanguage for email notifications (ISO 639-1)
expected_details.first_namestringNoTriggers mismatch warning if different (fuzzy match)
expected_details.last_namestringNoExpected last name (fuzzy match)
expected_details.date_of_birthstringNoYYYY-MM-DD
expected_details.genderstringNo"M", "F", or null
expected_details.nationalitystringNoISO 3166-1 alpha-3 country code
expected_details.id_countrystringNoISO alpha-3 for expected ID document country (overrides nationality)
expected_details.poa_countrystringNoISO alpha-3 for expected PoA document country
expected_details.addressstringNoExpected address (human-readable, for PoA matching)
expected_details.identification_numberstringNoExpected document/personal/tax number
expected_details.ip_addressstringNoExpected IP address (logs warning if different)
portrait_imagebase64NoReference portrait for Biometric Auth (max 1MB)

Response (201):

{
  "session_id": "...",
  "session_number": 1234,
  "session_token": "abcdef123456",
  "url": "https://verify.didit.me/session/abcdef123456",
  "status": "Not Started",
  "workflow_id": "..."
}

Send the user to url to complete verification.

2. Retrieve Session (Get Decision)

GET /v3/session/{sessionId}/decision/

Returns all verification results. Presigned image URLs expire after 4 hours.

Response (200): Full decision with status, features, id_verifications, liveness_checks, face_matches, aml_screenings, phone_verifications, email_verifications, poa_verifications, database_validations, ip_analyses, reviews.

3. List Sessions

GET /v3/sessions/
QueryTypeDefaultDescription
vendor_datastring—Filter by your user identifier
statusstring—Filter by status (e.g. Approved, Declined, In Review)
session_kindstring—user (KYC), business (KYB), or all
countrystring—Filter by ISO 3166-1 alpha-3 country code
workflow_idstring—Filter by workflow UUID
searchstring—Free-text search
date_from / date_tostring—ISO date range bounds
offsetinteger0Number of items to skip
limitinteger50Max items to return

Response (200): Paginated list with count, next, previous, results[].

4. Delete Session

DELETE /v3/session/{sessionId}/delete/

Response: 204 No Content. Permanently deletes all associated data.

5. Batch Delete Sessions

POST /v3/sessions/delete/
BodyTypeDescription
session_numbersarrayList of session numbers to delete
delete_allbooleanDelete all sessions (use with caution)

6. Update Session Status

PATCH /v3/session/{sessionId}/update-status/
BodyTypeRequiredDescription
new_statusstringYes"Approved", "Declined", or "Resubmitted"
commentstringNoReason for change
send_emailbooleanNoSend notification email
email_addressstringConditionalRequired when send_email is true
email_languagestringNoEmail language (default: "en")
nodes_to_resubmitarrayNoFor Resubmitted: [{"node_id": "feature_ocr", "feature": "OCR"}]

Resubmit requires session to be Declined, In Review, or Abandoned.

Reviewer data overrides — correct extracted data on a session (only send fields to change):

  • PATCH /v3/session/{sessionId}/update-data/ — KYC/ID fields (document_type, document_number, date_of_birth, first_name, last_name, gender M/F/U, address, nationality, extra_fields, …).
  • PATCH /v3/session/{sessionId}/update-poa-data/ — Proof of Address fields (document_type, issuer, issue_date, poa_address, name_on_document, …).

7. Generate PDF Report

GET /v3/session/{sessionId}/generate-pdf

Rate limit: 50 req/min.

8. Share Session

POST /v3/session/{sessionId}/share/

Generates a share_token for B2B KYC sharing. Only works for finished sessions.

9. Import Shared Session

POST /v3/session/import-shared/
BodyTypeRequiredDescription
share_tokenstringYesToken from sharing partner
trust_reviewbooleanYestrue: keep original status; false: set to "In Review"
workflow_idstringYesYour workflow ID
vendor_datastringNoYour user identifier

A session can only be imported once per partner application.

10. List Session Reviews

GET /v3/sessions/{session_id}/reviews/

Response (200): Array of review activity items:

[
  {
    "id": 1,
    "action": "status_change",
    "old_status": "In Review",
    "new_status": "Approved",
    "note": "Document verified manually",
    "created_at": "2025-06-01T15:00:00Z"
  }
]

11. Create Session Review

POST /v3/sessions/{session_id}/reviews/
BodyTypeRequiredDescription
new_statusstringYes"Approved", "Declined", or "In Review"
commentstringNoReview note

Response (201): The created review item.


Bulk Import (Migration)

Import historical verifications in bulk — e.g. migrating from another provider — from a hosted CSV or NDJSON file. All imports use Didit's canonical schema regardless of source.

POST /v3/session/imports/
BodyTypeRequiredDescription
source_file_urlstringYes*Publicly fetchable URL of the file (JSON body). *The multipart variant accepts a file upload instead.
import_typestringNouser_verification (default), business_verification, status_rules, or transactions
source_formatstringNocsv (default) or ndjson
workflow_idstringNoWorkflow to associate imported sessions with

There is no provider request field — all imports use Didit's canonical schema. To label where a record came from, include the optional per-row provider column in the file itself (defaults to generic, stored as metadata.imported_from).

Track and inspect jobs:

GET /v3/session/imports/template/            # canonical column template
GET /v3/session/imports/{importId}/          # job status + summary
GET /v3/session/imports/{importId}/errors/   # per-row errors

Lists (Block / Allow / Custom)

Lists drive automatic enforcement: a blocklist match auto-declines future sessions, an allowlist match fast-tracks/suppresses duplicate actions, and custom lists feed workflow conditions and monitoring rules.

  • list_type: blocklist (system, auto-provisioned per entry type, immutable — you can't create or delete these) · allowlist · custom
  • entry_type: face, document, phone, email, ip_address, device_fingerprint, wallet_address, bank_account, user, business, country, key

1. List Lists

GET /v3/lists/

Filters: list_type, entry_type, limit, offset.

2. Create List

POST /v3/lists/
BodyTypeRequiredDescription
namestringYesUnique per application
list_typestringYesallowlist or custom (blocklists are auto-provisioned)
entry_typestringYesOne of the entry types above
descriptionstringNoOptional description

3. Get / Update / Delete List

GET    /v3/lists/{list_uuid}/
PATCH  /v3/lists/{list_uuid}/          # body: name, description (system blocklists are immutable)
DELETE /v3/lists/{list_uuid}/          # allowlist/custom only

4. Add an Entry

POST /v3/lists/{list_uuid}/entries/
BodyTypeRequiredDescription
valuestringConditionalThe value to add (phone, email, IP, etc.). Required unless reference_session_id is given.
reference_session_iduuidConditionalAuto-extracts the value from a session based on the list's entry_type (face, document, phone, email, ip_address, device_fingerprint) and marks the underlying model blocklisted.
reference_object_uuiduuidNoSource entity (transaction / vendor user / business) for traceability
display_labelstringNoHuman-readable label
commentstringNoReason / note
metadataobjectNoe.g. { "reference_type": "vendor_user" }

Blocklist a session's face + document: add one entry to the face blocklist and one to the document blocklist, each with reference_session_id. On future matches Didit raises FACE_IN_BLOCKLIST / ID_DOCUMENT_IN_BLOCKLIST / PHONE_NUMBER_IN_BLOCKLIST / EMAIL_IN_BLOCKLIST and auto-declines.

5. Upload a Face Entry (no session)

POST /v3/lists/{list_uuid}/entries/face-upload/

For face lists when you have an image but no session. Body: image (base64 JPG/PNG/WebP, no data: prefix), optional comment. Requires a face-type list; returns 400 if no/multiple faces are detected.

6. List / Delete Entries

GET    /v3/lists/{list_uuid}/entries/        # query: search, limit, offset
DELETE /v3/lists/{list_uuid}/entries/{entry_uuid}/   # also unblocks the underlying user/business

Questionnaires

Custom forms attached to verification workflows. Support 7 element types: short_text, long_text, multiple_choice, checkbox, file_upload, date, number.

1. List Questionnaires

GET /v3/questionnaires/

2. Create Questionnaire

POST /v3/questionnaires/
BodyTypeRequiredDescription
titlestringYesDisplay title
descriptionstringNoDescription shown to users
default_languagestringNoDefault language code
languagesarrayNoSupported languages
form_elementsarrayYesQuestion objects

Form element:

FieldTypeRequiredDescription
element_typestringYesOne of the 7 types above
labelobjectYesTranslations: {"en": "Question?", "es": "¿Pregunta?"}
is_requiredbooleanNoMandatory answer
optionsarrayConditionalRequired for multiple_choice/checkbox
requests.post("https://verification.didit.me/v3/questionnaires/",
    headers=headers,
    json={
        "title": "Employment Details",
        "default_language": "en",
        "form_elements": [
            {"element_type": "short_text",
             "label": {"en": "Occupation?"}, "is_required": True},
            {"element_type": "multiple_choice",
             "label": {"en": "Employment status"},
             "options": [{"label": {"en": "Employed"}}, {"label": {"en": "Student"}}]},
        ]
    })

3. Get Questionnaire

GET /v3/questionnaires/{questionnaire_uuid}/

4. Update Questionnaire

PATCH /v3/questionnaires/{questionnaire_uuid}/

5. Delete Questionnaire

DELETE /v3/questionnaires/{questionnaire_uuid}/

Response: 204 No Content.


Users (KYC)

Manage verified individuals identified by vendor_data. A user's status is a monitoring status — ACTIVE, FLAGGED, or BLOCKED (not a verification decision).

1. List Users

GET /v3/users/
QueryTypeDescription
limitintegerResults per page
offsetintegerPagination offset

Response (200): Paginated list with vendor_data, full_name, status, session_count, issuing_states, approved_emails, approved_phones.

2. Create User

POST /v3/users/create/
BodyTypeRequiredDescription
vendor_datastringYesYour unique identifier
full_namestringNo
display_namestringNo
date_of_birthstringNoYYYY-MM-DD
statusstringNoACTIVE, FLAGGED, or BLOCKED
metadataobjectNoCustom JSON
approved_emailsarrayNoAllowlisted emails
approved_phonesarrayNoAllowlisted phones
issuing_statesarrayNoAllowed issuing states

3. Get User

GET /v3/users/{vendor_data}/

4. Update User

PATCH /v3/users/{vendor_data}/

Send only the fields to change: full_name, display_name, date_of_birth, status (ACTIVE/FLAGGED/BLOCKED), metadata, approved_emails, approved_phones, issuing_states.

5. Update User Status

PATCH /v3/users/{vendor_data}/update-status/
BodyTypeRequiredDescription
statusstringYesACTIVE, FLAGGED, or BLOCKED

6. Batch Delete Users

POST /v3/users/delete/
BodyTypeDescription
vendor_data_listarrayList of vendor_data strings
delete_allbooleanDelete all users

Businesses (KYB)

Manage verified businesses identified by vendor_data. Same ACTIVE/FLAGGED/BLOCKED monitoring status as users.

GET    /v3/businesses/                          # list (limit, offset)
POST   /v3/businesses/create/                   # vendor_data, display_name, legal_name, registration_number, country_code (ISO alpha-2), status, metadata
GET    /v3/businesses/{vendor_data}/            # get
PATCH  /v3/businesses/{vendor_data}/            # update (same fields as create)
PATCH  /v3/businesses/{vendor_data}/update-status/   # body: status (ACTIVE|FLAGGED|BLOCKED)
POST   /v3/businesses/delete/                   # vendor_data_list[], didit_internal_id_list[], delete_all

Standalone KYB registry lookup (no session): POST /v3/kyb/search/ with country_code (required) + name/registration_number returns candidates; pass a candidate's kyb_response_id to POST /v3/kyb/select/ to pull the full company record.


Transactions (AML monitoring)

Submit transactions for rule evaluation and ongoing monitoring.

GET   /v3/transactions/                  # list (limit, offset)
POST  /v3/transactions/                  # create
GET   /v3/transactions/{transaction_id}/ # get + rule-evaluation result

Create body — required: transaction_id, transaction_category (finance, kyc, travel_rule, user_event, audit_trail_event, gambling_bet, gambling_limit_change, gambling_bonus_change), transaction_details (object), subject (object). Optional: counterparty, transaction_at, time_zone, custom_properties (referenced in rules as custom_values.<key>), travel_rule_details, network_snapshot, include_crypto_screening.


Billing

1. Get Credit Balance

GET /v3/billing/balance/

Response (200):

{
  "balance": "142.5000",
  "auto_refill_enabled": true,
  "auto_refill_amount": "100.0000",
  "auto_refill_threshold": "10.0000"
}

2. Top Up Credits

POST /v3/billing/top-up/
BodyTypeRequiredDescription
amount_in_dollarsnumberYesMinimum $50
success_urlstringNoRedirect after payment
cancel_urlstringNoRedirect on cancel

Response (200):

{
  "checkout_session_id": "cs_live_...",
  "checkout_session_url": "https://checkout.stripe.com/..."
}

Present checkout_session_url to the user for payment.


Customization (Branding)

Brand the hosted verification UI with your own logos.

GET   /v3/customization/      # current branding
PATCH /v3/customization/      # multipart/form-data

Update fields (image files, multipart/form-data): image_square, image_rectangular, image_favicon. Send only the images you want to change.


Webhook Destinations

Configure webhooks programmatically — no console needed. You can register multiple destinations, each with its own URL, payload version, enabled flag, subscribed events, and signing secret.

1. List Destinations

GET /v3/webhook/destinations/

Response (200): Array of destinations, each with uuid, label, url, enabled, webhook_version, subscribed_events, and the signing secret.

2. Create Destination

POST /v3/webhook/destinations/
BodyTypeRequiredDescription
labelstringYesHuman-readable name
urlstringYesHTTPS endpoint to receive events
enabledbooleanNoWhether the destination receives events (default true)
webhook_versionstringNo"v1", "v2", or "v3" (v3 recommended)
subscribed_eventsarrayNoEvent types to deliver (omit to receive all)

Response (201): the created destination, including the secret used to verify the X-Signature header. Store it securely.

dest = requests.post(
    "https://verification.didit.me/v3/webhook/destinations/",
    headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
    json={"label": "Prod", "url": "https://myapp.com/webhooks/didit",
          "webhook_version": "v3", "subscribed_events": ["status.updated", "data.updated"]},
).json()
secret = dest["secret"]

3. Get / Update / Delete Destination

GET    /v3/webhook/destinations/{destination_uuid}/   # includes the signing secret
PATCH  /v3/webhook/destinations/{destination_uuid}/   # label, url, enabled, webhook_version, subscribed_events
DELETE /v3/webhook/destinations/{destination_uuid}/   # stop delivering to this endpoint

Example — disable a destination without deleting it:

requests.patch(
    f"https://verification.didit.me/v3/webhook/destinations/{dest['uuid']}/",
    headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
    json={"enabled": False},
)

Webhook Events & Signatures

Didit sends POST requests to your webhook URL when session status changes. Retries up to 2 times with exponential backoff (1 min, 4 min).

Payload

{
  "session_id": "...",
  "status": "Approved",
  "webhook_type": "status.updated",
  "vendor_data": "user-123",
  "timestamp": 1627680000,
  "decision": { ... }
}

Event types: status.updated (session status change), data.updated (KYC/POA data manually updated), user.created, user.updated, business.created, business.updated, transaction.created, transaction.updated. Subscribe a destination to specific events via subscribed_events, or omit it to receive all.

Idempotency: dedupe on session_id + status + webhook_type (not timestamp). The event_id is stable across retries.

Signature Verification (recommended)

Two headers: X-Signature (HMAC-SHA256 hex) and X-Timestamp (Unix seconds). The canonical string is the JSON body with floats shortened, keys sorted, compact separators, and ensure_ascii=False; the signed message is {timestamp}:{canonical}.

import hashlib, hmac, time, json

def verify_webhook_v2(body_dict: dict, signature: str, timestamp: str, secret: str) -> bool:
    if abs(time.time() - int(timestamp)) > 300:
        return False
    def process_value(v):
        if isinstance(v, float) and v == int(v):
            return int(v)
        if isinstance(v, dict):
            return {k: process_value(val) for k, val in v.items()}
        if isinstance(v, list):
            return [process_value(i) for i in v]
        return v
    canonical = json.dumps(process_value(body_dict), sort_keys=True, ensure_ascii=False, separators=(",", ":"))
    message = f"{timestamp}:{canonical}"
    expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Simple Signature (Fallback)

Header: X-Signature-Simple — HMAC of key fields only.

def verify_webhook_simple(session_id, status, webhook_type, timestamp, signature, secret):
    message = f"{timestamp}:{session_id}:{status}:{webhook_type}"
    expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature, expected)

Error Responses (All Endpoints)

CodeMeaningAction
400Invalid requestCheck required fields and formats
401Invalid or missing API keyVerify x-api-key header
403Insufficient credits or no permissionCheck balance, API key permissions
404Resource not foundVerify IDs
429Rate limitedCheck Retry-After header, exponential backoff

Common Workflows

Full KYC Onboarding

1. POST /programmatic/register/          → register
2. POST /programmatic/verify-email/      → get api_key
3. POST /v3/workflows/                    → create KYC workflow (features array)
4. POST /v3/webhook/destinations/         → register webhook URL + version "v3"
5. POST /v3/session/                      → create session → get URL
6. User completes verification at URL
7. Webhook fires → GET /v3/session/{id}/decision/ → read results

Programmatic Review + Blocklist

1. Webhook: status "In Review"
2. GET /v3/session/{id}/decision/   → inspect results
3. If fraud: PATCH update-status → Declined, then
   POST /v3/lists/{blocklist_uuid}/entries/ with reference_session_id
   If legit: PATCH update-status → Approved

B2B KYC Sharing

Service A: POST /v3/session/{id}/share/       → get share_token
Service B: POST /v3/session/import-shared/    → import with trust_review=true

Check Balance Before Sessions

1. GET /v3/billing/balance/    → check if balance > 0
2. If low: POST /v3/billing/top-up/ → get Stripe checkout URL
3. POST /v3/session/           → create session

Questionnaire + Workflow

1. POST /v3/questionnaires/  → create form → save uuid
2. POST /v3/workflows/       → questionnaire_verification type
3. POST /v3/session/         → session with workflow_id

Utility Scripts

setup_account.py — Register and verify accounts

pip install requests
python scripts/setup_account.py register you@gmail.com 'MyStr0ng!Pass'
# (check email for code)
python scripts/setup_account.py verify you@gmail.com A3K9F2
# Prints api_key, org_uuid, app_uuid
python scripts/setup_account.py login you@gmail.com 'MyStr0ng!Pass'

manage_workflows.py — CRUD workflows

export DIDIT_API_KEY="your_key"
python scripts/manage_workflows.py list
python scripts/manage_workflows.py create --label "My KYC" --liveness --face-match
python scripts/manage_workflows.py get <uuid>
python scripts/manage_workflows.py update <uuid> --label "Renamed KYC"
python scripts/manage_workflows.py delete <uuid>

create_session.py — Create verification sessions

export DIDIT_API_KEY="your_key"
python scripts/create_session.py --workflow-id <uuid> --vendor-data user-123
python scripts/create_session.py --workflow-id <uuid> --vendor-data user-123 --callback https://myapp.com/done

All scripts can be imported as libraries:

from scripts.setup_account import register, verify_email, login
from scripts.manage_workflows import list_workflows, create_workflow
from scripts.create_session import create_session

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/didit-protocol/skills/didit-verification-management">View didit-verification-management on skillZs</a>