Orders

Create an order from a quote, then track any order to settlement.

An order moves one payment from the customer to its destination. An onramp collects naira and delivers a stablecoin. An offramp collects a stablecoin and delivers naira. Orders come from two sources.

SourceHow the order startsFirst event
You create it from a quotePOST /v1/onramp/orders or POST /v1/offramp/ordersorder.awaiting_payment
A payment to a collectionPulse creates the order when the payment arrives: an offramp for a stablecoin deposit, an onramp for a naira transferorder.payment_received, or order.held

This page covers orders that you create. You read and track both kinds the same way. See Order status and Track an order.

Create an order

Create each order from an unused quote in the same direction. The quote sets the rate, the stablecoin, and the network. The network is the blockchain that the stablecoin moves on, such as POLYGON.

Every order takes these fields:

  • reference: your ID for the order, up to 128 characters. It must be unique across onramp and offramp orders, and it makes the request safe to retry. See Idempotency.
  • quote_id: the quote.
  • payer, on an onramp only: the customer who sends the naira.
  • The payout: destination on an onramp, beneficiary on an offramp, or recipient_id for a payout account.

payer and beneficiary carry the customer's nin and bvn, 11 digits each, for regulatory purposes. Pulse encrypts both at rest and omits them from API responses.

Create an onramp order

An onramp order gives the customer a bank account for one naira transfer. Pulse then sends the stablecoin to a wallet address: the customer's, or a payout account.

curl https://engine-api.pilot.pulseshiga.io/v1/onramp/orders \
  -H "X-API-Key: <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "partner-order-88213",
    "quote_id": "0198e2c1-…",
    "payer": {
      "name": "Ada Obi",
      "email": "ada@example.com",
      "nin": "12345678901",
      "bvn": "22345678901"
    },
    "destination": { "address": "0xAbC…" }
  }'

The response has status awaiting_payment. Show the customer funding_account. See Fund the order.

{
  "status": true,
  "data": {
    "id": "0198e2d0-…",
    "reference": "partner-order-88213",
    "type": "onramp",
    "status": "awaiting_payment",
    "rate": "1538.46",
    "source": { "currency": "NGN", "amount": "150000" },
    "destination": { "currency": "USDT", "network": "POLYGON", "amount": "97.500097" },
    "party": { "name": "Ada Obi", "email": "ada@example.com" },
    "funding_account": {
      "account_name": "Ada Obi",
      "account_number": "9901234567",
      "bank_code": "090175",
      "bank_name": "Rubies MFB",
      "amount": "150000"
    },
    "expires_at": "2026-07-30T12:12:00Z",
    "created_at": "…",
    "updated_at": "…"
  }
}

Pulse sends the stablecoin to destination.address on the quoted network. An address that is not valid for that network returns invalid_destination_address. See address formats.

Create an offramp order

An offramp order gives the customer a deposit address: a wallet address that Pulse issues for this order. The customer sends the stablecoin to it, and Pulse pays naira to a bank account: the customer's, or a payout account.

Resolve the account first to get its registered name. Ask the customer to confirm the name before you create the order.

curl https://engine-api.pilot.pulseshiga.io/v1/offramp/orders \
  -H "X-API-Key: <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "partner-order-88214",
    "quote_id": "0198e3f2-…",
    "beneficiary": {
      "name": "Ada Obi",
      "email": "ada@example.com",
      "nin": "12345678901",
      "bvn": "22345678901",
      "bank_account": {
        "bank_code": "058",
        "account_number": "0123456789"
      }
    }
  }'

The response has status awaiting_payment. Show the customer funding_account. See Fund the order.

{
  "status": true,
  "data": {
    "id": "0198e400-…",
    "reference": "partner-order-88214",
    "type": "offramp",
    "status": "awaiting_payment",
    "rate": "1366.75",
    "source": { "currency": "USDT", "network": "POLYGON", "amount": "102.432779" },
    "destination": { "currency": "NGN", "amount": "140000" },
    "party": { "name": "Ada Obi", "email": "ada@example.com" },
    "funding_account": {
      "deposit_address": "0xDeF…",
      "network": "POLYGON"
    },
    "expires_at": "2026-07-30T12:14:00Z",
    "created_at": "…",
    "updated_at": "…"
  }
}

Order creation verifies the beneficiary's 10-digit account number. An unconfirmed account returns account_verification_failed without creating an order.

Name a payout account on an order

If Pulse set up your business to pay out only to your own accounts, name a payout account on each order with recipient_id:

  • An offramp order sends recipient_id instead of beneficiary. The account must be a bank_account. Pulse still verifies it with the bank.
  • An onramp order sends recipient_id instead of destination, and still sends payer. The account must be a crypto_address with the quote's network and stablecoin.

Send recipient_id or the payout details, never both. A request with both, or with neither, returns 400 bad_request.

The order keeps the account details from the moment you create it. If an admin replaces the account, the order still pays those details. The old recipient_id then returns recipient_not_found, so use the new id for new orders.

See Errors for the codes.

Fund the order

Every order that you create carries its payment instructions in funding_account: on create, on read, and on the order.awaiting_payment event. The shape depends on the order type, so switch on type before you read it.

typefunding_account fieldsThe customer
onrampaccount_name, account_number, bank_code, bank_name, amountTransfers exactly amount in naira.
offrampdeposit_address, networkSends the quoted stablecoin to deposit_address on network.

A short naira transfer does not fund an onramp order. For an offramp, Pulse applies the order rate to the stablecoin received, so the naira payout changes with the amount received. The list endpoint is a summary and omits funding_account.

Send on the quoted network

Send the stablecoin on the quoted network. A deposit on any other network cannot be recovered.

Funding window

Every order carries an expires_at. An offramp order counts 30 minutes from creation. An onramp order counts 30 minutes from the moment its virtual account is issued, so a delayed account still gives the customer the full window.

Pulse uses the quote rate when funding arrives within 15 minutes. For funding that arrives later in the window, it can use the current rate. The order shows the rate and amount that Pulse used.

Funding that arrives after expires_at does not complete the order. Create a new quote and order, and contact support about the late payment.

Order status

An order has one of six statuses. The path depends on the source.

Order status state terminal
Any status before completed can end in failed instead.
StatusMeaningTerminal
awaiting_paymentWaiting for the customer's naira transfer or stablecoin deposit.no
processingFunds received. Pulse converts and settles the funds.no
completedSettled to the destination.yes
expiredNever funded in time.yes
failedCould not be settled.yes
heldPulse could not process a collection payment automatically, and holds the funds for review. See Held payments.no

An order from a collection payment never has awaiting_payment or expired, because the payment arrives before the order exists. Only an order from a collection payment can be held.

Each status change also sends a webhook.

Track an order

Track an order in one of two ways:

curl https://engine-api.pilot.pulseshiga.io/v1/orders/0198e2d0-… \
  -H "X-API-Key: <your key>"
{
  "status": true,
  "data": {
    "id": "0198e2d0-…",
    "reference": "partner-order-88213",
    "type": "onramp",
    "status": "processing",
    "rate": "1538.46",
    "source": { "currency": "NGN", "amount": "150000" },
    "destination": { "currency": "USDT", "network": "POLYGON", "amount": "97.500097" },
    "party": { "name": "Ada Obi", "email": "ada@example.com" },
    "funding_account": {
      "account_name": "Ada Obi",
      "account_number": "9901234567",
      "bank_code": "090175",
      "bank_name": "Rubies MFB",
      "amount": "150000"
    },
    "expires_at": "2026-07-30T12:12:00Z",
    "created_at": "…",
    "updated_at": "…"
  }
}

The API key scopes the request to your business. An unknown order and another business's order both return 404 order_not_found.

An order from a quote with a partner fee also returns partner_fee. An order from a collection payment also returns collection_id.

Order terms can differ from the quote

Reconcile with the order's rate and destination.amount, not the quote's. Late funding can change both. Confirm the delivered amount from order.completed.

In the test environment, trigger each outcome on purpose. See Testing.

List orders

List orders to reconcile a period or find an order by reference. Results are ordered from newest to oldest.

curl "https://engine-api.pilot.pulseshiga.io/v1/orders?type=onramp&per_page=20" \
  -H "X-API-Key: <your key>"
{
  "status": true,
  "data": [
    {
      "id": "0198e2d0-…",
      "reference": "partner-order-88213",
      "type": "onramp",
      "status": "completed",
      "rate": "1538.46",
      "source": { "currency": "NGN", "amount": "150000" },
      "destination": { "currency": "USDT", "network": "POLYGON", "amount": "97.500097" },
      "expires_at": "2026-07-30T12:12:00Z"
    }
  ],
  "meta": { "next_cursor": "0198e2c1-…" }
}

Query parameters

ParameterMeaning
referenceYour reference, exact match. Returns at most one order.
typeonramp or offramp.
statusOne order status.
collection_idOrders created from payments to one collection.
fromTimestamp, inclusive lower bound (RFC 3339).
toTimestamp, inclusive upper bound (RFC 3339).
per_pagePage size. The default is 20 and the maximum is 100.
cursorThe next_cursor from the last page.

See Pagination for cursor handling.

Errors

CodeCause
quote_expiredThe quote expired, or it already created an order. Get a new one.
quote_flow_mismatchAn onramp quote was used on an offramp order, or the reverse.
invalid_destination_addressThe address is not valid for the quoted network.
account_verification_failedThe bank could not confirm the beneficiary account.
recipient_id_requiredYour business pays out only to its own accounts. Send recipient_id, not beneficiary or destination.
recipient_id_not_supportedYour business pays its customers. Send beneficiary or destination, not recipient_id.
recipient_not_foundrecipient_id does not match one of your payout accounts.
recipient_type_mismatchAn offramp order named a wallet, or an onramp order named a bank account.
recipient_quote_mismatchThe wallet's network or stablecoin differs from the onramp quote's.
duplicate_referenceThe reference belongs to a different order.
quote_changedA refresh changed the quote during order creation.
order_not_foundThe order does not exist for your business.

See Errors for every code.

See the Orders reference for the full schema of every field.

On this page