Nova
Developers · Reference

One gateway. Cards, remittance, ledger.

All merchant endpoints live under /shop/**. Authenticate with X-Shop-No and X-Public-Key, send JSON, receive a unified { code, message, data } envelope. 60s timeout, HTTPS only.

The following content consists of reference snippets only. For the complete documentation, please contact our Sales team to complete verification and access.

1. Request headers

All /shop/** endpoints require two headers. Header names are case-insensitive; HTTPS is strongly recommended to prevent header interception.

curl -X GET "https://api.nova.dev/shop/account" \
  -H "X-Shop-No: NOVA20260114012345" \
  -H "X-Public-Key: 7c9c9e7b-a8d2-4f1c-9b3e-2a91f4d0e7c4"

2. Authentication

The gateway reads X-Shop-No and X-Public-Key, resolves the merchant from cache or database, and verifies that the supplied public key matches the one bound to the shop. Missing header → 400. Mismatch or unknown shop → 401. Disabled merchant or IP not whitelisted → 403. On success the merchant context is injected for downstream services.

3. Unified response envelope

Every business endpoint returns Response<T> with three fields: code (200 = success, anything else = business failure), message, and data (object, array, or paginated structure; may be null on failure).

{
  "code": 200,
  "message": "operation successful",
  "data": {
    "id": "card_8fK3",
    "status": "ACTIVE"
  }
}

{
  "code": 999,
  "message": "operation failed",
  "data": null
}

4. HTTP status codes

200 — request reached the business layer; check response.code. 400 — missing/invalid headers or parameters. 401 — bad shop number or public key. 403 — merchant disabled, or blocked by IP whitelist. 500 — uncaught platform exception. Always inspect the HTTP status first, then response.code.

GET /shop/account

Returns the merchant account profile: shop number, display name, account currencies, limits, KYB tier, and the timestamp of the last successful authentication.

GET /shop/card/bin/list

Lists the BIN segments currently open for this merchant. Use the returned bin + currency tuple as input to POST /shop/card/create.

GET /shop/card/bin/list

{
  "code": 200,
  "message": "operation successful",
  "data": [
    { "bin": "428392", "brand": "VISA",       "currency": "USD", "type": "VIRTUAL" },
    { "bin": "555512", "brand": "MASTERCARD", "currency": "USD", "type": "VIRTUAL" },
    { "bin": "517843", "brand": "MASTERCARD", "currency": "EUR", "type": "VIRTUAL" }
  ]
}

POST /shop/card/create

Issues a new virtual card on the chosen BIN. The created amount is debited from the merchant's funding account in the same currency. Result is delivered both synchronously and asynchronously via the card-create callback.

POST /shop/card/create
Content-Type: application/json
X-Shop-No: NOVA20260114012345
X-Public-Key: 7c9c9e7b-...

{
  "bin": "428392",
  "currency": "USD",
  "amount": 5000,
  "remark": "ads-google-q2",
  "callback_url": "https://merchant.example.com/hooks/card"
}

GET /shop/card/info

Retrieves the full card object by cardNo, including PAN reference (PCI-scoped), last4, status, balance and currency.

GET /shop/card/info?cardNo=tok_8fK3...

{
  "code": 200,
  "message": "operation successful",
  "data": {
    "cardNo":   "tok_8fK3a91c",
    "last4":    "4242",
    "status":   "ACTIVE",
    "balance":  5000.00,
    "currency": "USD",
    "createdAt":"2026-06-05T12:04:17Z"
  }
}

GET /shop/card/balance

Returns the live spendable balance. For bulk reads use POST /shop/card/balance/batch with up to 100 cardNos per call.

GET /shop/card/balance?cardNo=tok_8fK3a91c

{ "code": 200, "data": { "balance": 4127.55, "currency": "USD" } }

POST /shop/card/freeze · /shop/card/unfreeze

Toggles the card to FROZEN or back to ACTIVE. Idempotent on (cardNo, state). Authorization attempts on a frozen card return decline code 57 (transaction not permitted).

POST /shop/card/freeze

{ "cardNo": "tok_8fK3a91c", "reason": "user_requested" }

→ { "code": 200, "message": "operation successful", "data": null }

POST /shop/card/cancel

Permanently cancels the card. Remaining balance is refunded to the merchant funding account in the original currency. Irreversible.

POST /shop/card/cancel

{ "cardNo": "tok_8fK3a91c" }

→ { "code": 200, "message": "operation successful", "data": null }

POST /shop/card/transfer

Tops up (direction=IN) or withdraws (direction=OUT) funds between the merchant account and the card. Same-currency transfers settle synchronously; cross-currency transfers expose the executed FX rate in the response.

POST /shop/card/transfer

{
  "cardNo":   "tok_8fK3a91c",
  "amount":   250.00,
  "currency": "USD",
  "direction":"IN"
}

POST /shop/remittance/create

Initiates a global remittance via SWIFT, SEPA or local rails depending on corridor. Call GET /shop/remittance/dynamic-fields first to obtain the required beneficiary fields for the destination country.

POST /shop/remittance/create

{
  "payer_id":      "biz_91823",
  "beneficiary": {
    "name":        "ACME LTD",
    "country":     "GB",
    "bank_swift":  "BARCGB22",
    "account_no":  "GB29NWBK60161331926819"
  },
  "amount":   12500.00,
  "currency": "USD",
  "purpose":  "INVOICE_SETTLEMENT"
}

GET /shop/remittance/query

Returns the lifecycle state of a remittance: SUBMITTED → SCREENING → IN_FLIGHT → SETTLED or RETURNED. Status changes are also pushed via the remittance-status callback.

GET /shop/remittance/query?txId=remit_7c2a91d

{
  "code": 200,
  "data": {
    "txId":     "remit_7c2a91d",
    "status":   "SETTLED",
    "amount":   12500.00,
    "currency": "USD",
    "settledAt":"2026-06-05T14:22:08Z"
  }
}

GET /shop/bill/list

Paginated reconciliation export covering all account movements: card authorizations, settlements, remittance debits, fees and reversals. Cursor-stable across new inserts.

GET /shop/bill/list?startDate=2026-06-01&endDate=2026-06-30&page=1&size=50

{
  "code": 200,
  "data": {
    "total": 1248,
    "list": [
      { "billId":"b_01H8...", "type":"CARD_AUTH", "amount":-12.50, "currency":"USD", "ts":"2026-06-05T11:02:14Z" },
      { "billId":"b_01H9...", "type":"REMIT_OUT", "amount":-12500.00,"currency":"USD","ts":"2026-06-05T14:22:08Z" }
    ]
  }
}

Callback signature flow

Every callback carries X-Sign and X-Timestamp headers. Recompute sha256(rawBody + timestamp + your_private_key) and compare in constant time. Acknowledge with HTTP 200 + { code: 200 } within 5 seconds; the platform retries with exponential backoff up to 24 hours.

// 1. Concatenate body + timestamp + your shop private key
// 2. SHA-256 the result → hex string → compare with X-Sign header

const expected = sha256(rawBody + timestamp + SHOP_PRIVATE_KEY);
if (expected !== req.headers["x-sign"]) {
  return res.status(401).send("invalid signature");
}
// Acknowledge within 5s, idempotent on (event_id)
res.status(200).json({ code: 200 });
$ curl · POST /shop/card/create
$ export NOVA_SHOP_NO=NOVA20260114012345
$ export NOVA_PUBLIC_KEY=7c9c9e7b-a8d2-4f1c-9b3e-2a91f4d0e7c4

$ curl -X POST https://api.nova.dev/shop/card/create \
    -H "Content-Type: application/json" \
    -H "X-Shop-No:     $NOVA_SHOP_NO" \
    -H "X-Public-Key:  $NOVA_PUBLIC_KEY" \
    -d '{
      "bin":      "428392",
      "currency": "USD",
      "amount":   5000,
      "remark":   "ads-google-q2"
    }'

{
  "code": 200,
  "message": "operation successful",
  "data": {
    "cardNo":   "tok_8fK3a91c",
    "last4":    "4242",
    "status":   "ACTIVE",
    "currency": "USD",
    "balance":  5000.00
  }
}

Paste into a sandbox key — response back in seconds.