Payments
A payment is what a session produced. Read it for the outcome, the decline reason if there was one, and the hold state when the integration holds rather than captures.
GET /v1/payments/{payment_id} #
Retrieve a payment
Authentication. Your secret key, in X-Ripper-Api-Key. Server only.
Returns one of your payments. status is captured when the money was taken. A payment on hold has
status: held and capture_state: authorised until the hold is captured or voided.
Requires a secret key with the read_transactions permission.
| parameter | in | required | what it is |
|---|---|---|---|
payment_id |
path | yes | The payment's id. |
200 — The payment.
{
"id": "pay_89abcdef0123456789abcdef",
"checkout_session_id": "cs_0123456789abcdef01234567",
"status": "captured",
"amount": 2500,
"currency": "GBP",
"mode": "test",
"decline": null,
"authentication": {
"outcome": "Authenticated",
"liability_shifted": true,
"eci": null
},
"acquirer_transaction_id": null,
"created_at": "2026-09-16T10:17:41.0000000+00:00",
"executed_at": "2026-09-16T10:17:42.0000000+00:00",
"amount_verified": true,
"capture_state": "captured",
"customer": {
"email": "shopper@example.com",
"name": "Sam Shopper",
"account_created": null,
"account_id": "your-customer-4821",
"metadata": {
"tier": "gold"
}
},
"order_reference": "ORDER-1042",
"order_reference_captured_payments": 1
}Fields in the response
| field | type | always sent | what it is |
|---|---|---|---|
id |
string | yes | The payment. Quote this to us about anything that happened to the money. |
checkout_session_id |
string or null | yes | The session this payment came from. |
status |
string | yes | captured: paid. held: authorised and waiting on the hold decision. voided: a hold released. pending: the outcome is not known yet. |
amount |
integer | yes | What was charged, in the currency’s minor unit. |
currency |
string or null | yes | A three-letter ISO 4217 code, for example GBP. |
mode |
string | yes | test or live. A test payment moved no money. |
decline |
object or null | yes | Why the payment was declined, or null when it was not. |
authentication |
object or null | yes | The 3-D Secure result, PRESENT EXACTLY WHEN AN AUTHENTICATION RAN and absent otherwise. That absence carries a fact nothing else on the payment does. liability_shifted is false on a payment that never authenticated AND on one that authenticated without shifting liability — two different situations, and only the presence of this block tells them apart. If you are deciding who carries a disputed payment, check whether the block is here before you read anything inside it. |
acquirer_transaction_id |
string or null | yes | The bank’s own reference for this payment. Quote it to your acquirer, not to us. |
created_at |
string | yes | When the payment was created. |
executed_at |
string or null | yes | When the money actually moved, or null if it never did. |
amount_verified |
boolean | yes | Whether ripper could check the amount against your price list before charging it. When it could not, an approved payment is held for you to review rather than captured. |
capture_state |
string or null | yes | Where the money is. captured: taken. authorised: the shopper's bank is holding it for you and it has not been taken yet. voided: the authorisation was released and nothing was taken. null when nothing was authorised at all — a decline or a failure. |
items |
array or null | no | The basket, as sent on the server create. null when the session carried no lines — never an empty array, so "no basket" and "an empty basket" stay different answers. |
basket_total |
integer or null | no | What the lines add up to, in minor units, tax inclusive: products, shipping and fees added, discounts subtracted. Computed by ripper and never accepted in a request. null when there are no lines. When it differs from amount, amount is what was charged and the difference is shown to the shopper as one adjustment. |
tax_total |
integer or null | no | The tax across the lines, in minor units. null when no line carries a tax_amount. |
customer |
object or null | yes | The shopper, as you or the checkout supplied them. |
order_reference |
string or null | yes | Your own reference for this order, or null when none was sent. |
order_reference_captured_payments |
integer or null | yes | How many captured payments share this order reference, THIS ONE INCLUDED. So an ordinary captured payment on its own reference reads 1, not 0. null — no order reference, so there is nothing to count. 0 — the reference exists and no money has been taken on it yet. This is the answer on a held payment, and it is the one to check before releasing goods. 1 — the ordinary case: this payment, and no other capture on the reference. 2 or more — almost always the shopper paid twice. Duplicates are surfaced, never refused, so this is how you find out. Counts only your own payments: another merchant's payments on the same reference are not yours and are not counted. |
decline fields
| field | type | always sent | what it is |
|---|---|---|---|
code |
string | yes | The decline code. |
category |
string or null | yes | How to treat the decline: soft, hard, fraud, network or provider_error. Since v1.13 the word is the same snake_case everywhere — these routes, the webhook and the checkout — where the merchant routes and webhooks previously spelled it Soft, Hard, ProviderError and so on. It is the payment platform's own category, relayed unchanged rather than re-classified here. |
reason |
string or null | yes | The acquirer's own words, passed on as received. |
authentication fields
| field | type | always sent | what it is |
|---|---|---|---|
outcome |
string | yes | How the 3-D Secure authentication went. Today the value arrives as Authenticated, Attempted or Failed. There is no fourth word: when the authentication produced anything else, this whole block is absent rather than carrying another value. It is what decides liability_shifted beside it, so it is the field to read when you want to know who carries a disputed payment. COMPARE IT IGNORING CASE AND SEPARATORS — fold the value to one case and remove any _ or - before you match it. Those capitals are what the API sends today and are not a convention: everything else here is lower case with underscores, and whether this field should be too is under review. Ignoring case alone would be enough for these three words and would quietly stop being enough the day a two-word value arrived as two_words; ignoring separators as well costs you nothing and is right whichever way that decision goes. |
liability_shifted |
boolean | yes | Whether the card scheme moved liability for a disputed payment to the issuer. This is the point of 3-D Secure. |
eci |
string or null | yes | The scheme’s own code for how the authentication went. Your acquirer may ask for it. |
items fields
| field | type | always sent | what it is |
|---|---|---|---|
kind |
string | yes | What this line is: product, shipping, discount or fee. A discount carries a positive unit_amount that is subtracted. |
sku |
string or null | yes | Your code for the item, or null if the line had none. |
name |
string or null | yes | What the shopper was shown, or null if the line was priced from your catalogue and carried no name. |
quantity |
integer | yes | How many. |
unit_amount |
integer or null | yes | What the shopper paid per unit, tax inclusive, in the currency’s minor unit. null on a line your catalogue has not priced. |
tax_amount |
integer or null | yes | The tax inside this line’s total, in minor units, or null when the line carries no tax. |
tax_rate |
integer or null | yes | This line’s tax rate in basis points, where 2000 is 20.00%, or null when none was set. |
type |
string or null | yes | Your own label for the kind of thing this is, or null. |
customer fields
| field | type | always sent | what it is |
|---|---|---|---|
email |
string or null | yes | The shopper’s email address, or null when none was given. |
name |
string or null | yes | The shopper’s name, or null when none was given. |
account_created |
string or null | yes | When the shopper's account with you was created, if a browser session sent it. |
account_id |
string or null | yes | Your own identifier for this shopper, exactly as you sent it. null when none was sent. Set from a browser session it is whatever the page sent, so treat it as the page's claim rather than as something ripper has checked. |
metadata |
object or null | yes | Your own values about this shopper, keys exactly as you sent them. null when none were sent. This is the CUSTOMER's metadata; the session's own metadata is a separate field with a separate budget, and the two are never merged. |
When it refuses
401—unauthorized: no key, or a key that is unknown, expired, or used from an address or origin the key does not allow.key_revoked: the key was revoked.public_key_missing: the key has no publishable key paired with it.403—permission_denied: the key does not haveread_transactions.merchant_not_active: your account is not active.404—resource_not_found: there is no such id on your account. Another account's id answers the same.429— Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait forRetry-Afterseconds.500—internal_error: something failed on ripper's side. The body carries no message. Quoterequest_idto support.
Operation id getPayment, for code generators.