API contract for external payment integrations.
Third-party integrators implement this API as a standalone REST service. LoyaltyPlant (payments-service) calls these endpoints to delegate payment operations to your integration; your service in turn talks to your PSP (payment service provider). You never call payments-service to run a payment — payments-service drives the flow by calling you.
Settle (capture) funds previously held by /v1/authorize. Requires the
CAPTURE capability. transactionReference is the value you returned
from authorize. amount is optional — omit it to capture the full
authorized amount, or pass a smaller value for a partial capture.
Idempotent on Idempotency-Key.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| Idempotency-Key required | string <uuid> UUID for idempotent request handling, unique per logical operation. Carried by all mutating operations (authorize, sale, capture, refund, reverse); the read-only operations (inquire-status, capabilities, health) do not carry it. Your integration MUST return the same response for repeated requests carrying the same key (payments-service retries transient/network failures and must never double-charge). |
| paymentId required | string Unique payment identifier from payments-service |
| transactionReference required | string Transaction reference you returned from authorize |
| amount | number Capture amount (optional, for partial capture; if omitted, captures the full authorized amount) |
object Partner/outlet-specific configuration provisioned by LoyaltyPlant (NOT chosen by the integrator) |
{- "paymentId": "8e2b7d6a-1f3c-4e9a-9c2b-77a0e3d4f111",
- "transactionReference": "psp_txn_7Hagain2",
- "amount": 49.99,
- "settings": {
- "currency": "USD"
}
}{- "status": "SUCCESS",
- "transactionReference": "psp_txn_7HagaIn2"
}Authorize and capture in a single call (single-phase payment).
payments-service calls this when your integration declares the SALE
capability. Return SUCCESS with a transactionReference, PENDING +
redirectUrl for 3DS/redirect (see the integrationResult callback),
or DECLINED/RETRIABLE/UNKNOWN. Idempotent on Idempotency-Key.
paymentInstrument behaves exactly as in /v1/authorize: charge the
enrolled card token or wallet payload when it is present.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| Idempotency-Key required | string <uuid> UUID for idempotent request handling, unique per logical operation. Carried by all mutating operations (authorize, sale, capture, refund, reverse); the read-only operations (inquire-status, capabilities, health) do not carry it. Your integration MUST return the same response for repeated requests carrying the same key (payments-service retries transient/network failures and must never double-charge). |
| paymentId required | string Unique payment identifier from payments-service | ||||||||||||
| amount required | number Payment amount in major currency units (e.g. 49.99). Convert to your PSP's required unit yourself. | ||||||||||||
| currency required | string ISO 4217 currency code (e.g. "USD", "EUR", "SAR") | ||||||||||||
object Partner/outlet-specific configuration provisioned by LoyaltyPlant
(NOT chosen by the integrator). Common keys: | |||||||||||||
object (PaymentInstrument) The per-payment instrument to charge. Optional: when the field is
absent, behave exactly as before — nothing changes for integrations that
do not declare Which field carries the payload depends on
payments-service only sends an instrument whose capability you declared, so you never have to handle a type you did not opt into. Both |
{- "paymentId": "8e2b7d6a-1f3c-4e9a-9c2b-77a0e3d4f111",
- "amount": 49.99,
- "currency": "USD",
- "settings": {
- "currency": "USD",
- "merchantId": "acct_3092f1"
}
}{- "status": "SUCCESS",
- "transactionReference": "psp_txn_7HagaIn2"
}{- "status": "SUCCESS",
- "transactionReference": "psp_txn_7HagaIn2"
}Return funds for a captured payment. Requires the DIRECT_REFUND
capability. transactionReference identifies the original payment;
amount is the amount to refund (supports partial refunds).
Idempotent on Idempotency-Key.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| Idempotency-Key required | string <uuid> UUID for idempotent request handling, unique per logical operation. Carried by all mutating operations (authorize, sale, capture, refund, reverse); the read-only operations (inquire-status, capabilities, health) do not carry it. Your integration MUST return the same response for repeated requests carrying the same key (payments-service retries transient/network failures and must never double-charge). |
| paymentId required | string Unique payment identifier from payments-service |
| transactionReference required | string Transaction reference of the payment to refund |
| amount required | number Refund amount in major currency units (supports partial refunds) |
| reason | string Reason for the refund (free text, for your records / PSP) |
object Partner/outlet-specific configuration provisioned by LoyaltyPlant (NOT chosen by the integrator) |
{- "paymentId": "8e2b7d6a-1f3c-4e9a-9c2b-77a0e3d4f111",
- "transactionReference": "psp_txn_7Hagain2",
- "amount": 10,
- "reason": "Item out of stock",
- "settings": {
- "currency": "USD"
}
}{- "status": "SUCCESS",
- "transactionReference": "psp_txn_7HagaIn2"
}Void an authorization before it is captured (releases the hold).
transactionReference is the value returned from authorize.
Idempotent on Idempotency-Key.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| Idempotency-Key required | string <uuid> UUID for idempotent request handling, unique per logical operation. Carried by all mutating operations (authorize, sale, capture, refund, reverse); the read-only operations (inquire-status, capabilities, health) do not carry it. Your integration MUST return the same response for repeated requests carrying the same key (payments-service retries transient/network failures and must never double-charge). |
| paymentId required | string Unique payment identifier from payments-service |
| transactionReference required | string Transaction reference of the payment to reverse/void |
object Partner/outlet-specific configuration provisioned by LoyaltyPlant (NOT chosen by the integrator) |
{- "paymentId": "8e2b7d6a-1f3c-4e9a-9c2b-77a0e3d4f111",
- "transactionReference": "psp_txn_7Hagain2",
- "settings": {
- "currency": "USD"
}
}{- "status": "SUCCESS",
- "transactionReference": "psp_txn_7HagaIn2"
}Queries the PSP for the current status of a previously initiated payment.
Used for reconciliation and manual status checks (e.g. after a timeout or
an UNKNOWN result, or when an async callback never arrived).
Requires STATUS_POLLING capability. This is a read-only operation and
carries no Idempotency-Key.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| transactionReference | string Transaction reference returned by a previous authorize/sale/capture operation |
| paymentId | string Payment ID from payments-service (alternative lookup key) |
object Partner/outlet-specific configuration provisioned by LoyaltyPlant (NOT chosen by the integrator) |
{- "transactionReference": "psp_txn_7Hain2",
- "paymentId": "8e2b7d6a-1f3c-4e9a-9c2b-77a0e3d4f111",
- "settings": {
- "currency": "USD",
- "merchantId": "acct_3092f1"
}
}{- "status": "CAPTURED",
- "transactionReference": "psp_txn_7HagaIn2",
- "rawStatus": "captured"
}Start binding a customer's card so it can be charged later without
re-entering card details. payments-service calls this when the customer
adds a card in the app, and only when your integration declares the
TOKENIZATION capability.
Two shapes of answer are valid:
PENDING + redirectUrl + transactionReference — the usual
case. redirectUrl is your hosted card-entry page; payments-service
opens it for the customer. When the PSP tells you the card is bound,
deliver the token with the integrationEnrollmentResult callback.SUCCESS + card — for PSPs that tokenize without a redirect
(e.g. client-side SDK tokenization). No callback follows.DECLINED / RETRIABLE / UNKNOWN behave exactly as in payment
operations. Idempotent on Idempotency-Key.
Never return the card token on the browser redirect to returnUrls
— those are navigation only. The token travels server-to-server, in the
callback or in this response.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| Idempotency-Key required | string <uuid> UUID for idempotent request handling, unique per logical operation. Carried by all mutating operations (authorize, sale, capture, refund, reverse); the read-only operations (inquire-status, capabilities, health) do not carry it. Your integration MUST return the same response for repeated requests carrying the same key (payments-service retries transient/network failures and must never double-charge). |
| enrollmentId required | string <uuid> Enrollment identifier minted by payments-service. Echo it back in
the |
object (EnrollmentCustomer) Customer details for the hosted card-entry page. Whether any of these are
required depends on your PSP — state your requirements during onboarding.
LoyaltyPlant never sends a customer identifier here: your service does
not need to know who the customer is, and payments-service resolves the
enrollment from | |
object (EnrollmentReturnUrls) Where your hosted page sends the browser once the customer is done. These are navigation only — payments-service treats them as UX, not as a result. Never append the card token or any PSP secret to them. | |
object Partner/outlet-specific configuration provisioned by LoyaltyPlant
(NOT chosen by the integrator). Common keys: |
{- "enrollmentId": "3f6c1b90-2d4e-4a11-9f77-0b2c5d8e4a10",
- "customer": {
- "email": "customer@example.com",
- "name": "Jane Doe",
- "language": "en"
}, - "returnUrls": {
}, - "settings": {
- "currency": "USD",
- "merchantId": "acct_3092f1"
}
}{- "status": "PENDING",
- "transactionReference": "psp_enr_9KdlaQ7",
- "expectedTtlSeconds": 900
}{- "enrollmentId": "3f6c1b90-2d4e-4a11-9f77-0b2c5d8e4a10",
- "transactionReference": "psp_enr_9KdlaQ7",
- "status": "SUCCESS",
- "card": {
- "token": "tok_4gld6myqrxbu5g3gcxlqcwbxfa",
- "maskedPan": "**** 4242",
- "brand": "VISA",
- "expiryMonth": 12,
- "expiryYear": 2029
}
}Look up the current state of an enrollment started with /v1/enroll.
payments-service calls this once before expiring a pending enrollment,
to recover from a lost integrationEnrollmentResult callback: without
it a card bound at your PSP would silently never appear for the
customer.
Requires the STATUS_POLLING capability (the same flag that gates
/v1/inquire-status). Read-only, no Idempotency-Key.
Look up by enrollmentId — it is always known to payments-service,
whereas transactionReference is not if your PENDING response was
lost in transit. Return the card object whenever the status is
COMPLETED.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
| enrollmentId required | string <uuid> Enrollment identifier from the original |
| transactionReference | string The reference you returned in the PENDING response, when
payments-service has it. Absent if your PENDING response never
arrived — resolve by |
{- "enrollmentId": "3f6c1b90-2d4e-4a11-9f77-0b2c5d8e4a10",
- "transactionReference": "psp_enr_9KdlaQ7"
}{- "status": "COMPLETED",
- "transactionReference": "psp_enr_9KdlaQ7",
- "card": {
- "token": "tok_4gld6myqrxbu5g3gcxlqcwbxfa",
- "maskedPan": "**** 4242",
- "brand": "VISA",
- "expiryMonth": 12,
- "expiryYear": 2029
}, - "rawStatus": "card_verified"
}Returns the list of payment capabilities this integration supports. Payments-service caches the result and validates capabilities before invoking optional operations — it will never call an operation whose capability you did not declare. Declare only what you have actually implemented and tested.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
{- "capabilities": [
- "CAPTURE",
- "DIRECT_REFUND",
- "REDIRECT_FLOW",
- "DIRECT_WEBHOOK",
- "STATUS_POLLING"
]
}Returns the health status of the integration service.
Payments-service polls this endpoint periodically to decide whether to
route traffic to your integration. Return DOWN (or 503) when your
PSP connection is unavailable so payments-service can stop sending you
live payments until you recover.
| Authorization required | string Bearer token authenticating payments-service to your integration (the outbound token LoyaltyPlant provisions for you during onboarding). Validate it on every request (constant-time compare) and reject anything else with 401. Treat the token as a secret; rotate it via LoyaltyPlant. Example: "Bearer sk_live_abc123". |
{- "status": "UP"
}