Overview

PayCA dispatches a webhook every time a cardholder's status changes, so your system can react in real time without polling the API.


Registering a webhook

curl -s -X POST "$PAYCA_BASE_URL/v1/webhooks" \
  -H 'Content-Type: application/json' \
  -H "x-client-id: $PAYCA_CLIENT_ID" \
  -H "x-client-secret: $PAYCA_CLIENT_SECRET" \
  -d '{
    "url": "https://your-domain.com/webhooks/cardholder",
    "type": "cardholder"
  }'
  • url — HTTPS endpoint on your side that will receive the webhooks.
  • type — webhook category. Use "cardholder" for cardholder events.

Payload

Every status change triggers a POST to your URL with the following JSON body:

{
  "cardholderId": "1ff17026-f9d7-4870-8d48-daee288edd0a",
  "status": "pass_audit",
  "previousStatus": "under_review",
  "description": "",
  "timestamp": "2026-03-25T12:45:00Z"
}

Fields

Field Type Description
cardholderId string (UUID) Cardholder identifier.
status string New cardholder status.
previousStatus string Previous cardholder status.
description string Rejection reason (set on rejected_by_admin and reject).
timestamp string (ISO 8601) Time of the status change.

Statuses

A cardholder can be in any of the following states:

Status Meaning
pending_review Created, waiting for the first PayCA admin review.
rejected_by_admin Rejected by a PayCA admin (see description).
wait_audit Submitted to the provider; waiting for a provider response.
under_review Provider has started its review.
pending_approval Provider approved; waiting for a second confirmation by a PayCA admin.
pass_audit Fully approved — ready for card issuance.
reject Rejected by the provider (see description and statusFlowLocation).
submission_failed Could not be sent to the provider (e.g. API error). An admin can retry.

Transitions and webhooks

A cardholder is created in pending_review (no webhook). Subsequent transitions emit a webhook to your URL.

pending_review ─┬─→ rejected_by_admin
                └─→ (admin approval — submit to provider)
                       │
                       ├─→ wait_audit / under_review
                       │      │
                       │      ├─→ pending_approval ─┬─→ pass_audit
                       │      │                     ├─→ rejected_by_admin
                       │      │                     └─→ reject
                       │      └─→ reject
                       │
                       └─→ submission_failed
                              │
                              └─[retry]─→ wait_audit → ...
Transition When it fires
pending_reviewrejected_by_admin A PayCA admin rejected the cardholder.
pending_reviewwait_audit / under_review / pending_approval Admin approved and we submitted to the provider; the resulting status depends on the provider's response.
pending_reviewsubmission_failed Submission to the provider failed; reason is in description.
wait_auditunder_review The provider started a manual review.
wait_audit / under_reviewpending_approval The provider approved; awaiting the second PayCA confirmation.
wait_audit / under_reviewreject The provider rejected (reason in description).
pending_approvalpass_audit A PayCA admin gave the final approval — ready for card issuance.
pending_approvalrejected_by_admin A PayCA admin declined at the final step.
submission_failedwait_audit An admin retried the submission.

previousStatus always reflects the state immediately before this webhook. Branch on the (status, previousStatus) pair rather than assume a fixed sequence — the path may vary by provider.


Webhook examples

PayCA admin approved

{
  "cardholderId": "1ff17026-f9d7-4870-8d48-daee288edd0a",
  "status": "wait_audit",
  "previousStatus": "pending_review",
  "description": "",
  "timestamp": "2026-03-25T10:35:00Z"
}

Provider audit passed

{
  "cardholderId": "1ff17026-f9d7-4870-8d48-daee288edd0a",
  "status": "pass_audit",
  "previousStatus": "under_review",
  "description": "",
  "timestamp": "2026-03-25T12:45:00Z"
}

Action: the cardholder is approved — issue a card via POST /v1/cards.

Provider rejected

{
  "cardholderId": "1ff17026-f9d7-4870-8d48-daee288edd0a",
  "status": "reject",
  "previousStatus": "under_review",
  "description": "Document verification failed: ID photo is unclear",
  "timestamp": "2026-03-25T14:00:00Z"
}

PayCA admin rejected

{
  "cardholderId": "1ff17026-f9d7-4870-8d48-daee288edd0a",
  "status": "rejected_by_admin",
  "previousStatus": "pending_review",
  "description": "Incomplete personal data",
  "timestamp": "2026-03-25T11:00:00Z"
}

Handling guidance

  1. Reply with HTTP 200 — PayCA expects a success response. Failures trigger redelivery.
  2. Be idempotent — the same webhook may be redelivered. Deduplicate on cardholderId + status + timestamp.
  3. React to pass_audit — it signals that you can now issue a card for this cardholder.
  4. Log reject and rejected_by_admindescription carries the rejection reason you can surface to the end user.

Authentication

Every API request requires two headers:

x-client-id: <your-client-id>
x-client-secret: <your-client-secret>

Base URL: https://api.actisas.ee