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_accountcontainsaccount_name,account_number,bank_name, andexpires_at. - For an offramp,
funding_accountcontainsdeposit_addressandnetwork.
Order status
An order moves through five statuses. You track it until it reaches a terminal one, then stop.
awaiting_payment → processing → completed| Status | Meaning | Terminal |
|---|---|---|
awaiting_payment | Waiting for the customer's naira transfer or crypto deposit. | no |
processing | Funds received. Pulse is converting and settling. | no |
completed | Settled to the destination. | yes |
expired | Never funded in time. | yes |
failed | Could 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.
- Read
GET /v1/orders/{id}until the status is terminal. - Wait for a webhook that carries the same milestones.
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
| Parameter | Meaning |
|---|---|
reference | Your reference, exact match. Returns at most one order. |
type | onramp or offramp. |
from | Timestamp, inclusive lower bound (RFC 3339). |
to | Timestamp, inclusive upper bound (RFC 3339). |
per_page | Page size. Defaults to 20; maximum 100. |
cursor | The 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.