Skip to main content
POST
/
merchant
/
api
/
v1
/
scan-payment
curl --request POST \
  --url http://api-sandbox.fexpayments.com/merchant/api/v1/scan-payment \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "scan_token": "8566959d-f366-45d9-9e6e-241ba189988f",
  "counter_id": "c1d2e3f4-a5b6-7890-abcd-ef1234567890",
  "amount": 35.5,
  "currency": "USD",
  "description": "Lunch combo"
}
'
{
  "success": true,
  "payment_intent": {
    "id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    "merchant_id": "74815c83-e47b-4dc5-aefe-abe4484dd280",
    "amount": 99.99,
    "currency": "USD",
    "status": "pending",
    "expires_at": "2026-02-24T14:30:00Z",
    "merchant_name": "Whole Foods Market",
    "description": "Coffee and pastry",
    "qr_code_url": "data:image/png;base64,iVBORw0KGgo...",
    "qr_data": "{\"payment_intent_id\":\"abc123\",\"amount\":99.99,\"currency\":\"USD\",\"merchant_id\":\"...\",\"merchant_name\":\"Whole Foods Market\"}",
    "target_wallet_id": "8566959d-f366-45d9-9e6e-241ba189988f",
    "completed_by": "d9f3a2b1-c4e5-6789-abcd-ef0123456789",
    "refund_status": "pending",
    "refund_ledger_tx_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "counter_id": "c1d2e3f4-a5b6-7890-abcd-ef1234567890",
    "reference": "ORD-12345",
    "callback_url": "https://shop.example.com/orders/ORD-12345/payment-callback",
    "metadata": {
      "customer_email": "alice@example.com",
      "cart_id": "cart-abc123"
    },
    "created_at": "2026-02-24T14:00:00Z",
    "updated_at": "2026-02-24T14:00:00Z"
  }
}

Authorizations

Authorization
string
header
required

Keycloak JWT. Roles: admin (platform admin — can register merchants, act on behalf of any merchant), merchant (dashboard user — scoped to their own merchant_id via user attribute mapper), POS terminals use client credentials flow with merchant_id injected via protocol mapper.

Body

application/json

Request body for counter-initiated (reverse QR) payment. counter_id is required and validated server-side to confirm it belongs to the authenticated merchant.

scan_token
string<uuid>
required

Token read from the user's QR code (currently equals the user's wallet ID).

Example:

"8566959d-f366-45d9-9e6e-241ba189988f"

counter_id
string<uuid>
required

POS terminal identity — must belong to the authenticated merchant.

Example:

"c1d2e3f4-a5b6-7890-abcd-ef1234567890"

amount
number<double>
required
Required range: x >= 0.01
Example:

35.5

currency
string
default:USD
Example:

"USD"

description
string
Example:

"Lunch combo"

expires_in
integer
default:300

Seconds until approval expires (default: 300 — 5 minutes)

Required range: x >= 30
Example:

300

reference
string | null

Merchant's own order or invoice ID.

Example:

"ORD-9001"

callback_url
string<uri> | null

Per-intent webhook override URL.

Example:

"https://pos.example.com/webhooks/ORD-9001"

metadata
object

Arbitrary JSON metadata forwarded verbatim in the webhook payload.

Example:
{ "table": "T12", "cashier": "Jane" }

Response

Payment intent created — awaiting user approval on mobile app

success
boolean
Example:

true

payment_intent
object