Changelog
New in Pulse, and what it means for your integration.
Pay out only to your own accounts
Pulse can set up your business so that every payout goes to your own payout
accounts, never to your customers. Each order names the account with recipient_id,
and only your dashboard admins add, replace, and remove the accounts. Ask
support to set it up.
Nothing changes for a business that pays its customers.
To use it: Paying out only to your own accounts?
- Read the payout account
idvalues withGET /v1/recipients. - Send
recipient_idon each order, notbeneficiaryordestination. See Name a payout account on an order. - Handle
403 payout_accounts_lockedon the requests that change payout accounts.
| Endpoint | Change |
|---|---|
POST /v1/onramp/orders | Accepts recipient_id instead of destination. Adds recipient_id_required, recipient_id_not_supported, recipient_not_found, recipient_type_mismatch, and recipient_quote_mismatch. |
POST /v1/offramp/orders | Accepts recipient_id instead of beneficiary. Adds recipient_id_required, recipient_id_not_supported, recipient_not_found, and recipient_type_mismatch. |
POST /v1/recipients, DELETE /v1/recipients/{id} | Return 403 payout_accounts_locked when your business pays out only to its own accounts. |
PATCH /v1/collections/{id} | Returns 403 payout_accounts_locked for a different recipient_id when your business pays out only to its own accounts. |
Collect naira to permanent bank accounts
Give each of your customers a permanent bank account. Whenever anyone transfers naira to it, Pulse converts the transfer and sends a stablecoin to the wallet you choose. You do not create a quote or an order for each transfer.
Each transfer creates an onramp order, and its webhooks carry your collection
reference. Pulse holds a transfer below ₦15,000 or above ₦100,000,000.
Action required: Reading from_address?
order.payment_received and order.held replace from_address with a sender
object. For a stablecoin deposit, read sender.crypto_address.address. The simulate
response changes the same way.
Action required: Matching unsupported_collection_type?
Pulse no longer returns it. A wallet payout account now creates a naira collection. To switch a collection to a different kind of payout account, create a new collection.
To use it: Start collecting naira
- Add a wallet as a payout account.
- Create a collection for each customer with that wallet as
recipient_id. - Show the customer
deposit_account. - Read
sender,session_id, andpayoutonorder.payment_received.
Read Naira collections for the full flow.
| Endpoint | Change |
|---|---|
POST /v1/collections | Creates a naira collection (type onramp) when recipient_id is a wallet. Accepts optional customer.nin and customer.bvn. No longer returns unsupported_collection_type. |
GET /v1/collections, GET /v1/collections/{id}, PATCH /v1/collections/{id} | Return deposit_account for a naira collection, with an empty deposit_addresses. |
POST /v1/recipients | Accepts type crypto_address with network, address, and asset. Returns invalid_destination_address for an address that is not valid for its network. |
POST /v1/collections/deposits/simulate | Accepts account_number to simulate a naira transfer. Breaking. Returns sender instead of from_address. |
| Webhooks | Breaking. order.payment_received and order.held replace from_address with sender. A naira transfer adds session_id, and its payout.network names the stablecoin's network. A held naira transfer has no network or transaction_hash. |
| Errors | Removed unsupported_collection_type. |
Name the payout account on every collection
Every collection now names its payout account with recipient_id. Payout accounts no
longer have a default, so a collection always pays the account it names.
Action required: Creating collections without recipient_id?
Send recipient_id on POST /v1/collections. Without it, the request returns
400 bad_request. Stop sending is_default on POST /v1/recipients; Pulse ignores it.
| Endpoint | Change |
|---|---|
POST /v1/collections | recipient_id is required. Removed the no_default_recipient error. |
POST /v1/recipients | Removed is_default from the request and the response. Removed the default_recipient_conflict error. |
USDT0 on Optimism
Pulse accepts two USDT contracts on OPTIMISM: USDT0 and USDT.e. A customer can
send either one for an offramp. Onramp orders on OPTIMISM pay out USDT0 only.
To use it: Onramp on Optimism?
Tell your customers that they receive USDT0. Supported networks lists both contracts.
Collect stablecoins to permanent addresses
Give each of your customers permanent deposit addresses, one for EVM networks and one for Solana. Whenever a customer sends stablecoins, Pulse converts the deposit and pays naira to the bank account you choose. You do not create a quote or an order for each payment.
Each deposit is an offramp order with the usual webhooks, carrying your collection
reference so you can match it to your customer. A deposit Pulse cannot process, such
as one below the minimum or on an unsupported network, is held with a reason.
To use it: Start collecting
- Add a payout account with
POST /v1/recipients. - Create a collection for each customer with
POST /v1/collections, and show them the addresses indeposit_addresses. - Handle
order.heldand the new fields onorder.payment_received.
Read the Collections guide for the full flow.
Naira collections are next: a permanent naira account in your customer's name, with each credit converted to stablecoin.
To use it: Parsing order statuses?
Orders can now have the status held. It applies only to orders created from
collection deposits.
| Endpoint | Change |
|---|---|
POST /v1/recipients, GET /v1/recipients, GET /v1/recipients/{id}, DELETE /v1/recipients/{id} | Added. Manage the bank accounts that collections pay out to. |
POST /v1/collections, GET /v1/collections, GET /v1/collections/{id}, PATCH /v1/collections/{id} | Added. Create and manage collections. |
GET /v1/orders | Accepts collection_id and status filters. |
GET /v1/orders/{id} | Returns collection_id for an order created from a collection deposit. |
| Order status | Added held. |
POST /v1/collections/deposits/simulate | Added. Simulates a deposit to a collection address in the test environment. See Testing. |
| Webhooks | Added order.held. An offramp order.payment_received now carries transaction_hash and from_address. A collection deposit also carries payout. |
Show prices without creating a quote
Get indicative buy and sell rates for every asset and network Pulse supports, in one call. Show them on a price page or a calculator before the customer starts a trade. An indicative rate is a guide. To lock a price, create a quote.
A single quote is now limited to ₦100,000,000 on the naira side.
Action required: Quoting above ₦100,000,000?
POST /v1/quotes now returns invalid_amount for these trades. Price them with
indicative rates instead.
| Endpoint | Change |
|---|---|
GET /v1/rates | Added. Returns indicative buy and sell rates. fiat_amount sizes the buy rate and crypto_amount sizes the sell rate. |
POST /v1/quotes | Returns invalid_amount for a trade above ₦100,000,000 on the naira side. |
Earn a fee on every order
Set your own fee on any quote, in basis points. Pulse builds it into the rate your customer sees and pays it to your wallet when the order settles. Every order shows exactly what you earned.
To use it: Start earning
- Ask a team admin to add a payout wallet for each network on the Fees page in the dashboard.
- Send
partner_feewhen you create a quote. - Handle the two new errors:
partner_fee_exceeds_capandpartner_fee_wallet_missing.
Read the Partner fees guide for the full flow.
| Endpoint | Change |
|---|---|
POST /v1/quotes | Accepts partner_fee in basis points. Returns partner_fee with the estimated amount. |
GET /v1/orders/{id} | Returns partner_fee with the fee paid. See See the fee paid. |
| Errors | Added partner_fee_exceeds_cap and partner_fee_wallet_missing. |
USDT and USDC on Solana
Your customers can buy and sell USDT and USDC on Solana. It works for onramp and offramp, through the same endpoints you use today.
To use it: Add Solana
- Accept Solana wallet addresses. They are base58, not
0x. - For an offramp, the customer sends the SPL token to
deposit_address. Their wallet delivers it to that address's token account. - For an onramp,
transaction_hashis the Solana transaction signature. Link it to a Solana block explorer. - Try every outcome with the Solana sandbox addresses in Testing.
| Field | Change |
|---|---|
network | Added SOLANA for USDT and USDC. |
destination.address, deposit_address | Base58 addresses on SOLANA. |
transaction_hash | The transaction signature on SOLANA. |
invalid_destination_address | Now means the address is not valid for the quoted network, not only that it is malformed. |
Let customers choose what they receive
A customer can now say how much they want to receive, and Pulse works out what they pay. Orders tell you exactly when they stop accepting payment. Every amount Pulse returns is ready to send as-is.
Action required: Update your integration
These renames break existing requests. Ship them before this release reaches your environment.
- On
POST /v1/quotes, renameamounttosource_amount. - On onramp order creation, rename
accounttofunding_account. Readexpires_atfrom the order, not fromaccount.expires_at. - On offramp order creation, read
funding_account.deposit_addressinstead of the top-leveldeposit_address. - On order reads, read
expires_atfrom the order, not fromfunding_account.expires_at.
Also in this release:
- Onramp customers always get the full 30 minutes to pay. The clock starts when their virtual account is issued, so a slow account does not cut their time.
- An onramp payment that arrives after
expires_atdoes not execute the order, the same as offramp. - The minimum onramp quote is ₦15,000.
| Endpoint or field | Change |
|---|---|
POST /v1/quotes | Breaking. Renames amount to source_amount. |
POST /v1/quotes | Accepts destination_amount. Send exactly one of source_amount or destination_amount. Both or neither returns amount_required. |
| Onramp order creation | Breaking. Renames account to funding_account and moves account.expires_at to expires_at on the order. |
| Offramp order creation | Breaking. Replaces the top-level deposit_address with funding_account.deposit_address. |
| Order reads | Breaking. Move funding_account.expires_at to expires_at on the order. |
| Orders | Return expires_at, the point after which Pulse stops accepting payment. Offramp orders had a funding deadline that was never exposed until now. |
| Order creation | Returns rate and party, matching order reads. Creation and reads return the same object. The list endpoint stays a summary and omits funding_account. |
funding_account | Returns bank_code and amount on order reads. Both were previously available only on creation. |
order.awaiting_payment webhook | Adds funding_account.bank_code and funding_account.amount. No other webhook changes, and expires_at stays where it is. |
| Quote amounts | Rounded to the precision their currency supports. A computed source_amount rounds up and a computed destination_amount rounds down. |
| Quote refresh | Re-prices the amount you did not fix. A quote created with destination_amount returns a new source_amount. |
Quotes now hold for two minutes
A quote holds its price for two minutes. If the customer needs longer, refresh it, even after it expires. Orders that are never funded now close on their own when the payment window ends.
Action required
- Reconcile with the order, not the quote. Late funding can change an order's rate and amount.
- Handle
409 quote_changedwhen you create an order. Pulse returns it when a refresh changes the quote at the same time.
Pulse API v1 is here
One API to move between naira and crypto. Customers pay naira and receive crypto, or send crypto and get naira in a verified bank account. Signed webhooks tell you each time an order moves forward.
Test and live each have their own base URL and API keys. Each key allows 60 requests per minute.
To use it: Start building
Follow the onramp quickstart or the offramp quickstart.
| Endpoint | What it does |
|---|---|
POST /v1/quotes | Locks a rate for supported NGN, USDT, and USDC pairs. |
POST /v1/onramp/orders | Collects NGN and delivers crypto. |
POST /v1/offramp/orders | Collects crypto and pays NGN to a verified bank account. |
GET /v1/orders, GET /v1/orders/{id} | Report order status and settlement details. |
GET /v1/banks | Lists supported banks. |
POST /v1/banks/resolve | Confirms an account name before an offramp order. |