Skip to main content

Orders

An Order is the actual payout β€” it references a quotation, carries the sender and receiver, and moves through the states described in order status until it settles or fails (see failure details). OrdersClient covers creating, reading, and listing orders.

Reach these methods either directly on RetornaClient or through client.orders() β€” both call the same code.

createOrder(request, idempotencyKey)​

Creates an order against a quotation. The backend requires an X-Idempotency-Key header on every call; the SDK sends it for you from the idempotencyKey argument.

Signature​

public Order createOrder(CreateOrderRequest request)

public Order createOrder(CreateOrderRequest request, String idempotencyKey)

The single-argument overload generates a random UUID as the idempotency key. Prefer the two-argument form with your own reference (an invoice number, for example) β€” that value round-trips as order.idempotencyKey(), so you can look the order up later by it, and a retry that reuses the same key against the same body replays the original order instead of creating a duplicate.

Parameters​

NameTypeRequiredDescription
requestCreateOrderRequestYesThe order to create. See components below.
idempotencyKeyStringNoYour own reference. When null or blank, a random UUID is generated. Reusing the same key with a different body is a 409; reusing it with the identical body replays the original order.

CreateOrderRequest components β€” build it with the canonical constructor or withPurpose(...):

// Canonical (5-arg) constructor
public CreateOrderRequest(
String quotationId,
Map<String, Object> metadata,
String purpose,
OrderSender sender,
OrderDestination destination
)

// Typed entry point for the purpose catalog
public static CreateOrderRequest withPurpose(
String quotationId,
Map<String, Object> metadata,
OrderPurpose purpose,
OrderSender sender,
OrderDestination destination
)
ComponentTypeRequiredDescription
quotationIdStringYesUUID of a previously-created quotation. Single-use: it backs exactly one order, forever.
metadataMap<String, Object>NoClient-defined labels, echoed back untouched. Omitted from the wire when null.
purposeString (or OrderPurpose via withPurpose)YesDeclared remittance purpose. Must be a value from OrderPurpose β€” null or anything outside the catalog throws client-side. There is no idempotencyKey field here; it is response-only.
senderOrderSenderYesnames, lastNames, document (PersonDocument), country (2-char ISO alpha-2), phone (nullable, E.164), email (nullable).
destinationOrderDestinationYesSee below.

OrderSender is a record: OrderSender(names, lastNames, document, country, phone, email). The old 4-arg constructor (names, lastNames, document, country) still works β€” phone and email default to null β€” so existing code compiles unchanged. Pass the 6-arg form to set phone and/or email; the client validates phone as E.164 and email as an address when non-null. Both round-trip in sender() on reads only when you sent them on create.

OrderDestination β€” for building a request, use the 2-arg constructor (receiver, paymentInstructions); targetAmount/targetCurrency are response-only and stay off the create wire.

ComponentTypeRequiredDescription
receiverOrderReceiverYesnames, lastNames, document (PersonDocument), email (nullable), country (2-char ISO alpha-2).
paymentInstructionsPaymentInstructionsYesExactly one of bankAccount or bankPhoneAccount must be set β€” build it with PaymentInstructions.ofBankAccount(...) or PaymentInstructions.ofBankPhoneAccount(...).

PersonDocument(type, id, country) β€” type (e.g. "CC", "V"), id (document number), country (2-char ISO alpha-2 issuing country).

For a bank-transfer payout, build the account with BankAccount.of(FinancialEntity, number, BankAccountType):

public static BankAccount of(FinancialEntity bank, String number, BankAccountType type)
ComponentTypeRequiredDescription
bankFinancialEntityYesPlatform code from the closed bank catalog, e.g. BANCO_BANESCO_VE β€” never the commercial name. See bank entities for the full list.
numberStringYesAccount number, kept as a string to preserve leading zeros.
typeBankAccountTypeYesCHECKING, SAVINGS, CORRIENTE, or AHORRO β€” the backend accepts both the English and Spanish forms.

Returns​

Order:

AccessorTypeMeaning
id()StringOrder id.
type()StringOrder type (e.g. "REMITTANCE").
status()StringSee order status for the observed values and how they evolve.
quotationId()StringThe quotation this order was created from.
idempotencyKey()StringYour idempotency key, echoed back; nullable.
amount() / currency()StringSource-currency amount and code.
metadata()Map<String, Object>Echoed metadata; nullable.
sender() / destination()OrderSender / OrderDestinationNullable in some states. destination().targetAmount()/targetCurrency() carry the payout-side amount on reads.
execution()OrderExecutionsource() and destination(), each an ExecutionLeg with status() and referenceId() (nullable).
purposeEnum()OrderPurposeParsed from the raw purpose() string; null if absent or unrecognized by this SDK version.
events()List<OrderEvent>Status-change timeline; nullable. Each OrderEvent has fromStatus() (nullable), toStatus(), trigger(), reason() (nullable), message() (nullable), createdAt().
failureCode() / failureReason()StringMachine-readable / human-readable failure detail; both nullable. See failure details. Branch on failureCode(), never on failureReason().
createdAt() / updatedAt()OffsetDateTimeTimestamps.

JSON on the wire is snake_case (quotation_id, idempotency_key, failure_code, ...); the Java accessors above are camelCase.

Example​

import app.retorna.sdk.RetornaClient;
import app.retorna.sdk.RetornaClientBuilder;
import app.retorna.sdk.core.environment.RetornaEnvironment;
import app.retorna.sdk.models.order.BankPhoneAccount;
import app.retorna.sdk.models.order.CreateOrderRequest;
import app.retorna.sdk.models.order.FinancialEntity;
import app.retorna.sdk.models.order.Order;
import app.retorna.sdk.models.order.OrderDestination;
import app.retorna.sdk.models.order.OrderPurpose;
import app.retorna.sdk.models.order.OrderReceiver;
import app.retorna.sdk.models.order.OrderSender;
import app.retorna.sdk.models.order.PaymentInstructions;
import app.retorna.sdk.models.order.PersonDocument;

RetornaClient client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(System.getenv("RETORNA_CLIENT_ID"))
.clientSecret(System.getenv("RETORNA_CLIENT_SECRET"))
.privateKey(System.getenv("RETORNA_PRIVATE_KEY"))
.buildClient();

String quotationId = "0190f9b2-0000-7000-8000-000000000000"; // from createQuotation
String idempotencyKey = "invoice-2026-0042"; // your own reference

Order order = client.createOrder(
CreateOrderRequest.withPurpose(
quotationId,
null,
OrderPurpose.FAMILY_SUPPORT,
new OrderSender("Ana MarΓ­a", "PΓ©rez GΓ³mez",
new PersonDocument("CC", "1020304050", "CO"), "CO"),
new OrderDestination(
new OrderReceiver("Carlos AndrΓ©s", "RodrΓ­guez LΓ³pez",
new PersonDocument("V", "12345678", "VE"),
PaymentInstructions.ofBankPhoneAccount(
BankPhoneAccount.of(FinancialEntity.BNC_VE,
"+584121234567", "12345678")))),
idempotencyKey);

System.out.printf("Order %s status=%s idempotencyKey=%s%n",
order.id(), order.status(), order.idempotencyKey());

Errors​

Notes​

  • Always pass your own idempotencyKey in production code; the single-argument overload is convenient for scripts, not for anything you might need to safely retry.
  • There is no idempotencyKey field on the request β€” only on the response. Do not try to set one; it always comes from the idempotency key.

API reference​

POST /orders

getOrder(id)​

Reads a single order by id.

Signature​

public Order getOrder(String id)

Parameters​

NameTypeRequiredDescription
idStringYesThe order id as the backend issued it β€” validated for length only (1..100 chars), not a UUID shape.

Returns​

Same Order shape returned by createOrder above.

Example​

import app.retorna.sdk.RetornaClient;
import app.retorna.sdk.RetornaClientBuilder;
import app.retorna.sdk.core.environment.RetornaEnvironment;
import app.retorna.sdk.models.order.Order;

RetornaClient client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(System.getenv("RETORNA_CLIENT_ID"))
.clientSecret(System.getenv("RETORNA_CLIENT_SECRET"))
.privateKey(System.getenv("RETORNA_PRIVATE_KEY"))
.buildClient();

Order order = client.getOrder("0190f9b2-0000-7000-8000-000000000001");
System.out.printf("status=%s failureCode=%s%n", order.status(), order.failureCode());

Errors​

  • IllegalArgumentException β€” id is null, empty, or longer than 100 characters.
  • RetornaB2BException with codeEnum() one of: B2B_ORDER_NOT_FOUND, B2B_UNAUTHORIZED, B2B_RATE_LIMITED β€” retryable, B2B_UNKNOWN.
  • RetornaAuthException β€” token exchange failure.
  • RetornaSdkException β€” network failure or deserialization failure.

Notes​

  • The id is opaque; do not assume a fixed shape.

API reference​

GET /orders/:id

listOrders(params)​

Lists orders, cursor-paginated, with optional filters.

Signature​

public OrdersListResponse listOrders(ListOrdersParams params)

Parameters​

NameTypeRequiredDescription
paramsListOrdersParamsNo (pass null or ListOrdersParams.firstPage())Query filters. See components below.

ListOrdersParams components:

ComponentTypeRequiredDescription
cursorStringNoOpaque cursor from the previous page's next_cursor. Null for the first page.
limitIntegerNoPage size, 1..100; backend default is 20. Keep it fixed across a walk.
statusStringNoFilter by order status. Free-form β€” not constrained to an enum.
idempotencyKeyStringNoFilter by your idempotency key. Exact match, not partial.
createdFrom / createdToOffsetDateTimeNoInclusive bounds on created_at.
typeStringNoFilter by transaction type, e.g. "WALLET_TO_POG". Free-form, a single value β€” unlike status, it does not take a comma-separated list. Added as the last component of ListOrdersParams; the old 6-arg constructor still works and leaves type null.

Convenience factories: ListOrdersParams.firstPage(), firstPage(int limit), byIdempotencyKey(String idempotencyKey), and byType(String type).

Returns​

OrdersListResponse:

AccessorTypeMeaning
data()List<Order>Orders on this page β€” see the Order shape from createOrder above.
pagination()CursorPaginationnextCursor() (String, nullable when done), hasMore() (boolean), limit() (int), total() (Integer, nullable β€” count of matches, not page size).

Example​

import app.retorna.sdk.RetornaClient;
import app.retorna.sdk.RetornaClientBuilder;
import app.retorna.sdk.core.environment.RetornaEnvironment;
import app.retorna.sdk.models.order.ListOrdersParams;
import app.retorna.sdk.models.order.Order;
import app.retorna.sdk.models.order.OrdersListResponse;

RetornaClient client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(System.getenv("RETORNA_CLIENT_ID"))
.clientSecret(System.getenv("RETORNA_CLIENT_SECRET"))
.privateKey(System.getenv("RETORNA_PRIVATE_KEY"))
.buildClient();

String cursor = null;
do {
OrdersListResponse page = client.listOrders(
cursor == null ? ListOrdersParams.firstPage(20)
: new ListOrdersParams(cursor, 20, null, null, null, null));

for (Order order : page.data()) {
System.out.printf("%s %s %s%n", order.id(), order.status(), order.amount());
}
cursor = page.pagination().nextCursor();
} while (cursor != null);

Errors​

  • IllegalArgumentException β€” an empty (but non-null) cursor or idempotencyKey, or a limit outside 1..100.
  • RetornaB2BException with codeEnum() one of: B2B_INVALID_PAGINATION_CURSOR β€” restart the walk without a cursor, B2B_UNAUTHORIZED, B2B_RATE_LIMITED β€” retryable, B2B_UNKNOWN.
  • RetornaAuthException β€” token exchange failure.
  • RetornaSdkException β€” network failure or deserialization failure.

Notes​

  • See pagination for the full cursor contract: keep limit and filters fixed for the whole walk, and treat the cursor as opaque.
  • idempotencyKey is an exact match on your idempotency key β€” often faster than paging when you already know which order you are looking for.

API reference​

GET /orders