Saltar al contenido principal

Órdenes

Una orden es el movimiento real de dinero: referencia una cotización, nombra un remitente y un destinatario, y dice adónde llega el dinero. Su status avanza por un ciclo de vida — consulta Estado de la orden.

create_order​

Esto mueve dinero real. Construye el request a partir del id de una cotización, y después crea la orden con una idempotency key.

Firma​

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

Parámetros​

NombreTipoRequeridoDescripción
requestCreateOrderRequestSíLa orden a crear.
idempotency_keyOptional[str]NoString libre, no un UUID. Por defecto se genera un UUID si se omite — pasa el tuyo (p. ej. un número de factura) para que los reintentos sean seguros y correlacionables. Se manda como X-Idempotency-Key y vuelve como idempotency_key.

Campos de CreateOrderRequest (constrúyelo con CreateOrderRequest.with_purpose(...) para pasar purpose como enum):

CampoTipoRequeridoDescripción
quotation_idstrSíTiene que ser un UUID — el id de create_quotation/get_quotation.
senderOrderSenderSíQuién envía el dinero.
sender.names / sender.last_namesstrSíNo vacío.
sender.documentPersonDocumentSítype, id (ambos no vacíos), country (2 letras en mayúsculas).
sender.countrystrSíISO alpha-2 de 2 letras en mayúsculas.
sender.phoneOptional[str]NoFormato E.164 (p. ej. "+584121234567"), se valida cuando no es None. Solo vuelve en las lecturas si lo enviaste al crear.
sender.emailOptional[str]NoSe valida como dirección de email cuando no es None. Solo vuelve en las lecturas si lo enviaste al crear.
destinationOrderDestinationSíAdónde llega el dinero.
destination.receiverOrderReceiverSínames, last_names (no vacíos), document (como arriba), country (2 letras en mayúsculas), email (opcional, se valida si está presente).
destination.payment_instructionsPaymentInstructionsSíExactamente uno de bank_account o bank_phone_account — si se configuran ambos, o ninguno, se lanza un error.
destination.payment_instructions.bank_accountOptional[BankAccount]Uno de los dosConstrúyelo con BankAccount.of(FinancialEntity, number, BankAccountType). bank_name se valida contra el catálogo FinancialEntity; type es BankAccountType.CHECKING / SAVINGS / CORRIENTE / AHORRO.
destination.payment_instructions.bank_phone_accountOptional[BankPhoneAccount]Uno de los dosConstrúyelo con BankPhoneAccount.of(FinancialEntity, phone_number, document_id=None). phone_number tiene que ser E.164 (p. ej. "+584121234567"); document_id cae de vuelta a destination.receiver.document.id si se omite.
purposeOrderPurpose (vía with_purpose) / strSíUno de 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]]NoPares clave/valor libres que vuelven en la orden.

Retorno​

Order:

CampoTipoDescripción
idOptional[str]String opaco, de 1 a 100 caracteres — no necesariamente un UUID.
typeOptional[str]Tipo de movimiento interno, p. ej. "WALLET_TO_POG".
statusOptional[str]Estado del ciclo de vida — consulta Estado de la orden.
quotation_idOptional[str]La cotización con la que se armó esta orden.
idempotency_keyOptional[str]Tu idempotency_key, tal cual vuelve.
amount / currencyOptional[str]El monto liquidado, como string decimal.
metadataOptional[Dict[str, Any]]Lo que hayas mandado, tal cual vuelve.
purposeOptional[str]Valor de wire del propósito declarado; usa order.purpose_enum para recuperarlo como OrderPurpose.
sender / destinationOptional[OrderSender] / Optional[OrderDestination]Vuelven tal cual, con los mismos modelos todo-opcional que el request.
executionOptional[OrderExecution]Tramos source / destination, cada uno un ExecutionLeg (status, reference_id).
eventsOptional[List[OrderEvent]]Transiciones del ciclo de vida — from_status, to_status, trigger, reason, message, created_at.
failure_code / failure_reasonOptional[str]Se definen cuando status es un estado de falla — consulta Detalle de fallas.
created_at / updated_atOptional[datetime]Timestamps.

Ejemplo​

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)

Errores​

Notas​

  • Reutiliza la misma idempotency_key al reintentar; el servidor deduplica en vez de pagar dos veces.
  • Cada modelo del request anidado también funciona como modelo de respuesta con campos todo-opcionales, así que una respuesta parcial del servidor igual deserializa.

Referencia de API​

POST /orders

list_orders​

Lista las órdenes de tu compañía, paginadas por cursor, con filtros opcionales.

Firma​

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

Parámetros​

ListOrdersParams (todos opcionales; helpers: ListOrdersParams.first_page(limit=...), ListOrdersParams.by_idempotency_key(idempotency_key)):

CampoTipoDescripción
cursorOptional[str]Cursor opaco del pagination.next_cursor de una página anterior. Omítelo para la primera página — un string vacío es inválido.
limitOptional[int]De 1 a 100. Queda fijo para todo el recorrido una vez que pasas un cursor.
statusOptional[str]Filtro por estado de la orden.
typeOptional[str]Filtro por tipo de transacción, ej. "WALLET_TO_POG". Libre, un solo valor — a diferencia de status, no acepta una lista separada por comas.
idempotency_keyOptional[str]Filtro por tu idempotency key.
created_from / created_toOptional[datetime]Filtro por rango de fechas.

Retorno​

OrdersListResponse:

CampoTipoDescripción
dataOptional[List[Order]]La página de órdenes — consulta la tabla de Order en create_order.
paginationOptional[CursorPagination]next_cursor, has_more, limit, total (nullable). Consulta Paginación.

Ejemplo​

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)

Errores​

  • B2B_INVALID_PAGINATION_CURSOR — el cursor estaba mal formado, manipulado, o no fue emitido por este listado.
  • B2B_UNAUTHORIZED — token o firma de request inválidos.
  • ValueError — se lanza localmente cuando limit está fuera de 1..100, o cursor/idempotency_key está presente pero vacío.

Notas​

  • No existe un parámetro page — la paginación por offset se eliminó. Mantén los filtros idénticos a lo largo de un recorrido paginado; consulta Paginación.

Referencia de API​

GET /orders

get_order​

Trae una orden puntual por su id.

Firma​

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

Parámetros​

NombreTipoRequeridoDescripción
order_idstrSíId opaco, de 1 a 100 caracteres — no asumas que tiene forma de UUID.

Retorno​

El mismo Order que create_order — consulta la tabla de arriba.

Ejemplo​

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

Errores​

  • B2B_ORDER_NOT_FOUND — el id no existe o no es tuyo.
  • B2B_UNAUTHORIZED — token o firma de request inválidos.
  • ValueError — se lanza localmente cuando order_id es None o su longitud está fuera de 1..100 caracteres.

Notas​

  • Sondea status (o lee events) para seguir un pago después de crearlo — consulta Estado de la orden.

Referencia de API​

GET /orders/{id}