Verifications
A verification is a record of a check Kontorion ran (or had a third-party run) against a customer - a VIES VAT lookup, a KYC document review, a payment-instrument ownership confirmation. Verifications are first-class objects with their own typed status so downstream features (reverse-charge eligibility, promotion conditions, payment-method gating) can read directly from them.
Anatomy
| Field | Notes |
|---|---|
customer_id | The customer this verification belongs to |
provider | Free-form string identifying the external system that ran the check (vies, stripe_identity, manual, etc.). Provider-specific |
verification_type | Free-form string for the kind of check (eu_vat, business_registration, identity_document, bank_account_ownership, …). Provider-defined; treat unknown values as opaque |
status | One of pending / verified / expired / failed |
verified_at | When the most recent passing check completed |
expires_at | When the verification's verified window ends (provider-set or org-policy) |
provider_reference | Provider's own ID for the underlying check (the VIES query record, the Stripe Verification Session ID, etc.) - useful for follow-up calls and audit |
last_checked_at | When the engine last polled / re-ran the check |
Both provider and verification_type are free-form strings, not closed enums - Kontorion doesn't try to be the source of truth for which providers and check types exist. Define the values that match the providers you've wired up.
Status lifecycle
Code
| Status | Meaning |
|---|---|
pending | The check has been started but the result hasn't come back yet - typical for async providers (VIES, KYC) |
verified | The provider returned a passing result. verified_at is set; expires_at may be set if the provider declared one |
expired | A previously-verified check passed its expires_at. The customer needs re-verification before the verified state unlocks again |
failed | The provider returned a definitive negative |
Allowed transitions:
| From | To |
|---|---|
pending | verified, failed |
verified | expired, failed |
expired | pending (kick off re-verification) |
failed | pending (retry) |
The transition rules are enforced - invalid transitions return 409 INVALID_TRANSITION.
Verifications don't currently emit dedicated webhook events. To react to a status change, poll the verification or watch the consuming feature's events (e.g. an
eu_vatgoingexpiredwill surface as a tax-treatment change on the next invoice).
What verifications gate
Other features read verification status; nothing in the verifications surface itself enforces gating. Common consumers:
| Consumer | Reads |
|---|---|
| Tax engine | An eu_vat verification at status verified is the precondition for intra-EU B2B reverse-charge treatment. expired or failed falls back to the consumer (B2C) path |
| Promotions | The external_verification condition matches against the named verification type + status |
| Your application | Read GET /v1/verifications?customer_id=... and gate plan tiers, payment-method activation, etc. however your business rules dictate |
Creating
Code
The request body is intentionally small - no provider-specific input fields. The provider knows where to find what it needs (e.g. the VIES provider reads the customer's tax_identifiers["eu_vat"]). The response carries the verification ID and initial status (pending for async providers, the final state for synchronous ones).
For the EU VAT case specifically, you can also kick off a check via POST /v1/customers/{id}/validate-vat - it's a thin wrapper that creates an eu_vat verification using the customer's primary VAT ID.
Updating status
For external type and manual reviews, your application or the dashboard reports the outcome via PUT (not POST) on the status endpoint:
Code
The transition rules above apply - the engine refuses to set, e.g., verified → pending directly.
For provider-driven status updates, the integrating service (the VIES poller, the KYC webhook handler) owns the lifecycle - you don't manually flip status when a provider's automated check completes.
Endpoints
All Verifications endpoints - GET /verifications (cursor-paginated, supports ?customer_id= filter), GET /verifications/{id}, POST /verifications, PUT /verifications/{id}/status.
Related
- Customers - owns the verifications and the
tax_identifiersproviders read from - Taxes - reverse-charge gating against
eu_vatstatus - Promotions - the
external_verificationcondition type - Payments - payment-method activation typically reads the relevant ownership / KYC verification