Skip to main content

Orders

An order is the actual movement of money: it references a quotation, names a sender and a recipient, and says where the money lands. Its status moves through a lifecycle β€” see Order status.

create_order​

This moves real money. Build the request from a quotation's id, then create the order with an idempotency key.

Signature​

def create_order(
self,
request: CreateOrderRequest,
idempotency_key: Optional[str] = None,
) -> Order:

Parameters​

NameTypeRequiredDescription
requestCreateOrderRequestYesThe order to create.
idempotency_keyOptional[str]NoFree-form string, not a UUID. Defaults to a generated UUID when omitted β€” pass your own (e.g. an invoice number) to make retries safe and correlatable. Sent as X-Idempotency-Key and echoed back as idempotency_key.

CreateOrderRequest fields (build with CreateOrderRequest.with_purpose(...) to pass purpose as an enum):

FieldTypeRequiredDescription
quotation_idstrYesMust be a UUID β€” the id from create_quotation/get_quotation.
senderOrderSenderYesWho is sending the money.
sender.names / sender.last_namesstrYesNon-empty.
sender.documentPersonDocumentYestype, id (both non-empty), country (2-letter uppercase).
sender.countrystrYes2-letter uppercase ISO alpha-2.
sender.phoneOptional[str]NoE.164 format (e.g. "+584121234567"), validated when not None. Round-trips on reads only when sent on create.
sender.emailOptional[str]NoValidated as an email address when not None. Round-trips on reads only when sent on create.
destinationOrderDestinationYesWhere the money lands.
destination.receiverOrderReceiverYesnames, last_names (non-empty), document (as above), country (2-letter uppercase), email (optional, validated if present).
destination.payment_instructionsPaymentInstructionsYesExactly one of bank_account or bank_phone_account β€” setting both, or neither, raises.
destination.payment_instructions.bank_accountOptional[BankAccount]One of twoBuild with BankAccount.of(FinancialEntity, number, BankAccountType). bank_name is validated against the FinancialEntity catalog; type is BankAccountType.CHECKING / SAVINGS / CORRIENTE / AHORRO.
destination.payment_instructions.bank_phone_accountOptional[BankPhoneAccount]One of twoBuild with BankPhoneAccount.of(FinancialEntity, phone_number, document_id=None). phone_number must be E.164 (e.g. "+584121234567"); document_id falls back to destination.receiver.document.id when omitted.
purposeOrderPurpose (via with_purpose) / strYesOne of FAMILY_SUPPORT, PAYMENT_OF_BILLS, PURCHASE_OF_GOODS, PROFESSIONAL_SERVICES, RENTAL_OF_SPACES, INVESTMENTS, COMMISSIONS_LOANS_CAPITAL_INCREASE, TRANSPORTATION_COSTS, FEES.
metadataOptional[Dict[str, Any]]NoFree-form key/value pairs echoed back on the order.

Returns​

Order:

FieldTypeDescription
idOptional[str]Opaque string, 1..100 chars β€” not necessarily a UUID.
typeOptional[str]Internal movement type, e.g. "WALLET_TO_POG".
statusOptional[str]Lifecycle state β€” see Order status.
quotation_idOptional[str]The quotation this order was built from.
idempotency_keyOptional[str]Your idempotency_key, echoed back.
amount / currencyOptional[str]The settled amount, as a decimal string.
metadataOptional[Dict[str, Any]]Whatever you sent, echoed back.
purposeOptional[str]Wire value of the declared purpose; use order.purpose_enum to get it back as OrderPurpose.
sender / destinationOptional[OrderSender] / Optional[OrderDestination]Echoed back, using the same all-optional models as the request.
executionOptional[OrderExecution]source / destination legs, each an ExecutionLeg (status, reference_id).
eventsOptional[List[OrderEvent]]Lifecycle transitions β€” from_status, to_status, trigger, reason, message, created_at.
failure_code / failure_reasonOptional[str]Set when status is a failure state β€” see Failure details.
created_at / updated_atOptional[datetime]Timestamps.

Example​

import os, uuid
from retorna_sdk import (
CreateOrderRequest, OrderSender, OrderReceiver, PersonDocument,
OrderDestination, PaymentInstructions, BankPhoneAccount,
FinancialEntity, OrderPurpose,
)

# quotation is a QuotationDetail from create_quotation(); client is the RetornaClient
# from the overview's RetornaClient.create(...)
request = CreateOrderRequest.with_purpose(
quotation_id=quotation.id,
sender=OrderSender(names="Ana MarΓ­a", last_names="PΓ©rez GΓ³mez",
document=PersonDocument(type="CC", id="1020304050", country="CO"),
country="CO"),
destination=OrderDestination(
receiver=OrderReceiver(names="Carlos AndrΓ©s", last_names="RodrΓ­guez LΓ³pez",
document=PersonDocument(type="V", id="12345678", country="VE"),
email="[email protected]", country="VE"),
payment_instructions=PaymentInstructions.of_bank_phone_account(
BankPhoneAccount.of(FinancialEntity.BNC_VE, "+584121234567", "12345678"))),
purpose=OrderPurpose.FAMILY_SUPPORT,
)

idempotency_key = f"invoice-{uuid.uuid4()}" # free-form str, NOT a uuid.UUID
if os.environ.get("RETORNA_CREATE_ORDER") == "yes":
order = client.create_order(request, idempotency_key)
print(order.id, order.status, order.idempotency_key)

Errors​

Notes​

  • Reuse the same idempotency_key on retry; the server deduplicates instead of paying twice.
  • Every nested request model doubles as a response model with all-optional fields, so a partial server response still deserializes.

API reference​

POST /orders

list_orders​

Lists your company's orders, cursor-paginated, with optional filters.

Signature​

def list_orders(self, params: Optional[ListOrdersParams] = None) -> OrdersListResponse:

Parameters​

ListOrdersParams (all optional; helpers: ListOrdersParams.first_page(limit=...), ListOrdersParams.by_idempotency_key(idempotency_key)):

FieldTypeDescription
cursorOptional[str]Opaque cursor from a previous page's pagination.next_cursor. Omit for the first page β€” an empty string is invalid.
limitOptional[int]1 to 100. Fixed for the whole walk once you pass a cursor.
statusOptional[str]Filter by order status.
typeOptional[str]Filter by transaction type, e.g. "WALLET_TO_POG". Free-form, a single value β€” unlike status, it does not take a comma-separated list.
idempotency_keyOptional[str]Filter by your idempotency key.
created_from / created_toOptional[datetime]Date range filter.

Returns​

OrdersListResponse:

FieldTypeDescription
dataOptional[List[Order]]The page of orders β€” see the Order table under create_order.
paginationOptional[CursorPagination]next_cursor, has_more, limit, total (nullable). See Pagination.

Example​

from retorna_sdk import ListOrdersParams

first = client.list_orders(ListOrdersParams.first_page(limit=50))
by_invoice = client.list_orders(ListOrdersParams.by_idempotency_key("invoice-2026-00456"))
for order in first.data or []:
print(order.id, order.status, order.idempotency_key)

Errors​

  • B2B_INVALID_PAGINATION_CURSOR β€” the cursor was malformed, tampered with, or not issued by this listing.
  • B2B_UNAUTHORIZED β€” bad token or bad request signature.
  • ValueError β€” raised locally when limit is outside 1..100, or cursor/idempotency_key is present but blank.

Notes​

  • There is no page parameter β€” offset pagination was removed. Keep filters identical across a paging loop; see Pagination.

API reference​

GET /orders

get_order​

Fetches a single order by its id.

Signature​

def get_order(self, order_id: str) -> Order:

Parameters​

NameTypeRequiredDescription
order_idstrYesOpaque id, 1 to 100 characters β€” do not assume a UUID shape.

Returns​

Same Order as create_order β€” see the table above.

Example​

order = client.get_order(order.id)
print(order.id, order.status, order.failure_code)

Errors​

  • B2B_ORDER_NOT_FOUND β€” the id doesn't exist or isn't yours.
  • B2B_UNAUTHORIZED β€” bad token or bad request signature.
  • ValueError β€” raised locally when order_id is None or its length is outside 1..100 characters.

Notes​

  • Poll status (or read events) to track a payout after creation β€” see Order status.

API reference​

GET /orders/{id}