How to lock an FX rate in a naira payments API
On the Daya API a quote holds nothing and a bound rate holds for about 30 minutes. How rate locking works in a naira payments API, and what to build for the moment it expires.

To hold an exchange rate in a payments API, you bind the rate to the payment rather than just reading it. On the Daya API, a quote comes back marked as an estimate and holds nothing, while a temporary funding account bound to a rate ID executes at that rate for about 30 minutes from when the rate was created.
Every provider in this market uses the word quote, and they don't all mean the same thing by it. Some return a price you can show a customer. Some return a price that will still be honoured when the money actually arrives. The gap between those two is where a naira integration loses money, because a naira bank transfer doesn't land the moment your customer presses send. For the wider picture, see stablecoin on- and off-ramps for developers in Africa.
What does locking an FX rate actually mean?
Locking a rate means the provider will convert at a price it has already committed to, for a stated length of time. A quote with no lock behind it is a price estimate, good for showing a customer and nothing more. The Daya API's quote reference states it plainly: the quote is always marked as an estimate and "does not lock the final payout", and the call doesn't create a funding account, start a payout, reserve funds or move money.
Three separate things travel with a locked rate, and keeping them apart saves an argument with your own finance team later. There's the rate, which is the number you quote. There's the window, which is how long that number survives. And there's everything that isn't the rate, which includes the provider's fees. Daya's documentation is explicit that "binding the FX rate does not freeze all fees or guarantee the final payout", so a locked rate is a narrower promise than the phrase suggests.
How do you lock a naira rate on the Daya API?
You take a rate, bind it to a temporary funding account, and show the customer the amount that account gives back. The Daya API generates new rates about every 10 minutes and they expire about 30 minutes after creation, and a temporary funding account is bound to a specific rate ID at creation where the contract requires a quote. Five steps:
- Read the current rate from the rates endpoint, or create a quote to preview the net payout after fees.
- Create the temporary funding account, passing the rate ID in the settlement destination.
- Show the customer the amount from the create response, not the amount you asked for. Daya's guidance is to display the create response amount and not to work the provider charge out yourself.
- Store the expiry on your own server and treat it as the deadline, because a deposit that arrives late isn't settled automatically.
- If it expires, get a new rate. Daya's documentation says rates can't be extended, reused or retroactively applied.
A permanent naira virtual account behaves differently, and it's worth being clear which one your flow uses. Daya's documentation says each deposit on a permanent funding account uses the current rate at the time of execution, and that permanent funding accounts don't guarantee a fixed price. So the lock lives on the temporary account, not on the account you leave open for a customer to top up whenever they like. How to accept naira and settle in USDC or USDT walks through that collection path end to end.
How long do FX quotes stay valid?
Yellow Card, Fincra and Bitnob each describe a quote that expires, and none of the three says how long it lasts. The Daya API states the window: about 30 minutes from the rate's creation, with new rates generated about every 10 minutes. If you need a number to design a checkout timer around, that's the only one documented in this set.
| Provider | What holds the rate | Window it states | What it says happens at expiry |
|---|---|---|---|
| Yellow Card | A receive or send request locks a rate | Not stated | A send request auto-expires if it isn't accepted |
| Daya API | A temporary funding account bound to a rate ID | About 30 minutes from the rate's creation | A late deposit is flagged and doesn't settle automatically |
| Fincra | A quote reference passed into the conversion | Not stated; the quote carries an expiry timestamp | Not stated |
| Bitnob | A quote carrying an expiry timestamp | Not stated | Payments after the time "may be rejected, returned, or underpaid" |
Yellow Card's wording is in its API glossary, where a receive request "locks in an exchange rate for the funds and awaits approval". Fincra's quote and its expiry timestamp are in its currency conversions guide, and Bitnob's are on its page on quote lifecycle and expiry. Daya's figures are on its rates and settlement page. For how the four compare on everything other than the rate, see the best naira on-ramp and off-ramp APIs, compared.
What happens when the quote expires?
On the Daya API, a deposit that arrives after the bound rate has expired is flagged rather than converted, and it doesn't settle on its own. Daya's documentation adds that rates can't be extended, reused or retroactively applied, so there's no way to honour the old price after the event. The only route forward is a new rate and a new quote.
That makes expiry something you build for rather than something you handle when it goes wrong. Four things to put in your own flow:
- A visible deadline for the customer, and a confirm button that stops working when it runs out.
- A check against the stored expiry on your server before you submit anything, not only in the browser.
- A fresh quote on expiry, with the new numbers shown to the customer before they commit to them.
- One quote per payment. Bitnob's own guidance puts it in three words: never reuse old quotes.
Why is a short quote window a problem for a naira payment?
Because a naira bank transfer doesn't arrive the moment the customer decides to pay. Most published guidance on quote expiry comes from providers built on instant rails, where a short window is comfortable. BlindPay's documentation sets a default expiry of five minutes on its payin, payout and transfer quotes, and ten seconds on an over-the-counter Pix payin, and those are sensible numbers for Pix, SPEI and SEPA.
A customer moving naira out of their own banking app is on a different clock, so two numbers have to fit together: the window the provider gives you, and how long your customer realistically takes. About 30 minutes covers someone who opens their bank app and pays while your page is still open. It doesn't cover someone who saves the account details and pays tomorrow morning. For that second customer a permanent funding account, priced at the rate on the day the money lands, is the honest structure, and a quoted price you can't honour is worse than no quote at all.
What happens if the customer sends the wrong amount?
On the Daya API it depends which bank the customer pays from, and Fidelity Bank is the exception. From most banks an underpayment is refunded to the sender automatically: no deposit is created, no webhook fires, and the funding account stays active until expiry so the customer can pay again. An overpayment converts the correct amount and refunds the excess.
Daya's own worked examples are the clearest way to hold it. If the create response says ₦50,000:
- The customer sends ₦45,000, and the whole ₦45,000 is refunded. Nothing is converted and nothing reaches your webhook.
- The customer sends ₦55,000, and ₦50,000 is converted while ₦5,000 is refunded. The deposit object shows the processed amount only, not the refunded part.
- The customer pays from Fidelity Bank and the amount is out by any margin, and the transaction fails outright. No funds are processed, the deposit status is FAILED, and a deposit.failed event fires.
Two things follow for your build. Warn a customer who may be paying from Fidelity Bank that the amount has to be exact, because for them a rounding habit is a failed payment rather than a refund. And listen for the failure event so you can prompt a retry instead of leaving someone watching a pending screen. Daya states that refunds typically arrive in 1 to 2 business days and that the merchant isn't charged for a refunded amount. The same discipline applies to the success path: handling webhooks for stablecoin settlement covers why you reconcile against the provider rather than crediting a user straight off an event.
Where does the Daya API fit?
The Daya API is the one in this comparison with both a documented window and a documented expiry behaviour: about 30 minutes from a rate's creation, a late deposit flagged rather than converted, and no extension or retroactive application. For a naira flow where the customer pays within a few minutes of being quoted, that's the mechanism to build on, and it's the figure a countdown can be designed against.
Where it's narrower than the phrase "rate lock" suggests: Daya's documentation says binding the rate doesn't freeze all fees, and that a fee change can make a preview stale before the rate itself expires. So read the expiry from the response and the amount from the create response, rather than holding either of them in your own code. What the Daya API gives you is a price you can stand behind for a stated window, and a documented answer for what happens when that window closes. For what the naira leg costs once the money moves, see how to pay out naira to a Nigerian bank account with an API.
Frequently asked questions
- How do you lock an exchange rate in a payments API?
You bind the rate to the payment instead of just reading it. On the Daya API that means creating a temporary funding account bound to a rate ID, which then executes at that rate for about 30 minutes from the rate's creation. Yellow Card locks a rate on a receive or send request, and Fincra passes a quote reference into the conversion.
- How long is a Daya API rate valid?
About 30 minutes from when the rate was created, with new rates generated about every 10 minutes. Deposits received inside that window execute at the bound rate, and Daya's documentation says no slippage occurs within the validity window.
- Does a quote reserve the exchange rate?
Not on its own. The Daya API's quote is always marked as an estimate and the reference says it "does not lock the final payout". The call doesn't create a funding account, start a payout, reserve funds or move money. The reservation happens when a temporary funding account is created against a rate ID.
- What happens if a customer pays after the rate expires?
On the Daya API the deposit is flagged and doesn't settle automatically, and rates can't be extended, reused or retroactively applied. You request a new rate and show the customer the new amount. Bitnob's documentation warns that payments made after a quote's time "may be rejected, returned, or underpaid".
- Can you lock a rate on a permanent naira virtual account?
No. Daya's documentation says each deposit on a permanent funding account uses the current rate at the time of execution, and that permanent funding accounts don't guarantee a fixed price. If you need a held price, use a temporary funding account bound to a rate ID. If the customer will pay days later, the permanent account is the more honest structure.
- What happens if a customer sends the wrong amount to a naira funding account?
From most Nigerian banks the Daya API refunds an underpayment to the sender automatically and refunds the excess on an overpayment, with the correct amount converted. From Fidelity Bank a mismatch fails outright, no funds are processed and a failure event fires, so the customer has to send the exact amount again.
Sources(7)
- Rates and settlement, Daya developer documentation. Accessed .
- Preview an onramp or offramp payout, Daya developer documentation. Accessed .
- Handling amount mismatch, Daya developer documentation. Accessed .
- API glossary, Yellow Card. Accessed .
- Currency conversions (FX), Fincra. Accessed .
- Quote lifecycle and expiry, Bitnob. Accessed .
- Stablecoin API quotes explained, BlindPay. Accessed .





