Apple Pay payin

Charge the card behind an Apple Pay token on the web. You validate the merchant session, the payer confirms in Apple Pay, you send the token.

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. On onvalidatemerchant, send validationURL and your domain to POST /v2/payins/apple-pay/sessions. Pass data.apple_pay.session to completeMerchantValidation unchanged.
  2. On onpaymentauthorized, generate merchant_reference and save it with your order.
  3. Create the payin: POST /v2/payins/apple-pay with token.paymentData in Base64. Save id.
  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
Merchant validation POST /v2/payins/apple-pay/sessions createApplePaySession
Create POST /v2/payins/apple-pay createApplePayPayin
Refund POST /v2/payins/{payin_id}/refunds — common for all payins, see Refunds createRefund
Read one GET /v2/transactions/{transaction_id} — common for all transactions, see Read one transaction retrieveTransaction

The session and the create have their own sections below. Reading returns the Payin object.

POST /v2/payins/apple-pay/sessions

Gets an Apple Pay merchant session. Creates no transaction; safe to repeat.

Request

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

Field Type Required Format and limits
apple_pay object yes
apple_pay.validation_url string yes validationURL from onvalidatemerchant: https://apple-pay-gateway.apple.com/…
apple_pay.domain string yes The domain the payment runs on, registered for the shop: shop.example.com
curl -X POST https://payments-api.mrcr.io/v2/payins/apple-pay/sessions \
  -H "Authorization: Bearer $PAYIN_SHOP_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "apple_pay": { "validation_url": "https://apple-pay-gateway.apple.com/paymentservices/startSession", "domain": "shop.example.com" } }'

Response 200 OK

Field Type Always set Meaning
data.apple_pay.session object yes The Apple Pay merchant session. Pass it to completeMerchantValidation unchanged

Errors

HTTP code When Retry
400 validation_failed validation_url is not an Apple Pay gateway URL, or domain is not registered for the shop No
403 method_not_enabled Apple Pay 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

Also 401, 429, 500 — see Errors.

POST /v2/payins/apple-pay

Creates a payin from the Apple Pay token.

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: "59.90". A string, never a number
amount.currency string yes ISO 4217, the shop currency: EUR
payer object yes The person who pays
payer.first_name string yes Letters, digits, spaces, ., ', -
payer.last_name string yes Letters, digits, spaces, ., ', -
payer.email string yes Email address
payer.ip_address string yes IPv4 or IPv6 of the payer
payer.address object yes Billing address
payer.address.country string yes ISO 3166-1 alpha-2: US
payer.address.state string for US, CA, AU payers ISO 3166-2 subdivision code without the country prefix, 2–3 letters: CA
payer.address.city string yes Not digits only
payer.address.postal_code string yes
payer.address.line1 string yes Street and house number
payer.address.line2 string no Apartment, suite, floor
apple_pay object yes
apple_pay.payment_token string yes Base64 of the token.paymentData JSON from onpaymentauthorized
curl -X POST https://payments-api.mrcr.io/v2/payins/apple-pay \
  -H "Authorization: Bearer $PAYIN_SHOP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "merchant_reference": "order-20001",
    "amount": { "value": "59.90", "currency": "EUR" },
    "payer": {
      "first_name": "Jane", "last_name": "Doe", "email": "jane@example.com", "ip_address": "203.0.113.10",
      "address": { "country": "US", "state": "CA", "city": "San Francisco", "postal_code": "94105", "line1": "1 Market Street" }
    },
    "apple_pay": { "payment_token": "eyJ2ZXJzaW9uIjoiRUNfdjEiLCJkYXRhIjoi…" }
  }'

Response 201 Created

The Payin object in data, in created. Any status is possible, including a final one when the call repeats an earlier one.

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": "3e9c7b5d-0f4a-4b1e-8d6c-8a5f1b4e7da3",
    "object": "payin",
    "merchant_reference": "order-20001",
    "method_type": "payin_apple_pay",
    "status": "created",
    "status_details": null,
    "amount": { "value": "59.90", "currency": "EUR" },
    "refunded_amount": { "value": "0.00", "currency": "EUR" },
    "next_action": null,
    "created_at": "2026-09-29T09:10:00Z",
    "updated_at": "2026-09-29T09:10:00Z"
  }
}

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 the shop currency No. Fix the request
401 authentication_failed The key is missing, malformed, revoked, or sent to the wrong host No
403 method_not_enabled Apple Pay 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.

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 an Apple Pay payin:

Field Type Always set Meaning
id string yes UUID. Use it in refunds and GET /v2/transactions/{transaction_id}
object string yes payin
method_type string yes payin_apple_pay
status string yes created, processing, completed, failed, refunded — see Statuses
status_details.code string when failed See Decline reasons
refunded_amount object yes Sum of completed refunds; above zero in refunded
refunded_amount.value string yes Major units: "20.00"
refunded_amount.currency string yes ISO 4217: EUR
apple_pay object no Set after the token is decrypted
apple_pay.brand string no Card scheme: visa, mastercard
apple_pay.last4 string no Last four digits of the device card number

Statuses

Status What it means The money Webhook What you do Next
created Accepted and recorded — — Wait processing, failed
processing The token is decrypted, checks run, the payin is at the provider — — Wait completed, failed
completed Final. Charged Charged payin.completed Fulfil the order refunded
refunded Final. Charged, then refunded in part or in full. refunded_amount says how much Refunded in part or in full payin.refunded on every completed refund Reflect the refund in your order —
failed Final. Not charged. status_details.code says why — payin.failed Act on the decline reason —
  • Only completed, failed and refunded are outcomes. A final status never changes, with one exception: a completed refund moves the payin from completed to refunded.
  • An unknown status is not final — keep waiting (R13).

Decline reasons

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

Code When What you do
invalid_payment_token The token could not be decrypted Ask the payer to pay again in Apple Pay
card_not_supported The card's BIN is unknown or not accepted Ask the payer for another card
method_unavailable No route for this card right now Try again later with a new payin
risk_rejected Rejected by antifraud Do not retry automatically
provider_declined The provider or the issuer declined Ask the payer to try again or use another card
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.completed The payin reaches completed The Payin object
payin.refunded A refund of the payin completes — the first one moves it to refunded The Payin object, with refunded_amount
payin.failed The payin reaches failed The Payin object, with status_details
refund.completed, refund.failed A refund of this payin reaches a final status The Refund object — see Refunds

Headers, signature check and redelivery — Webhooks.

In the sandbox

apple_pay.payment_token: test_apple_pay_token_visa, or a real token from Apple Pay in its sandbox environment. The session endpoint returns a stub session. The cents of amount.value select the outcome:

Cents Example Outcome
any other 59.00 completed
.51 59.51 failed — provider_declined
.52 59.52 failed — risk_rejected
.54 59.54 failed — card_not_supported
.55 59.55 failed — method_unavailable
.56 59.56 failed — internal_error
.61 59.61 processing for 60 seconds, then completed

Sandbox keys and fixtures — Sandbox.

Next: Google Pay