Payments

One request shape for every rail you accept.

Create a payment with an amount, a currency and a payment method. NATIO evaluates risk, picks a provider, sends the request and returns the outcome together with the route it took. What changes between cards, bank transfers, QR and local methods is configuration, not your integration.

Create a payment

Amounts in minor units. Idempotency on every mutating call.

For synchronous methods the create response already carries the final status. For asynchronous methods it carries processing and a next_action for the customer.

01

Minor units only

Integers, never decimals: 10000 is 100.00 USD. The same rule applies to captures, refunds, fees and payouts.
amount
02

Method as a type or a token

Send a type such as "card", or an object with a provider token or a stored payment method id. Raw card numbers are never accepted.
payment_method
03

Idempotency

Send a key on every create, capture, cancel and refund. A replayed key returns the original response instead of creating a second payment.
Idempotency-Key
04

Route on every payment

Which provider processed it, the provider's own id for the payment, how many attempts it took and which routing rule matched.
route
Request
curl -X POST https://api.natio.me/v1/payments \
  -H "Authorization: Bearer natio_sk_test_..." \
  -H "Idempotency-Key: order-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "currency": "USD",
    "payment_method": "card",
    "country": "US",
    "reference": "ORD-1001",
    "customer": { "external_id": "cus_42", "email": "jane@example.com" },
    "capture_method": "automatic"
  }'
Response · 201 Created
{
  "id": "pay_7Kq2mN9xR4vL8wP1tY3z",
  "object": "payment",
  "mode": "test",
  "status": "successful",
  "amount": 10000,
  "currency": "USD",
  "captured_amount": 10000,
  "refunded_amount": 0,
  "capture_method": "automatic",
  "payment_method": { "type": "card", "id": null },
  "country": "US",
  "reference": "ORD-1001",
  "route": {
    "provider": { "code": "demo_acquirer_b", "name": "NATIO Demo Acquirer B" },
    "provider_payment_id": "dmb_9f21c4",
    "attempts": 2,
    "rule": "Cards → Acquirer A, fallback Acquirer B"
  },
  "risk": { "decision_id": "rsk_3Jv...", "score": 0 },
  "failure": null,
  "next_action": null,
  "fee": { "amount": 320, "currency": "USD" },
  "processing_time_ms": 83,
  "attempts": [
    {
      "attempt_number": 1,
      "status": "failed",
      "outcome": "technical_error",
      "provider_name": "NATIO Demo Acquirer A",
      "provider_code": "GW-500",
      "latency_ms": 41
    },
    {
      "attempt_number": 2,
      "status": "succeeded",
      "outcome": "success",
      "provider_name": "NATIO Demo Acquirer B",
      "provider_payment_id": "dmb_9f21c4",
      "latency_ms": 42
    }
  ]
}
Payment methods

Seven method types behind one contract.

Which providers can serve a given type, currency and country is provider configuration. Your request does not change when a market is added.

cardbank_transferqropen_bankingwalletinstantlocal
card

Cards

Domestic and international card payments through the acquirers and PSPs connected to your account. Card entry happens on a provider hosted page or is tokenised by a PCI-compliant provider.

bank_transfer

Bank transfer

Push and pull bank transfers where the provider confirms the credit asynchronously. The payment stays processing until the provider notifies NATIO.

qr

QR

QR-based rails: the provider returns a payload and an expiry, which NATIO passes back as a structured next_action for you to render.

open_banking

Open banking

Account-to-account initiation where the customer authorises the payment at their bank. Returned as a redirect next_action.

wallet

Wallets

Wallet balances and wallet-backed rails, typically synchronous: the create response already carries the final status.

instant

Instant rails

Domestic instant payment schemes with near-real-time confirmation from the provider.

local

Local methods

Country-specific methods exposed under one contract. Adding a new one is configuration on the provider side, not a new integration on yours.

Lifecycle

Ten statuses, guarded transitions.

Every payment moves through an explicit state machine. Transitions are validated in code and guarded in the database, so retries and concurrent webhooks cannot produce an invalid path.

StatusMeaning
createdAccepted and persisted. Risk and routing have not produced a provider attempt yet.
pendingWaiting on something outside the request: a manual risk review, or a customer action at the provider.
processingA provider attempt is in flight, or an asynchronous confirmation is outstanding.
authorizedFunds reserved by the provider. Reached only with capture_method: manual; capture or cancel next.
capturedTransitional state while a capture is being confirmed by the provider.
successfulThe provider confirmed the payment. Refundable in full or in part.
failedDeclined, blocked by risk, or every eligible provider failed. Carries a failure object with code, category and message.
cancelledCancelled before completion. Terminal.
refundedRefunds cover the full captured amount. Terminal.
partially_refundedOne or more refunds cover part of the captured amount. Further refunds are allowed up to the remainder.

An invalid transition returns 409 invalid_state_transition. Refunds have their own lifecycle: created → processing → successful or failed.

Operations on a payment

Capture, cancel, refund.

The same three operations exist for every provider, normalised by the adapter layer.

01

Capture

With capture_method: manual the payment stops at authorized. Capture the full amount or less; the remainder is released by the provider.
POST /v1/payments/{id}/capture
02

Cancel

Cancels a payment that has not completed, or voids an authorisation that has not been captured. Terminal once accepted.
POST /v1/payments/{id}/cancel
03

Refund

Full or partial, repeatedly, up to the captured amount. The payment moves to partially_refunded and then refunded; each refund is its own object with its own status.
POST /v1/payments/{id}/refund
Customer action

Redirects and QR codes come back as data.

Asynchronous rails need the customer to do something. NATIO returns that as a structured next_action rather than an HTML page, so you decide how to present it.

redirect
A url to send the customer to, typically a provider hosted page or a bank authorisation screen. You provide return_url on create.
qr_code
A payload to render as a QR code, with an expiry timestamp.
display_details
Instructions to show the customer, such as transfer details for a manual bank payment.
Completion
The payment stays processing until the provider confirms. NATIO then updates the state machine and delivers a signed webhook (payment.successful or payment.failed).
Response · asynchronous rail
{
  "status": "processing",
  "next_action": {
    "type": "qr_code",
    "qrPayload": "00020101021238...",
    "expiresAt": "2026-09-22T10:45:00.000Z"
  }
}
Card data

Hosted pages and tokenisation keep you out of scope.

Card data never touches NATIO. Entry happens on a hosted page operated by a PCI-compliant provider, or is tokenised by that provider in the browser.

What NATIO stores

Token references
Provider-issued tokens and stored payment method ids, usable only by the provider that issued them.
Display metadata
Brand, last four digits and expiry where the provider returns them, for support and reconciliation.
Nothing else
No PAN, no CVV, no magnetic stripe data. The API rejects requests that look like raw card numbers.

What that means for you

SAQ-A scope
Redirecting to a hosted page or using provider tokenisation keeps a merchant integration in the smallest PCI scope. Your own obligations depend on your implementation and your assessor.
Provider-side compliance
Card acceptance, PCI DSS attestation and acquiring are the responsibility of the licensed providers connected to the platform.
No custody
NATIO does not hold or take customer funds. Money moves between you and the licensed providers, which settle directly.
Visibility

Every attempt is on the record.

A payment is not a single provider call. NATIO stores each attempt and the reasoning around it, and exposes both through the API and the dashboard.

01

Attempts array

Provider, account, outcome, provider code and message, fee and latency for every attempt, in order.
02

Timeline

The human-readable narrative: risk evaluated, rule matched, provider selected, request sent, error, fallback, success, webhook queued.
GET /v1/payments/{id}/timeline
03

Transactions

Every movement — payment, refund, payout — written as a transaction row with the provider reference used for reconciliation.
04

Webhooks

payment.created, payment.processing, payment.authorized, payment.successful, payment.failed, payment.cancelled, payment.refunded, signed with HMAC-SHA256.

Send your first test payment.

Create a sandbox account, take a test key and run the full orchestration flow against demo providers — including failover, timeouts and refunds.