Quotations
A Quote locks in an exchange rate, fees, and the
resulting amounts before money moves. createQuotation requests one;
getQuotation re-reads it. A quotation is single-use β it backs exactly one
order, forever β and it expires, so the window
between quoting and sending matters.
createQuotation(...)β
Requests a new quotation for a source-to-destination corridor and locks in its exchange rate and fees.
Signatureβ
createQuotation(req: CreateQuotationRequest): Promise<QuotationDetail>
Parametersβ
| Name | Type | Required | Description |
|---|---|---|---|
req.source.currency | string | Yes | Always "USDR" β B2B funds originate from the USDR wallet. Any other value is rejected client-side. |
req.destination.country | string | Yes | 2-character ISO alpha-2 destination country code. |
req.destination.currency | string | Yes | Destination currency code. |
req.destination.payout_method.type | "BANK_TRANSFER" | "P2P_PHONE_TRANSFER" | Yes | The payout method the destination amount will be settled with. |
req.quote.mode | "SEND_EXACT" | "RECEIVE_EXACT" | Yes | SEND_EXACT fixes the source amount; RECEIVE_EXACT fixes the target amount. |
req.quote.amount | string | Yes | Decimal string, up to 6 fractional digits (^\d+(\.\d{1,6})?$). |
Returnsβ
QuotationDetail:
| Field | Type | Meaning |
|---|---|---|
id | string | Quotation identifier. Pass it as quotation_id to createOrder. |
source.currency | string | Source currency β always "USDR". |
source.decimals | number | Decimal precision of the source amounts. |
source.gross_amount | string | Source amount before fees. |
source.net_amount | string | Source amount after fees. |
destination.country | string | null | Destination country the quotation locked (ISO-2). |
destination.payout_method.type | string | null | Payout method the quotation locked. The order's payment_instructions must match it, or createOrder fails with B2B_QUOTATION_MISMATCH. Both destination fields are null only when the network could not attach a rate β do not build an order on that quotation. |
target.currency | string | Destination currency. |
target.decimals | number | Decimal precision of the target amount. |
target.amount | string | Amount the beneficiary receives. |
exchange_rate.value | string | The locked rate, as a decimal string. |
exchange_rate.quoted_at | string | ISO 8601 timestamp the rate was quoted at. |
exchange_rate.expires_at | string | ISO 8601 timestamp the quotation stops being usable. |
fees.total_in_source_currency | string | Total fees, expressed in the source currency. |
fees.breakdown[].description | string | Human-readable line item. |
fees.breakdown[].pricing_type | "FEE" | "DISCOUNT" | Whether the line adds to or reduces the cost. |
fees.breakdown[].applied_to | string | Base the line was computed against, e.g. "GROSS" or "NET". |
fees.breakdown[].value | string | Line amount, as a decimal string. |
fees.breakdown[].currency | string | Currency of the line amount. |
Exampleβ
import {
RetornaClientBuilder,
RetornaEnvironment,
} from "@retorna-tech/retorna-gateway-sdk";
const client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(process.env.RETORNA_CLIENT_ID!)
.clientSecret(process.env.RETORNA_CLIENT_SECRET!)
.privateKey(process.env.RETORNA_PRIVATE_KEY!)
.buildClient();
const quotation = await client.createQuotation({
source: { currency: "USDR" },
destination: {
country: "VE",
currency: "VES",
payout_method: { type: "BANK_TRANSFER" },
},
quote: { mode: "SEND_EXACT", amount: "10.00" },
});
console.log(quotation.id, quotation.target.amount, quotation.exchange_rate.expires_at);
console.log(quotation.destination.payout_method.type); // "P2P_PHONE_TRANSFER" β use bank_phone_account on the order
Errorsβ
Client-side, before any network call (RetornaSdkError):
- Empty
source.currency,destination.currency, or adestination.countrythat is not exactly 2 characters. destination.payout_method.typeoutsideBANK_TRANSFER/P2P_PHONE_TRANSFER.quote.modeother thanSEND_EXACT/RECEIVE_EXACT, orquote.amountnot matching the decimal-string format.
From the API (RetornaB2BError, see the error catalog):
B2B_UNAUTHORIZEDβ credentials, token, or signature rejected.B2B_RATE_NOT_FOUNDβ no active rate for the requested corridor.B2B_RATE_LIMITEDβ too many requests; retry with backoff.B2B_PROVIDER_UNAVAILABLEβ the payment network is unreachable; retry with backoff.B2B_UNKNOWNβ unclassified failure; retry once, then escalate withcorrelationId.
Notesβ
source.currencyonly ever accepts"USDR"β funds always originate from the USDR wallet, only the destination corridor varies.- The quotation is only good until
exchange_rate.expires_at. AcreateOrdercall against an expired quotation fails withB2B_QUOTATION_EXPIRED(see orders) β request a fresh quotation instead of retrying. - A quotation is single-use: once an order references it, a second
createOrderwith the samequotation_idfails withB2B_QUOTATION_ALREADY_USED. See idempotency.
API referenceβ
getQuotation(id)β
Reads back a previously created quotation by id.
Signatureβ
getQuotation(id: string): Promise<QuotationDetail>
Parametersβ
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The quotation id returned by createQuotation. Between 1 and 100 characters. |
Returnsβ
QuotationDetail β same shape as createQuotation above.
Exampleβ
const quotation = await client.getQuotation("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
console.log(quotation.exchange_rate.expires_at);
Errorsβ
Client-side (RetornaSdkError):
idempty or longer than 100 characters.
From the API (RetornaB2BError):
B2B_UNAUTHORIZEDβ credentials, token, or signature rejected.B2B_QUOTATION_NOT_FOUNDβ the quotation does not exist, or does not belong to your company.
Notesβ
- Read-only: it does not refresh the rate or extend
expires_at. - Useful to re-check
exchange_rate.expires_atright before callingcreateOrder, since a quotation you fetched earlier may have expired since.