Quotations
A quotation locks an exchange rate, fees and the resulting
amounts for a short window. Create one before building an order, then reference its
id β an order that references an expired or already-used quotation fails before any
money moves. See Orders for create_order.
create_quotationβ
Locks a rate for a transfer corridor: a source currency, a destination country/currency/payout method, and the amount you want quoted.
Signatureβ
def create_quotation(self, request: CreateQuotationRequest) -> QuotationDetail:
Parametersβ
| Name | Type | Required | Description |
|---|---|---|---|
request | CreateQuotationRequest | Yes | The quote to build. |
CreateQuotationRequest fields:
| Field | Type | Required | Description |
|---|---|---|---|
source | QuotationSource | Yes | Where the money comes from. Carries only currency β adding anything else is a 400. |
source.currency | str | Yes | Non-empty currency code, e.g. "USDR". |
destination | QuotationDestination | Yes | Where the money is going. |
destination.country | str | Yes | 2-character ISO alpha-2 country code, uppercase, e.g. "VE". |
destination.currency | str | Yes | Non-empty currency code, e.g. "VES". |
destination.payout_method | QuotationPayoutMethod | Yes | How the recipient will be paid. |
destination.payout_method.type | PayoutMethodType | Yes | PayoutMethodType.BANK_TRANSFER or PayoutMethodType.P2P_PHONE_TRANSFER. |
quote | QuotationQuote | Yes | The amount being quoted. |
quote.mode | QuoteMode | Yes | QuoteMode.SEND_EXACT (the sender parts with exactly quote.amount) or QuoteMode.RECEIVE_EXACT (the recipient gets exactly quote.amount). |
quote.amount | str | Yes | Decimal string with up to 6 decimals, e.g. "56.00". Never a float. |
Returnsβ
QuotationDetail:
| Field | Type | Description |
|---|---|---|
id | Optional[str] | The quotation id. Pass it as quotation_id to create_order. |
source | Optional[QuotationSourceDetail] | currency, decimals, gross_amount, net_amount β the source side, before and after fees. |
destination | Optional[QuotationDestinationDetail] | country (ISO-2) and payout_method.type β the corridor the quotation locked. The order's payment instructions must match payout_method.type, or create_order fails with B2B_QUOTATION_MISMATCH. Both are None only when the network could not attach a rate β do not build an order on that quotation. |
target | Optional[QuotationTargetDetail] | currency, decimals, amount β what the recipient side computes to. |
exchange_rate | Optional[ExchangeRate] | value (decimal string), quoted_at, expires_at β the locked rate and its validity window. |
fees | Optional[QuotationFees] | total_in_source_currency plus a breakdown list of FeeBreakdownItem (description, pricing_type, applied_to, value, currency). |
Exampleβ
from retorna_sdk import (
CreateQuotationRequest, QuotationSource, QuotationDestination,
QuotationPayoutMethod, QuotationQuote, QuoteMode, PayoutMethodType,
)
# client is the RetornaClient from the overview's RetornaClient.create(...)
quotation = client.create_quotation(CreateQuotationRequest(
source=QuotationSource(currency="USDR"),
destination=QuotationDestination(
country="VE", currency="VES",
payout_method=QuotationPayoutMethod(type=PayoutMethodType.BANK_TRANSFER)),
quote=QuotationQuote(mode=QuoteMode.SEND_EXACT, amount="56.00"),
))
print(quotation.id, quotation.exchange_rate.value, quotation.target.amount)
print(quotation.destination.payout_method.type) # "P2P_PHONE_TRANSFER" β use bank_phone_account on the order
Errorsβ
B2B_RATE_NOT_FOUNDβ no active rate for this source/destination/payout-method corridor. Checkget_routesfirst.B2B_RATE_LIMITEDβ too many requests; retry with backoff.B2B_UNAUTHORIZEDβ bad token or bad request signature.ValueErrorβ raised locally, before any request goes out, whenrequest,source,destinationorquoteisNone; whenquote.modeordestination.payout_method.typeis not a valid enum member; or whensource.currency/destination.currencyis empty,destination.countryis not a 2-letter uppercase code, orquote.amountis not a decimal string.
Notesβ
sourcecarries onlycurrencyβ nocountryornetwork. The DTO enforces this even where old documentation says otherwise.- The quotation expires quickly; do not cache one across requests you expect to take more than a few minutes.
API referenceβ
get_quotationβ
Re-fetches a previously created quotation by its id β useful to check whether it is
still within its validity window before building an order from it.
Signatureβ
def get_quotation(self, quotation_id: str) -> QuotationDetail:
Parametersβ
| Name | Type | Required | Description |
|---|---|---|---|
quotation_id | str | Yes | Opaque id, 1 to 100 characters β not necessarily a UUID. |
Returnsβ
Same QuotationDetail as create_quotation β see the table above.
Exampleβ
quotation = client.get_quotation(quotation.id)
print(quotation.id, quotation.exchange_rate.expires_at)
Errorsβ
B2B_QUOTATION_NOT_FOUNDβ the id does not exist, or does not belong to your company.B2B_UNAUTHORIZEDβ bad token or bad request signature.ValueErrorβ raised locally whenquotation_idisNoneor its length is outside 1..100 characters.
Notesβ
- Fetching a quotation does not extend or refresh it β
expires_atis fixed at creation time.