Docs

Orders

Create an order in either direction, then read and track it to settlement.

An order moves money one way. An onramp order takes naira and delivers crypto. An offramp order takes crypto and delivers naira. You create an order against a quote, and the order tells you where the customer sends the money. From there you track it until it settles.

Both flows share the same identity fields and status path.

Create an onramp order

Naira to crypto. The order returns a virtual bank account. Once the customer funds it, Pulse delivers crypto to the address you named.

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

The order comes back awaiting_payment with an account. The customer transfers the exact account.amount into it before account.expires_at, and Pulse then converts and delivers the crypto.

{
  "status": true,
  "data": {
    "id": "0198e2d0-…",
    "status": "awaiting_payment",
    "account": {
      "account_number": "9901234567",
      "account_name": "Shiga/Ada Obi",
      "bank_code": "090175",
      "bank_name": "Rubies MFB",
      "amount": "150000",
      "expires_at": "2026-07-30T12:12:00Z"
    }
  }
}

destination.address is where the crypto settles, on the network from the quote. tag is optional, for chains that use a destination tag or memo. An address that does not match the chain returns invalid_destination_address.

The transfer must be exact

A short or late transfer does not fund the order, and the account expires at account.expires_at. The funding window is 30 minutes. After that, start again from a fresh quote.

Create an offramp order

Crypto to naira. The order returns a deposit address. Once the crypto arrives, Pulse settles naira to the bank account.

Resolve the account first, so the customer can check the registered name. See Banks for the account resolution call and the list of bank codes.

curl https://engine-api.pilot.pulseshiga.io/v1/offramp/orders \
  -H "X-API-Key: <your key>" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "piggy-txn-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 order comes back awaiting_payment with a deposit_address. The customer sends the crypto there, and Pulse settles naira to the bank account.

{
  "status": true,
  "data": {
    "id": "0198e400-…",
    "status": "awaiting_payment",
    "deposit_address": "0xDeF…"
  }
}

Pulse checks the account number with the bank during the create call. A number the bank cannot confirm returns account_verification_failed, and no order is created. Account numbers are ten digits.

Pulse settles the crypto amount that arrives at the accepted quote rate. A smaller deposit produces a smaller NGN payout, and a larger deposit produces a larger NGN payout. Reconcile the final payout from order.completed.

Send on the quoted network

Send the crypto on the same network as the quote. A deposit on the wrong chain cannot be recovered.

Identity and the reference

Both create calls take the same identity fields, and both take a reference.

reference is a value you set, up to 128 characters, unique across your onramp and offramp orders. It is also your idempotency key: send the same one again and you get the original order, not a second. A reference that already belongs to an order returns 409 duplicate_reference. See Errors and retries.

The customer's National Identity Number (nin) and Bank Verification Number (bvn) are required for regulatory purposes. Each value must contain eleven digits. Pulse encrypts both at rest and omits them from API responses.

Funding instruction fields

An onramp create returns its funding instruction in account; an offramp create returns deposit_address. Order reads and the order.awaiting_payment webhook use funding_account for either flow. Switch on the order type before reading its shape.

  • For an onramp, funding_account contains account_name, account_number, bank_name, and expires_at.
  • For an offramp, funding_account contains deposit_address and network.

Order status

An order moves through five statuses. You track it until it reaches a terminal one, then stop.

awaiting_payment  →  processing  →  completed
StatusMeaningTerminal
awaiting_paymentWaiting for the customer's naira transfer or crypto deposit.no
processingFunds received. Pulse is converting and settling.no
completedSettled to the destination.yes
expiredNever funded in time.yes
failedCould not be settled.yes

These five are the only statuses the API returns.

Track an order

You learn the final result in one of two ways.

An order can sit in awaiting_payment while the customer moves money, so read it on an interval with backoff rather than in a tight loop. Once it reaches completed, expired, or failed, the status is final.

On pilot, drive an order to each terminal status with a reserved value. See Testing on pilot.

Get one order

curl https://engine-api.pilot.pulseshiga.io/v1/orders/0198e2d0-… \
  -H "X-API-Key: <your key>"
{
  "status": true,
  "data": {
    "id": "0198e2d0-…",
    "reference": "piggy-txn-88213",
    "type": "onramp",
    "status": "processing",
    "rate": "1538.46",
    "source": { "currency": "NGN", "amount": "150000" },
    "destination": { "currency": "USDT", "network": "POLYGON", "amount": "97.50" },
    "created_at": "…",
    "updated_at": "…"
  }
}

The read is scoped to your business by your API key. An id that is not yours returns 404 order_not_found rather than 403, so Pulse never reveals whether another business's order exists.

rate is the rate you accepted on the quote behind the order, returned so you can reconcile without keeping the quote.

destination.amount is quoted, not delivered

The delivered amount can differ from the quoted destination.amount. Reconcile against the amount in order.completed.

List orders

Your orders, newest first. Use it to reconcile a period, or to find one by the reference you set.

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": "piggy-txn-88213",
      "type": "onramp",
      "status": "completed",
      "rate": "1538.46",
      "source": { "currency": "NGN", "amount": "150000" },
      "destination": { "currency": "USDT", "network": "POLYGON", "amount": "97.50" }
    }
  ],
  "meta": { "next_cursor": "0198e2c1-…" }
}

Query parameters

ParameterMeaning
referenceYour reference, exact match. Returns at most one order.
typeonramp or offramp.
fromTimestamp, inclusive lower bound (RFC 3339).
toTimestamp, inclusive upper bound (RFC 3339).
per_pagePage size. Defaults to 20; maximum 100.
cursorThe next_cursor from the last page.

Paging

Paging is cursor-based. Pass meta.next_cursor from one page as cursor on the next. When next_cursor is absent, you have reached the end.

Ordering is newest first and stable, so a row added while you page cannot shuffle earlier pages. Filtering by reference returns at most one order, since a reference is unique across your onramp and offramp orders.

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

On this page