Compliance - Adapters

Location: api/nextango/apps/compliance/services/kyc/ Last Updated: 2026-07-06

Overview

KYC vendor adapters translate between the platform's credential model and third-party identity verification services. Each vendor gets its own adapter file. Adding a vendor requires no changes to the base contract or to existing adapters. The platform ships with a Persona adapter; additional vendors slot in as sibling files.

Every adapter speaks the same two-method contract and returns the same VerificationResult dataclass, so the webhook view, onboarding service, and credential state machine do not depend on any vendor-specific logic.


KYCVendorAdapter (base)

Abstract base in compliance/services/kyc/base.py. Concrete adapters implement both methods.

initiate_verification(user, credential_key) → str

Starts a verification session for a credential. Returns a URL the storefront or POS redirects the customer to. The adapter passes credential_key to the vendor as whatever field the vendor uses to echo back identifiers on webhooks (Persona: reference-id).

handle_webhook(payload) → VerificationResult

Parses an inbound vendor webhook body into a normalised outcome. Adapters never mutate credentials directly; they return a VerificationResult and leave state transitions to the webhook view.


VerificationResult

Dataclass returned by every handle_webhook call.

FieldTypePurpose
credential_keystrThe _key of the credential this event refers to. Empty string means the webhook could not be tied to a credential.
outcomestrTri-state: 'approved', 'rejected', or 'unresolved'.
rawAnyThe original payload, preserved for audit storage and debugging.
vendor_reference_idstrVendor's own identifier for the event (e.g. Persona inquiry id), stored on the credential's verificationData.vendorReferenceId for reconciliation.

Outcome semantics:

  • approved, terminal success; the webhook view transitions the credential to active.
  • rejected, terminal failure; the webhook view transitions the credential to rejected and records a rejectionReason.
  • unresolved, non-terminal or unknown status (e.g. inquiry still in progress). The webhook view acks the event with 200 OK but does not mutate the credential.

PersonaAdapter

Persona uses inquiry-based verification. When a customer starts KYC, the adapter creates an inquiry and passes the credential _key as the reference-id. Persona echoes reference-id back on every webhook, which is how the webhook view resolves the credential.

Reference: Persona: Create an Inquiry.

Settings

SettingPurpose
PERSONA_API_KEYBearer token for the Persona REST API
PERSONA_TEMPLATE_IDInquiry template id used for storefront KYC
PERSONA_WEBHOOK_SECRETHMAC secret for signature verification in the webhook view

initiate_verification(user, credential_key)

POST https://withpersona.com/api/v1/inquiries with:

  • data.attributes.inquiry-template-id = PERSONA_TEMPLATE_ID
  • data.attributes.reference-id = credential_key
  • data.attributes.fields.email-address.value = user.email

On success returns attributes.hosted-session-token-url (or session-token as fallback). On non-2xx raises RuntimeError including the HTTP status and response body.

handle_webhook(payload)

Extracts data.attributes.reference-id and data.attributes.status. Outcome is derived from the status string:

Persona statusOutcome
approved, completedapproved
failed, declined, expiredrejected
anything elseunresolved

Returns a VerificationResult populated with credential_key=reference-id, the resolved outcome, the raw payload, and vendor_reference_id=data.id.


Was this page helpful?