Merchant portal

Open Banking collection (merchant)

End customers pay through their bank; funds are credited to the platform’s configured collection account (EUR/GBP). Your merchant account is identified by the API key only. Payers always pass through a StixBNK-hosted checkout before Open Banking (see Hosted checkout).

Introduction

The public API accepts POST requests with a JSON body only. The payee (creditor) account is not chosen by the integrator: the platform applies the server-validated platform collection IBAN (and GBP details where applicable).

Base URL (production). https://stixbnk.com — prepend this host to the paths below (e.g. POST https://stixbnk.com/api/v1/payments/merchant/requests). Use your own host only for local or staging environments.

Quick start

Follow these steps to run a first test payment:

  1. Create an active merchant API key in the portal (Merchant → API Keys) after KYB is approved.
  2. Call POST /api/v1/payments/merchant/requests with amount, currency, market, reference, and a product label (product_name or product.product_name).
  3. Redirect the payer’s browser to the checkout_url from the response — a StixBNK-hosted page (order summary, merchant-of-record notice) — then the payer continues to Open Banking (Tink) or, in sandbox, to the test bank UI.
  4. Configure a webhook in Merchant → Webhooks to receive open_banking.collection.updated.

Prerequisites

API authentication

Send your API key in the X-API-Key header. Requests without a key or with an inactive key receive 400; KYB not approved returns 403 (kyb_not_approved).

Example headers
Content-Type: application/json
X-API-Key: your_merchant_api_key

Create a payment request

Method POST  ·  Path /api/v1/payments/merchant/requests

JSON body — field reference

FieldTypeRequiredDescription
amountnumberYesAmount to collect (e.g. 45.00).
currencystringYesEUR or GBP (GBP requires market GB and platform GBP collection details).
marketstringYesPay Direct market (ISO 3166-1 alpha-2, e.g. FR, IT, GB for GBP).
referencestringYesYour business reference — must be globally unique across all Open Banking collections and must not collide with an existing platform transaction reference.
product_namestringYes*Product or line-item label (max 255 characters). Stored with the request and shown in the portal under transaction Line item. *Required unless you send product.product_name instead (see product).
productobjectNoAlternative to top-level product_name: { "product_name": "Your label" }. Must be a JSON object when present; invalid shapes are rejected.
descriptionstringNoHuman-readable payment description (defaults if omitted).
localestringNoTink Link locale (e.g. en_US, fr_FR). If omitted, language may be mapped.
customer_emailstringNoMust be a valid email when provided.
customer_first_namestringNoPayer first name (alias: customer_firstname).
customer_lastnamestringNoPayer last name. Alias: customer_last_name.
languagestringNoShort code (e.g. en, fr); used to build a Tink locale when locale is not sent.
store_namestringNoStore or sub-brand label (stored for portal / logging; shown on the hosted checkout when provided).
success_urlstringNoAbsolute https URL (or http in dev). Browser redirect when the payment ends in a success terminal state. Alias: urlok.
failure_urlstringNoAbsolute URL for failure / cancel / error terminal outcomes. Alias: urlko.

The product label is persisted for the portal and API logs; optional customer and store fields are also stored for the portal and request logs. None of these override the creditor account.

Example JSON body (Postman)
{
  "amount": 45.00,
  "currency": "EUR",
  "market": "FR",
  "reference": "postman-merchant-014",
  "product_name": "Example product",
  "description": "Test Postman",
  "customer_email": "payer@example.com",
  "customer_lastname": "Doe",
  "customer_first_name": "John",
  "language": "en",
  "store_name": "Example Store",
  "success_url": "https://stixbnk.com/success",
  "failure_url": "https://stixbnk.com/failed"
}
Same body via cURL
curl -sS -X POST "https://stixbnk.com/api/v1/payments/merchant/requests" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your_key" \
  -d '{
  "amount": 45.00,
  "currency": "EUR",
  "market": "FR",
  "reference": "postman-merchant-014",
  "product_name": "Example product",
  "description": "Test Postman",
  "customer_email": "payer@example.com",
  "customer_lastname": "Doe",
  "customer_first_name": "John",
  "language": "en",
  "store_name": "Example Store",
  "success_url": "https://stixbnk.com/success",
  "failure_url": "https://stixbnk.com/failed"
}'

Equivalent: "product": { "product_name": "Example product" } at the root (omit top-level product_name when you use this object).

Success response

JSON
{
  "success": true,
  "payment_request_id": "33ec136e91cf4cd7bfc5919d27940f44",
  "checkout_url": "https://stixbnk.com/checkout/payment/?pr=33ec136e91cf4cd7bfc5919d27940f44",
  "checkout_expires_at": "2026-03-25T14:30:00Z",
  "funds_destination": "stixbnk"
}

funds_destination is always stixbnk for the merchant API: funds are collected for StixBNK (platform collection account). After checkout_expires_at (UTC, ISO8601), or once the payment is in a final state, the checkout URL returns HTTP 410 and cannot be used.

When you send "sandbox": true, the JSON success body also includes "sandbox": true and payment_request_id values start with sb_.

Hosted checkout (StixBNK)

Do not send payers straight from your site to Tink. The API returns an absolute checkout_url on the StixBNK host so the payer sees who they are paying before authorising the bank transfer.

Integration sandbox (no real bank)

Use the same endpoint (POST /api/v1/payments/merchant/requests) with "sandbox": true in the JSON body to test redirects, return URLs, webhooks, and completed / failed transaction states without calling Tink. The integration sandbox is available for testing in all environments.

Example request (sandbox)

Same POST URL and X-API-Key header as production. Add "sandbox": true to the JSON body. Each test still needs a unique reference (same rules as live).

JSON body (sandbox) — Postman
{
  "sandbox": true,
  "amount": 45.00,
  "currency": "EUR",
  "market": "FR",
  "reference": "postman-merchant-sandbox-001",
  "product_name": "Sandbox test product",
  "description": "Integration test via StixBank Sandbox",
  "customer_email": "payer@example.com",
  "customer_lastname": "Doe",
  "customer_first_name": "John",
  "language": "en",
  "store_name": "Example Store",
  "success_url": "https://stixbnk.com/success",
  "failure_url": "https://stixbnk.com/failed"
}
Same sandbox request — cURL
curl -sS -X POST "https://stixbnk.com/api/v1/payments/merchant/requests" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your_key" \
  -d '{
  "sandbox": true,
  "amount": 45.00,
  "currency": "EUR",
  "market": "FR",
  "reference": "postman-merchant-sandbox-001",
  "product_name": "Sandbox test product",
  "description": "Integration test via StixBank Sandbox",
  "customer_email": "payer@example.com",
  "customer_lastname": "Doe",
  "customer_first_name": "John",
  "language": "en",
  "store_name": "Example Store",
  "success_url": "https://stixbnk.com/success",
  "failure_url": "https://stixbnk.com/failed"
}'

Example success response (sandbox)

payment_request_id starts with sb_; checkout_url points to /checkout/sandbox/ on your host, then Open bank simulator leads to /sandbox/ob_bank.php for the fake bank flow.

JSON (illustrative)
{
  "success": true,
  "payment_request_id": "sb_a1b2c3d4e5f678901234567890abcdef12",
  "checkout_url": "https://stixbnk.com/checkout/sandbox/?pr=sb_a1b2c3d4e5f678901234567890abcdef12",
  "checkout_expires_at": "2026-03-25T14:30:00Z",
  "funds_destination": "stixbnk",
  "sandbox": true
}

Browser return after payment

After the payer completes hosted checkout and the bank flow (Tink or sandbox), Tink (or the sandbox handler) returns the shopper to the platform-configured Pay Direct return URL (merchant callback). After status sync, the browser may be redirected (302) to your success_url or failure_url when the payment reaches a terminal state. Query parameters are appended, including payment_request_id, reference, ob_status, and transaction_id when available.

Do not rely on this redirect alone to confirm funds: use webhooks and/or server-side verification as appropriate.

Outbound webhooks

When the collection or linked transaction is updated (callback, provider sync), the platform sends open_banking.collection.updated to each active endpoint configured in Merchant → Webhooks.

HTTP request

Verify the signature on the raw string before parsing JSON to avoid whitespace mismatches.

Event envelope
{
  "id": "evt_…",
  "type": "open_banking.collection.updated",
  "created": 1774451228,
  "data": { /* see table below */ }
}

HMAC verification (example)

PHP
$raw = file_get_contents('php://input');
$sig = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $raw, $endpointSecret);
$ok = hash_equals($expected, $sig);

data object reference

FieldDescription
sourceAlways open_banking for this event.
actor_typemerchant for payments created via the merchant API.
payment_request_idPayment request id (matches API response).
referenceBusiness reference from creation.
amount / currencyAmount and currency.
marketMarket (may be null).
collection_statusPlatform collection status.
transfer_statusRaw bank transfer status from the provider (e.g. SENT, COMPLETED), or null.
transaction_idInternal transaction id when linked.
linked_merchant_idFor direct merchants this is typically null (reseller sub-merchants populate this).
callback_error / callback_error_reasonCallback error details when present.
transaction_statusLinked transaction status when applicable.
sandboxtrue when the payment was created with "sandbox": true (integration simulator). Omitted for live Tink flows.

Respond with 2xx promptly; non-success responses may be logged for manual retry according to platform policy.

Common errors