BLIK payin

The payer gives a BLIK code from their banking app, then confirms the payment in the app. PLN only.

Use the key of a payin shop; a payout shop key gets 403 method_not_enabled. Rules shared by every method — Authentication, Idempotency, Errors, Webhooks — apply here and are not repeated.

Flow

  1. Ask the payer for the BLIK code. Generate merchant_reference and save it with your order.
  2. Create the payin: POST /v2/payins/blik. Save id from the response.
  3. Read next_action: tell the payer to confirm the payment in the banking app (await_confirmation), or send them to next_action.redirect.url (redirect). Which one comes is set for the shop.
  4. Wait for the webhook payin.completed or payin.failed. Verify the signature and act on data.object — the full payin.
  5. Fallback: 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).

Endpoints

Step Endpoint Operation
Create POST /v2/payins/blik createBlikPayin
Read one GET /v2/transactions/{transaction_id} — common for all transactions, see Read one transaction retrieveTransaction

Refunds of BLIK payins return 501 not_supported_yet — see Refunds. The create has its own section below. Reading returns the Payin object.

POST /v2/payins/blik

Creates a payin and waits up to 10 seconds for the payer step, so the response usually carries next_action.

Request

Headers: Authorization: Bearer <payin shop key>, Content-Type: application/json.

Field Type Required Format and limits
merchant_reference string yes 1–100 letters, digits, _, -. Unique per merchant across payins, refunds, payouts and pay sessions. The idempotency key of this call
amount object yes
amount.value string yes Major units, at most two decimals, at least 0.01: "120.00". A string, never a number
amount.currency string yes PLN, the shop currency
payer object yes The person who pays
payer.first_name string yes 2–255 Latin letters, spaces, ., ', -
payer.last_name string yes 2–255 Latin letters, spaces, ., ', -
payer.email string yes Email address
payer.ip_address string yes IPv4 or IPv6 of the payer
payer.phone string no +48500100200
blik object yes
blik.code string yes The BLIK code from the payer's banking app
curl -X POST https://payments-api.mrcr.io/v2/payins/blik \
  -H "Authorization: Bearer $PAYIN_SHOP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_reference": "order-40001",
    "amount": { "value": "120.00", "currency": "PLN" },
    "payer": { "first_name": "Jan", "last_name": "Kowalski", "email": "jan@example.com", "ip_address": "203.0.113.20" },
    "blik": { "code": "777123" }
  }'

Response 201 Created

The Payin object in data. Usually requires_action with next_action; if the payer step is not ready in 10 seconds — processing, and the step comes by the payin.requires_action webhook. A repeat of an earlier call returns the payin in its current status.

Header Meaning
Idempotent-Replayed: true The same merchant_reference and body were sent before. This is the existing payin in its current status; nothing was created again
{
  "data": {
    "id": "5a1e9d7f-2b6c-4d3a-8f8e-0c7b3d6a9fc5",
    "object": "payin",
    "merchant_reference": "order-40001",
    "method_type": "payin_blik",
    "status": "requires_action",
    "status_details": null,
    "amount": { "value": "120.00", "currency": "PLN" },
    "refunded_amount": { "value": "0.00", "currency": "PLN" },
    "next_action": { "type": "await_confirmation" },
    "created_at": "2026-09-29T09:30:00Z",
    "updated_at": "2026-09-29T09:30:02Z"
  }
}

Errors

No payin is created on any of them.

HTTP code When Retry
400 validation_failed A field is missing or malformed — details[] names it. Also: the amount has more than two decimals or is not in PLN No. Fix the request
401 authentication_failed The key is missing, malformed, revoked, or sent to the wrong host No
403 method_not_enabled BLIK is not enabled for the shop, or the key is of a payout shop No. Use the payin shop key, or ask Mercuryo to enable the method
409 merchant_reference_conflict The reference was used with a different body No. Resend the original body, or use a new reference for a new payin
429 rate_limited Too many requests Yes, after Retry-After seconds
500 internal_error Failure on our side Yes, the identical request

After a timeout or a dropped connection the payin may or may not exist. Resend the identical request (R4), never with a new reference.

Payer step: confirm the payment

The payin waits in requires_action until the payer confirms or rejects the payment in the banking app. next_action.type is set for the shop:

next_action.type What you do
await_confirmation Tell the payer to confirm the payment in the banking app. Keep the page open until the final status
redirect Send the payer to next_action.redirect.url — the payment page — as a full page or a new window

How to show it in a browser or an app — Payer actions.

The Payin object

Returned by the create and by GET /v2/transactions/{transaction_id}, and sent in webhooks as data.object. It has the common fields of every transaction, with these values and fields for a BLIK payin:

Field Type Always set Meaning
id string yes UUID. Use it in GET /v2/transactions/{transaction_id}
object string yes payin
method_type string yes payin_blik
status string yes created, processing, requires_action, completed, failed — see Statuses
status_details.code string when failed See Decline reasons
refunded_amount object yes "0.00" in PLN
next_action object or null yes Set in requires_action, null in every other status
next_action.type string in requires_action await_confirmation or redirect
next_action.redirect.url string when type is redirect The payment page

Statuses

Status What it means The money Webhook What you do Next
created Accepted and recorded — — Wait processing, failed
processing Checks run, the payin goes to the bank — — Wait requires_action, failed
requires_action Waiting for the payer to confirm in the banking app — payin.requires_action Show the payer step from next_action completed, failed
completed Final. Charged Charged payin.completed Fulfil the order —
failed Final. Not charged, including a payer who rejected. status_details.code says why — payin.failed Act on the decline reason —
  • Only completed and failed are outcomes. A final status never changes.
  • requires_action usually comes in the create response; the payin.requires_action webhook comes as well.
  • An unknown status is not final — keep waiting (R13).

Decline reasons

status_details.code on a failed BLIK payin. Every decline is final: a new attempt is a new payin with a new merchant_reference and a new BLIK code.

Code When What you do
method_unavailable BLIK is not available right now Try again later with a new payin
risk_rejected Rejected by antifraud Do not retry automatically
provider_declined The bank declined, or the code is wrong or used Ask the payer for a new code
canceled_by_payer The payer rejected the payment in the app, or the code ran out Ask the payer whether to try again
internal_error Failure on our side; nothing was charged Try again with a new payin. Quote id to support if it repeats

An unknown code: handle it like provider_declined.

Webhooks

type When data.object
payin.requires_action The payin waits for the payer to confirm The Payin object, with next_action
payin.completed The payin reaches completed The Payin object
payin.failed The payin reaches failed The Payin object, with status_details

Headers, signature check and redelivery — Webhooks.

In the sandbox

blik.code: any six digits. The cents of amount.value select the outcome:

Cents Example Outcome
any other 120.00 requires_action, then completed after 5 seconds
.51 120.51 failed — provider_declined
.52 120.52 failed — risk_rejected
.55 120.55 failed — method_unavailable
.56 120.56 failed — internal_error
.58 120.58 requires_action, then failed — canceled_by_payer

Sandbox keys and fixtures — Sandbox.

Next: Hosted payment form