Payment passes (Passes)
Using the payment pass system for guaranteed payment routing and fee management in Syncra V2
Payment passes (Passes)
The payment passes (Passes) mechanism is an advanced Syncra V2 feature that lets merchants reserve specific payment details (cards, SBP phone numbers, IBANs for international transfers) for particular payers for a defined period.
This guarantees that payments from VIP clients go through, optimizes routing, and protects the payment details from overload (Anti-Spam). A pass bypasses the standard cascade routing — a deal with a matching pass is pinned to a specific provider.
Creating a pass
POST /api/v1/p2p/merchant/passesRequest parameters (JSON Body)
| Field | Type | Required | Description |
|---|---|---|---|
amount | int64 | Yes | The reservation amount in the currency's minor units (the only required field). |
currency_id | string(UUID) | No | Currency UUID; empty = any currency. |
payment_method_id | string(UUID) | No | A specific payment method UUID; empty = any method. UUID only — a slug does not resolve on the pass branch (unlike PayIn/PayOut deals). |
requisite_type | string | No | Payment details type: BANK_CARD, SBP, E_WALLET, SIM, or BANK_TRANSFER (IBAN, for international markets — Havale/SEPA/...); empty = any type. The full reference is in Requisite types. |
expires_at | string(RFC3339) | No | Pass expiration time. Optional: an empty or missing value means the pass never expires (expires_at = NULL). |
provider_id | string(UUID) | No | A specific provider UUID (when pinning is required). |
Request example (with expiration)
{
"amount": 1000000,
"currency_id": "4ac148fe-19a3-45bb-b992-019fac55b72c",
"requisite_type": "BANK_CARD",
"expires_at": "2026-07-12T18:30:00Z"
}Request example (no expiration)
{
"amount": 1000000,
"currency_id": "4ac148fe-19a3-45bb-b992-019fac55b72c",
"requisite_type": "BANK_CARD"
}If expires_at is omitted or empty, the pass is valid indefinitely
(NULL in the database). This is useful for permanent VIP routes. To
limit the validity period, pass an RFC3339 timestamp.
Response example (200 OK)
{
"pass": {
"pass_id": "812d77a0-0d3a-4422-b91c-7cb052a21abc",
"status": "ACTIVE",
"amount": "1000000",
"currency_id": "4ac148fe-19a3-45bb-b992-019fac55b72c",
"payment_method_id": "",
"requisite_type": "BANK_CARD",
"expires_at": "2026-07-12T18:30:00Z"
}
}Pass statuses
A pass goes through a two-phase commit that prevents pass loss when a
deal expires. There are 4 canonical states (the domain enum PassStatus):
| Status | Description | Transition |
|---|---|---|
ACTIVE | The pass is created, the payment details are reserved, and it awaits matching with a deal. | → RESERVED (a deal claimed the pass) or → EXPIRED (the TTL ran out). |
RESERVED | A deal claimed this pass but has not finished yet. No other deal can match an ACTIVE pass while it is RESERVED. | → USED (the deal completed successfully) or → ACTIVE (the deal expired or was canceled — the pass returns to the pool via ReleasePass). |
USED | The deal that claimed the pass completed successfully. A terminal state — the pass cannot be reused. | Terminal. |
EXPIRED | The pass TTL ran out before it was consumed. A terminal state — checked by the expires_at guard condition in the MatchActivePass request. | Terminal. |
Transition diagram
┌─────────┐ MatchAndReserve ┌───────────┐
│ ACTIVE │ ─────────────────► │ RESERVED │
└─────────┘ └───────────┘
│ │ │
TTL │ ConfirmPass (deal done) │ │ ReleasePass
exceeded │ ▼ │ (deal expired/canceled)
│ ┌─────────┐│
▼ │ USED ││
┌─────────┐ └─────────┘│
│ EXPIRED │ ▼
└─────────┘ (back to ACTIVE)Two-phase commit (loss protection)
MatchAndReserve—ACTIVE → RESERVEDwhen a deal is created.ConfirmPass—RESERVED → USEDwhen the deal completes successfully.ReleasePass—RESERVED → ACTIVEwhen the deal expires or is canceled (viaPaymentTimeoutWorker).
If the deal holding a pass (RESERVED) expires or is canceled, the pass
is not lost — it returns to the pool (ACTIVE) and becomes available
for matching again. This guarantees that VIP payment details never get
stuck on failed deals.
Competitive reservation
If two deals try to reserve the same pass at the same time, the first transaction wins and the second one gets an error (RFC 9457 problem+json):
HTTP/1.1 409 Conflict
{
"type": "about:blank",
"title": "Conflict",
"status": 409,
"detail": "{\"code\":10,\"message\":\"pass was concurrently reserved\",\"details\":[]}",
"instance": "/api/v1/p2p-engine"
}This conflict is retry-safe: repeat the request with the same
idempotency_key after a short pause (200–500 ms). See the
Retry matrix.
Related materials
- Error codes —
ABORTED,RESOURCE_EXHAUSTED, and retry strategies. - Deals — deal matching with passes.
- Status mapping reference — requisite types and deal statuses.