Transactions
Payins, refunds and payouts are all transactions: one id space, one read endpoint.
| Object | object |
Created by | Final statuses |
|---|---|---|---|
| Payin | payin |
POST /v2/payins/card, /apple-pay, /google-pay, /blik; a pay session when the payer submits the form |
completed, failed |
| Refund | refund |
POST /v2/payins/{payin_id}/refunds |
completed, failed |
| Payout | payout |
POST /v2/payouts/card |
completed, failed |
Every transaction has a UUID id; object says which kind it is.
Response shape
| Response | Shape |
|---|---|
| One object | { "data": { "id": "…", "object": "payin", … } } |
| A list | { "data": [ … ], "has_more": true } |
| An error | { "error": { … } } — see Errors |
Branch on object to tell the three apart.
The transaction object
Every response with a transaction — the create, GET /v2/transactions/{transaction_id}, the list and
data.object in a webhook — has the same layout: the common fields, the fields of its object, and
the fields of its payment instrument in an object named after it: card, apple_pay, google_pay.
Common fields
| Field | Type | Always set | Meaning |
|---|---|---|---|
id |
string | yes | Transaction id, a UUID |
object |
string | yes | payin, refund or payout |
merchant_reference |
string | yes | As you sent it |
method_type |
string | yes | The flow, end to end: payin_card, payin_apple_pay, payin_google_pay, payin_blik, refund, payout_card. The method of a refund is the method of its payin, payin_id |
status |
string | yes | The status of the object — see Statuses |
status_details |
object or null |
yes | null unless status is failed |
status_details.code |
string | when failed |
The decline reason — see Errors |
status_details.message |
string | no | Human-readable. Not stable — do not parse |
amount |
object | yes | As you sent it; for a refund sent without amount — the refunded remainder |
amount.value |
string | yes | Major units: "300.00" |
amount.currency |
string | yes | ISO 4217: EUR |
created_at |
date-time | yes | UTC |
updated_at |
date-time | yes | UTC. Time of the last change |
Fields by object
object |
Fields |
|---|---|
payin |
refunded_amount, next_action, capture_method (card) — see the method pages |
refund |
payin_id — the payin the money is returned from. See Refunds |
payout |
rrn — the reference of the payout in the card network |
Fields of the payment instrument
method_type |
Object | Fields |
|---|---|---|
payin_card |
card |
brand, last4, token |
payout_card |
card |
brand, last4 |
payin_apple_pay |
apple_pay |
brand, last4 |
payin_google_pay |
google_pay |
brand, last4 |
The exact set for each method is on its page: Card payin, Apple Pay, Google Pay, BLIK, Card payout.
Your reference
merchant_reference is your id for a transaction, required on every create, unique per merchant
across payins, refunds, payouts and pay sessions. It is also the idempotency key of the create — see
Idempotency.
Amounts
{ "value": "100.50", "currency": "EUR" }. value is a string in major units with at most two
decimals, never a number.
currency is the shop currency. A shop has one currency; to work in several currencies, use a shop
per currency. A transaction in another currency gets 400 validation_failed.
A refund is its own transaction
A refund has its own id, merchant_reference and status. When it completes, the payin moves to
refunded and its refunded_amount grows. Card, Apple Pay and Google Pay payins can be refunded;
BLIK returns 501 not_supported_yet. See Refunds.
Reading
| Need | Call |
|---|---|
| One transaction by id | GET /v2/transactions/{transaction_id} |
| A list, newest first | GET /v2/transactions |
| Refunds of one payin | GET /v2/transactions?payin_id=… |
| By your reference | GET /v2/transactions?merchant_reference=… |
| Everything that changed since the last sync | GET /v2/transactions?updated_from=… |
List filters: object (payin, refund, payout), method_type, status, merchant_reference,
payin_id, created_from, created_to, updated_from, updated_to. *_from is inclusive, *_to
exclusive.
Order: order=created_desc (default) — newest first, for browsing; order=updated_asc — oldest
change first, ties broken by id, for syncing.
Pages: limit (1–100, default 20). While has_more is true, request the next page with
starting_after = the id of the last item; ending_before = the first id goes back.
Read one transaction
GET /v2/transactions/{transaction_id} — retrieveTransaction. Returns a payin, refund or payout of
the key's shop. The fallback channel for statuses — see Webhooks first;
also finds the status after a lost response.
Request
Headers: Authorization: Bearer <shop key>.
| Parameter | In | Type | Required | Meaning |
|---|---|---|---|---|
transaction_id |
path | string | yes | id from the create response, a UUID |
curl https://payments-api.mrcr.io/v2/transactions/6b2f0e8a-3c7d-4e4b-9a9f-1d8c4e7b0ad6 \
-H "Authorization: Bearer $PAYOUT_SHOP_KEY"
Response 200 OK
The transaction in data — see The transaction object. object says
which one:
object |
Fields |
|---|---|
payin |
The Payin object on the method page: Card, Apple Pay, Google Pay, BLIK |
refund |
The Refund object |
payout |
The Payout object |
{
"data": {
"id": "6b2f0e8a-3c7d-4e4b-9a9f-1d8c4e7b0ad6",
"object": "payout",
"merchant_reference": "payout-10001",
"method_type": "payout_card",
"status": "failed",
"status_details": { "code": "invalid_recipient_details", "message": "Card number rejected by the receiving bank" },
"amount": { "value": "300.00", "currency": "EUR" },
"card": { "brand": "visa", "last4": "1111" },
"created_at": "2026-09-29T12:00:00Z",
"updated_at": "2026-09-29T12:00:09Z"
}
}
Errors
| HTTP | code |
When |
|---|---|---|
| 401 | authentication_failed |
The key is missing, malformed, revoked, or sent to the wrong host |
| 404 | resource_not_found |
No such transaction in this shop, for example an id of another shop |
| 429 | rate_limited |
Too many requests |
| 500 | internal_error |
Failure on our side. Retry |
Webhooks first, reading as the fallback
Status changes come to you by webhook. A verified webhook carries the full
transaction; it is the result. If no webhook has come for a minute, you can start polling the status with
GET /v2/transactions/{transaction_id} until it is final. Polling instead of webhooks loads the API
and gets 429 rate_limited (R20). The scheduled sync below catches the rest.
Syncing statuses
Webhooks can be missed; a scheduled sync catches what they did not deliver (R19):
window_start= thewindow_endof the last run minus 5 minutes (overlap);window_end= now.GET /v2/transactions?order=updated_asc&updated_from={window_start}&updated_to={window_end}&limit=100.- While
has_more, repeat withstarting_after= the lastid. - Apply each transaction. Do not overwrite a final status, except
completed→refundedof a payin. - Save
window_endonly after the last page.
Pages are keyset cursors: within one window a transaction is never skipped or repeated. A
transaction changed while you page moves past window_end and comes in the next run.
A key reads only its own shop: a payin shop sees payins and refunds, a payout shop sees payouts.
Next: Statuses