Skip to main content
Nuvion supports three ways to accept payments from your users: directly into provisioned account details shared with the payer, a hosted bank transfer checkout that handles the full authentication flow, and a direct card acquiring API for platforms that want to collect card details themselves.

Accept via account details

Entities can receive funds directly into their Nuvion account using provisioned banking coordinates — no hosted checkout or payment session required. Share the account details with your payer and Nuvion notifies you via webhook when funds arrive.
Provision account details for an entity’s account using POST /account-details. Use asset_type: fiat for banking coordinates or asset_type: stablecoin for a wallet address. See Account Details for the full guide.

How it works

  1. Provision account details for the entity (POST /account-details, asset_type: fiat or stablecoin).
  2. Share the returned banking coordinates — account number, sort code or routing number, BIC/SWIFT — with the payer.
  3. The payer initiates a bank transfer from their own bank to those coordinates.
  4. Nuvion credits the entity’s account and fires inflows.completed.

Webhook: inflows.completed

Listen for inflows.completed to be notified when funds arrive. This is the authoritative signal that the account has been credited.
{
  "event": "inflows.completed",
  "data": {
    "id": "01K6ZXCNMVA04GM3WQRCKQNCMB",
    "amount": 10000,
    "currency": "USD",
    "unique_reference": "01K6ZX7360026KPNA2SQ6NPNZY-1759504425996",
    "counterparty_id": "acct-01K6ZX7360026KPNA2SQ6NPNZY",
    "account_id": "acc_01HXYZ5678EFGH",
    "entity_id": "ent_01HXYZ1234ABCD",
    "status": "successful",
    "status_reason": "Successful.",
    "narration": "Invoice payment received",
    "type": "inflow",
    "applicable_fee": 0,
    "meta": {},
    "created": 1759860119195,
    "updated": 1759860119195
  }
}
id
string
Unique identifier for the inflow transaction.
amount
number
Amount received in the smallest currency unit. e.g. 10000 = $100.00 USD.
currency
string
ISO 4217 currency code of the received funds.
unique_reference
string
Idempotency reference for the transaction. Use this to deduplicate webhook deliveries.
counterparty_id
string
Identifier for the sender’s account.
account_id
string
The ID of the Nuvion account that was credited.
entity_id
string
The ID of the entity whose account was credited.
status
string
Always successful for this event.
narration
string
Payment reference provided by the sender.
applicable_fee
number
Fee applied to the inflow in the smallest currency unit.
type
string
Always inflow.

Accept via bank transfer

Nuvion hosts the bank transfer checkout page. Your server creates a funding session, redirects the user to the hosted URL, and receives a webhook when funds settle. Supported currencies: GBP, EUR

Create a funding session

curl -X POST https://api.nuvion.dev/v1/funding-sessions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "currency": "GBP",
    "account_id": "acc_01HXYZ5678EFGH",
    "redirect_url": "https://yourplatform.com/checkout/complete",
    "unique_reference": "order-2025-001",
    "narration": "Payment for Order #1042"
  }'
amount
number
required
Amount in the smallest currency unit. 10000 = £100.00 GBP. Minimum: 1.
currency
string
required
ISO 4217 currency code. One of GBP, EUR.
account_id
string
required
The ID of the account to credit when the payment settles.
redirect_url
string
required
HTTPS URL to redirect the user to after they complete or abandon the checkout. Must use HTTPS.
unique_reference
string
required
A unique idempotency key for this session. 1–255 characters. Submitting a duplicate reference returns a 409 with the original session’s payment_id.
narration
string
Display text shown to the user on the checkout page. Max 255 characters.
country_code
string
ISO 3166-1 alpha-2 country code of the payer. e.g. GB, DE. Used to tailor the checkout experience to the payer’s country.
meta
object
Optional key-value metadata to attach to the session.
{
  "payment_id": "fps_01HXYZ9012MNOP",
  "checkout_url": "https://checkout.nuvion.co/pay/fps_01HXYZ9012MNOP",
  "amount": 10000,
  "currency": "GBP",
  "account_id": "acc_01HXYZ5678EFGH",
  "status": "awaiting_user",
  "unique_reference": "order-2025-001",
  "expires_at": 1735729200000,
  "created": 1735725600000,
  "updated": 1735725600000
}

Redirect the user

Redirect your user to the checkout_url returned in the response. Nuvion handles bank authentication, authorisation, and error states on the hosted page.
Checkout URLs expire. Check expires_at and regenerate the session if the user returns after expiry.

Handle the return

When the user completes or abandons the checkout, they are redirected to your redirect_url. Do not treat the redirect as confirmation of payment — always verify status via webhook or API.
Never fulfil an order based on the redirect alone. Always confirm status via the funding_session.updated webhook or by fetching the session.

Check session status

curl https://api.nuvion.dev/v1/funding-sessions/fps_01HXYZ9012MNOP \
  -H "Authorization: Bearer $NUVION_API_KEY"

Funding session statuses

StatusTerminalDescription
awaiting_userNoSession created, user has not started
processingNoUser has initiated the bank transfer
pending_settlementNoTransfer accepted by the bank, awaiting settlement
settledYesFunds credited to the account
failedYesTransfer rejected by the bank
expiredYesSession expired before the user completed payment
cancelledYesSession was cancelled
When failed, the response includes a failure_code:
CodeRetryableReason
insufficient_fundsYesPayer account has insufficient funds
bank_rejectedYesBank rejected the transfer
account_closedNoPayer account is closed
authorization_revokedNoAuthorisation was revoked
provider_errorYesInternal provider error

Webhook

Listen for funding_session.updated to receive real-time status changes. Nuvion retries webhook delivery for 72 hours with exponential backoff.

Accept via card

Nuvion’s card acquiring API uses a two-step flow: create a Payment Intent to declare the charge, then submit an Intent Action to execute it with the card details.

Step 1: Create a payment intent

A Payment Intent represents your intent to charge a card. No funds are moved at this stage.
curl -X POST https://api.nuvion.dev/payment-intents \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USD",
    "amount": 5000,
    "account_id": "acc_01HXYZ5678EFGH",
    "reference": "order_abc123",
    "description": "Order #1042"
  }'
currency
string
required
ISO 4217 currency code. e.g. USD.
amount
number
required
Amount in the smallest currency unit. 5000 = $50.00 USD.
account_id
string
required
The ID of the account to credit on successful charge.
reference
string
required
Your internal order or transaction reference.
description
string
A human-readable description shown in the Nuvion dashboard.
{
  "id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "currency": "USD",
  "amount": 5000,
  "reference": "order_abc123",
  "description": "Order #1042",
  "status": "requires_action",
  "status_reason": null,
  "entity_id": "ent_01HXYZ1234ABCD",
  "account_id": "acc_01HXYZ5678EFGH",
  "intent_action": null,
  "metadata": null,
  "created": 1735725600000,
  "updated": 1735725600000
}
The intent is created with status: requires_action. No charge happens until you submit an Intent Action.

Step 2: Submit an intent action

Submit the card details against the intent using POST /intent-actions. Card data must be encrypted using Nuvion’s public key before submission.

Without 3DS

Use this path when the card does not require strong customer authentication.
curl -X POST https://api.nuvion.dev/intent-actions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "card-acq",
      "payment_type_data": {
        "data": "<base64_encrypted_card_data>",
        "billing_address": {
          "address_line_one": "350 Fifth Avenue",
          "city": "New York",
          "state": "NY",
          "country": "US",
          "zip": "10001"
        }
      }
    },
    "description": "Order #1042",
    "return_url": "https://yourplatform.com/checkout/complete"
  }'
{
  "id": "01HACT9012EFGH",
  "currency": "USD",
  "amount": 5000,
  "applicable_fee": 75,
  "charge_amount": 5075,
  "reference": "order_abc123",
  "intent_action": {
    "action": "confirm",
    "category": "collections",
    "payment_type": "card-acq"
  },
  "status": "completed",
  "status_reason": null,
  "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "provider_reference": "ch_3PxYzA2eZvKYlo2C1a2b3c4d",
  "completed_at": 1735725645000,
  "created": 1735725600000,
  "updated": 1735725645000
}
charge_amount is the total debited from the card — amount plus applicable_fee. Save provider_reference for reconciliation with your payment processor records.

With 3DS

Include browser_info collected from the cardholder’s browser to enable 3DS authentication. If the issuer requires a challenge, the response returns status: pending_user_action and a next_action.url to redirect the cardholder to.
curl -X POST https://api.nuvion.dev/intent-actions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "card-acq",
      "payment_type_data": {
        "data": "<base64_encrypted_card_data>",
        "billing_address": {
          "address_line_one": "350 Fifth Avenue",
          "city": "New York",
          "state": "NY",
          "country": "US",
          "zip": "10001"
        },
        "browser_info": {
          "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
          "language": "en-US",
          "color_depth": "24",
          "screen_height": "900",
          "screen_width": "1440",
          "timezone_offset": "-300",
          "java_enabled": false,
          "javascript_enabled": true,
          "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
        }
      }
    },
    "description": "Order #1042",
    "return_url": "https://yourplatform.com/checkout/complete"
  }'
{
  "id": "01HACT9012EFGH",
  "currency": "USD",
  "amount": 5000,
  "reference": "order_abc123",
  "status": "pending_user_action",
  "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
  "return_url": "https://yourplatform.com/checkout/complete",
  "next_action": {
    "type": "redirect_to_url",
    "url": "https://3ds.nuvion.co/challenge/01HACT9012EFGH"
  },
  "completed_at": null,
  "created": 1735725600000,
  "updated": 1735725600000
}
Redirect the cardholder to next_action.url. After the 3DS challenge completes, they are sent to your return_url. Listen for payment_intent.completed or payment_intent.failed to confirm the outcome.

Apple Pay

For Apple Pay, set payment_type to applepay-acq. The payment_type_data does not require a data field — only billing_address.
curl -X POST https://api.nuvion.dev/intent-actions \
  -H "Authorization: Bearer $NUVION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_intent_id": "01HXYZ7K3M9PQRST4UVWXY2Z6",
    "intent_action": {
      "action": "confirm",
      "category": "collections",
      "payment_type": "applepay-acq",
      "payment_type_data": {
        "billing_address": {
          "address_line_one": "350 Fifth Avenue",
          "city": "New York",
          "state": "NY",
          "country": "US",
          "zip": "10001"
        }
      }
    },
    "description": "Order #1042",
    "return_url": "https://yourplatform.com/checkout/complete"
  }'

Intent action parameters

payment_intent_id
string
required
The ID of the Payment Intent to charge against.
intent_action.action
string
required
Always confirm.
intent_action.category
string
required
Always collections.
intent_action.payment_type
string
required
The payment method. One of card-acq or applepay-acq.
intent_action.payment_type_data.data
string
Base64-encoded encrypted card data. Required for card-acq.
intent_action.payment_type_data.billing_address
object
required
Cardholder billing address. Fields: address_line_one, city, state, country, zip.
intent_action.payment_type_data.browser_info
object
Browser fingerprint for 3DS authentication. Include to enable 3DS. Fields: user_agent, language, color_depth, screen_height, screen_width, timezone_offset, java_enabled, javascript_enabled, accept_header.
return_url
string
required
URL to redirect the cardholder to after 3DS completes.

Payment intent statuses

StatusDescription
requires_actionIntent created — no action submitted yet
pending_user_actionAwaiting 3DS completion from the cardholder
completedCharge successful
failedPayment could not be completed — check status_reason

Webhooks

EventTrigger
payment_intent.completedCharge successful — funds credited to the account
payment_intent.failedCharge declined or failed

What’s next

Send a payout

Send funds from an account to any bank account globally.

Stablecoins

Accept USDC and USDT via a provisioned wallet address.

Transfers API reference

Full endpoint documentation for payment intents and transfers.