Skip to Content
Core ConceptsOrders & Order Types

Orders & Order Types

Orders create — quick reference

Authoritative schema: npx @koyweforest/cli orders create --schema prints the full, up-to-date JSON schema for the create request. If the summary below ever diverges from that output, the CLI schema is the source of truth.

Endpoint (PAYIN / PAYOUT / BALANCE_TRANSFER / PAYMENT_LINK / INTER_MERCHANT_TRANSFER): POST /organizations/{orgId}/merchants/{merchantId}/orders

ONRAMP and OFFRAMP are not created via this endpoint. Crypto operations go through the deals endpoint (POST /organizations/{orgId}/merchants/{merchantId}/deals) because a deal can be paid in full or across multiple partial payments, each of which creates its own order. See the ONRAMP and OFFRAMP sections below, or use npx @koyweforest/cli flow deal.

Required fields:

  • type — always required.
  • originCurrencySymbol, destinationCurrencySymbol — required unless you pass quoteId (in which case omit them along with amountIn/amountOut; the quote carries all three).

type enum (7 values — ONRAMP and OFFRAMP route via /deals, the rest via /orders):

PAYIN · PAYOUT · BALANCE_TRANSFER · PAYMENT_LINK · INTER_MERCHANT_TRANSFER — via /orders

ONRAMP · OFFRAMP — via /deals (see below)

Amount specification (mutually exclusive — pick exactly one):

  • amountIn — amount in origin currency.
  • amountOut — amount in destination currency.
  • quoteId — ID of a prior quote that locks the rate. When you pass quoteId, omit originCurrencySymbol, destinationCurrencySymbol, amountIn, and amountOut — the quote supplies them.

Conditional requirements (for types that route via /orders):

Order typeAlso required
PAYINpaymentMethods (exactly one element)
PAYOUTdestinationAccountId
BALANCE_TRANSFERAn active policy with a matching rule (see Passkeys & Approvals). Auto-sets isMerchantSelfOrder=true if not provided.
PAYMENT_LINKpaymentMethods may be []
INTER_MERCHANT_TRANSFERdestinationMerchantId

For ONRAMP / OFFRAMP see the Deals sections — those types require destinationAccountId and a network from the enum below.

network enum (ONRAMP/OFFRAMP, passed on the deal):

ETHEREUM · POLYGON · SOLANA · TRON · BSC · BITCOIN · BASE · ALGORAND

paymentMethods shape:

[ { "method": "KHIPU" } ]
[ { "method": "PSE", "extra": { "bankAccount": { "name": "BANCOLOMBIA" } } } ]

Policy & MFA: Operations gated by policy return POL00007 (428 Precondition Required) and the order enters ON_HOLD until approved. Pass --mfa-token <token> to confirm inline, or use npx @koyweforest/cli flow order --wait to block on polling.

See the full CLI reference for orders create, the Error Code Catalog for every OR* / BAA* / POL* code, and the complete orders API spec.


Orders are the core transaction entities in Koywe Payments. Each order type serves a specific purpose in your payment operations.

Order Types Overview

Koywe Payments supports seven distinct order types:

TypePurposeOriginDestinationUse Case
PAYINAccept customer paymentsExternal (customer)Virtual balanceE-commerce checkout
PAYOUTPay providersVirtual balanceExternal (provider bank)Vendor payments
BALANCE_TRANSFERCurrency exchangeVirtual balance (currency A)Virtual balance (currency B)Convert COP to USD
ONRAMPBuy cryptoVirtual balance (fiat)Crypto walletBuy USDC with COP
OFFRAMPSell cryptoCrypto walletVirtual balance (fiat)Sell BTC for COP
PAYMENT_LINKPayment linkExternal (customer)Virtual balanceInvoice payment
INTER_MERCHANT_TRANSFERMove funds between merchants in the same organizationVirtual balance (merchant A)Virtual balance (merchant B)Treasury operations within one organization

Order Status Lifecycle

All orders follow a similar status progression:

Status Descriptions:

StatusDescriptionActions Available
PENDINGOrder created, waiting for paymentCancel, Check status
ON_HOLDHeld pending MFA verification or human approval under an active policy (POL00007 at creation). See Policy & MFA and Passkeys & Approvals.Approve / reject via dashboard, provide --mfa-token, or poll with npx @koyweforest/cli flow order --wait
PROCESSINGPayment being processedCheck status
PAIDPayment confirmed, settlement in progressCheck status
COMPLETEDFunds delivered, order completeView details
FAILEDPayment or settlement failedRetry, Contact support
CANCELLEDOrder cancelled (or approval rejected)View details
EXPIREDPayment window expiredCreate new order

PAYIN - Accept Customer Payments

Accept payments from customers into your virtual balance.

When to Use

  • E-commerce checkout
  • Service payments
  • Subscription billing
  • Invoice payments
  • Donation collection

Flow Diagram

Required Fields

{ "type": "PAYIN", // Order type "originCurrencySymbol": "COP", // Fiat currency "destinationCurrencySymbol": "COP", // Same as origin "amountIn": 50000, // Amount to collect "description": "Payment for Order #12345", // Customer-facing description "paymentMethods": [ // At least one payment method { "method": "PSE", // Payment method code "extra": { "bankAccount": { "name": "BANCOLOMBIA" } } // Per-method extras } ], "successUrl": "https://yoursite.com/success", // Redirect after success "failedUrl": "https://yoursite.com/failed" // Redirect after failure }

Optional Fields

{ "contactId": "cnt_abc123", // Link to customer contact "externalId": "order-12345", // Your internal reference "metadata": { "orderId": "12345" }, // Custom data "dueDate": "2025-11-14T23:59:59Z" // Payment deadline }

Example

async function createPayinOrder(token, orgId, merchantId) { const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'PAYIN', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'COP', amountIn: 50000, description: 'Payment for Order #12345', externalId: `order-${Date.now()}`, paymentMethods: [ { method: 'PSE', extra: { bankAccount: { name: 'BANCOLOMBIA' } } } ], successUrl: 'https://yoursite.com/success', failedUrl: 'https://yoursite.com/failed' }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); return response.data; } const order = await createPayinOrder(token, orgId, merchantId); console.log('Payment URL:', order.paymentUrl); // Redirect customer to order.paymentUrl

Complete PAYIN Integration Guide →


PAYOUT - Pay Providers

Send payments from your virtual balance to external bank accounts.

When to Use

  • Vendor payments
  • Contractor payouts
  • Refunds to customers
  • Affiliate commissions
  • Partner settlements

Flow Diagram

Required Fields

{ "type": "PAYOUT", // Order type "originCurrencySymbol": "COP", // Fiat currency "destinationCurrencySymbol": "COP", // Same as origin "amountIn": 100000, // Amount to send "destinationAccountId": "ba_xyz789", // Provider's bank account ID "description": "Payment for Invoice #456" // Internal description }

Optional Fields

{ "contactId": "cnt_provider123", // Link to provider contact "externalId": "invoice-456", // Your internal reference "metadata": { "invoiceId": "456" } // Custom data }

Example

async function createPayoutOrder(token, orgId, merchantId, contactId, bankAccountId) { // 1. Check balance first const balances = await getMerchantBalances(token, orgId, merchantId); const copBalance = balances.find(b => b.currencySymbol === 'COP'); if (copBalance.availableBalance < 100000) { throw new Error('Insufficient balance'); } // 2. Create payout order const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'PAYOUT', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'COP', amountIn: 100000, contactId: contactId, destinationAccountId: bankAccountId, description: 'Payment for Invoice #456', externalId: `invoice-456-${Date.now()}` }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); return response.data; } const payout = await createPayoutOrder(token, orgId, merchantId, 'cnt_provider', 'ba_xyz789'); console.log('Payout created:', payout.id);

Important: Always check your virtual account balance before creating PAYOUT orders. The order will fail if you have insufficient funds.

Complete PAYOUT Integration Guide →


BALANCE_TRANSFER - Currency Exchange

Transfer funds between different currency virtual accounts (instant currency exchange).

When to Use

  • Convert COP to USD for international payments
  • Rebalance currency holdings
  • Lock in exchange rates
  • Prepare funds for specific currency payouts

Flow Diagram

Required Fields

{ "type": "BALANCE_TRANSFER", // Order type "originCurrencySymbol": "COP", // Source currency "destinationCurrencySymbol": "USD", // Target currency "amountIn": 1000000 // Amount to convert (1M COP) }

Example

async function transferCurrency(token, orgId, merchantId) { // 1. Get quote for exchange rate const quote = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`, { type: 'BALANCE_TRANSFER', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'USD', amountIn: 1000000 }, { headers: { 'Authorization': `Bearer ${token}` } } ); console.log('Exchange rate:', quote.data.exchangeRate); console.log('Will receive:', quote.data.amountOut, 'USD'); // 2. Create transfer order — passing quoteId locks rate & amount, so omit // originCurrencySymbol / destinationCurrencySymbol / amountIn / amountOut const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'BALANCE_TRANSFER', quoteId: quote.data.id }, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } const transfer = await transferCurrency(token, orgId, merchantId); console.log('Transfer completed instantly:', transfer.status); // "COMPLETED"

Instant Settlement: BALANCE_TRANSFER orders complete instantly. No waiting for external confirmations.

Complete Balance Transfer Guide →


ONRAMP - Buy Cryptocurrency

Convert fiat currency to cryptocurrency.

Uses Deals Endpoint: ONRAMP operations use the /deals endpoint. Deals can be paid in full or partially, with each payment creating orders that execute the crypto purchase.

When to Use

  • Buy crypto for treasury
  • Offer crypto purchases to users
  • Hedge with stablecoins
  • Pay crypto-native providers

Supported Cryptocurrencies

SymbolNameNetworks
USDCUSD CoinEthereum, Polygon, BSC
USDTTetherEthereum, Polygon, BSC
ETHEthereumEthereum
BTCBitcoinBitcoin
MATICPolygonPolygon
BNBBNBBSC

Required Fields for Quote

{ "type": "ONRAMP", "originCurrencySymbol": "COP", // Fiat currency "destinationCurrencySymbol": "USDC", // Crypto currency "amountIn": 50000 // Fiat amount }

Required Fields for Deal

{ "type": "ONRAMP", "destinationAccountId": "wallet_abc123", // Crypto wallet ID "quoteId": "quote_xyz789" // Quote ID }

Simplified: Deals only need the destination account and quote ID. The amounts and currencies come from the quote.

Example

async function buyUSDC(token, orgId, merchantId, walletId) { // 1. Get quote const quote = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`, { type: 'ONRAMP', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'USDC', amountIn: 50000 }, { headers: { 'Authorization': `Bearer ${token}` } } ); console.log('Will receive:', quote.data.amountOut, 'USDC'); console.log('Exchange rate:', quote.data.exchangeRate); console.log('Network fee:', quote.data.networkFee); // 2. Create deal (not order!) const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/deals`, { type: 'ONRAMP', destinationAccountId: walletId, quoteId: quote.data.id }, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } const deal = await buyUSDC(token, orgId, merchantId, 'wallet_abc123'); console.log('ONRAMP deal created:', deal.id); console.log('Deal can be paid in full or partially');

Partial Payments: ONRAMP deals can be paid in multiple installments. Each payment creates an order that purchases the proportional amount of crypto. Great for dollar-cost averaging!

Balance Required: By default, sufficient balance in your virtual account is required to close an ONRAMP deal. Deals execute automatically when funds are credited to your account. Pre-approved merchants can operate without upfront balance.

Complete ONRAMP Guide →


OFFRAMP - Sell Cryptocurrency

Convert cryptocurrency to fiat currency.

Uses Deals Endpoint: OFFRAMP operations use the /deals endpoint. Unlike ONRAMP, OFFRAMP deals must be paid completely (no partial payments). The deal creates orders when fully funded.

When to Use

  • Sell crypto holdings
  • Convert crypto payments to fiat
  • Realize crypto gains
  • Prepare fiat for operations

Required Fields for Quote

{ "type": "OFFRAMP", "originCurrencySymbol": "USDC", // Crypto currency "destinationCurrencySymbol": "COP", // Fiat currency "amountIn": 10 // Crypto amount (10 USDC) }

Required Fields for Deal

{ "type": "OFFRAMP", "destinationAccountId": "va_cop_12345", // Virtual account ID "quoteId": "quote_xyz789" // Quote ID }

Complete Payment Only: OFFRAMP deals must be funded completely. Partial payments are not supported.

Example

async function sellUSDC(token, orgId, merchantId) { // 1. Get quote const quote = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`, { type: 'OFFRAMP', originCurrencySymbol: 'USDC', destinationCurrencySymbol: 'COP', amountIn: 10 // 10 USDC }, { headers: { 'Authorization': `Bearer ${token}` } } ); console.log('Will receive:', quote.data.amountOut, 'COP'); // 2. Create deal (not order!) const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/deals`, { type: 'OFFRAMP', destinationAccountId: 'va_cop_12345', // Virtual account for COP quoteId: quote.data.id }, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } const deal = await sellUSDC(token, orgId, merchantId); console.log('OFFRAMP deal created:', deal.id); console.log('Deposit address:', deal.depositAddress); console.log('Send full crypto amount to complete'); // Funds will be credited to COP virtual account after crypto received

Complete Funding: After creating the deal, you must send the full crypto amount to the provided deposit address. Once received, the deal creates orders and credits your virtual account with fiat.

Complete OFFRAMP Guide →


Generate shareable payment links with a complete Koywe-branded checkout flow - no contact or payment method needed upfront!

user-slashNo Contact Required

Customer enters their own information in the checkout

💳No Payment Method

Customer selects their preferred payment method

window-maximizeKoywe-Branded UI

Beautiful, secure checkout hosted by Koywe

share-nodesShare Anywhere

Send via email, WhatsApp, SMS, or QR code

When to Use

  • E-commerce checkout: Simple payment collection without complex integration
  • Invoice payments: Send payment link for issued invoices
  • Email/WhatsApp: Share payment requests directly
  • QR code payments: Generate QR for in-person payments
  • One-time collections: Quick payment requests without storing customer data

How It Works

Differences from PAYIN

FeaturePAYINPAYMENT_LINK
ContactOptional but recommendedNot needed - customer enters data
Payment MethodMust be specifiedCustomer selects from all available
Checkout UIRedirect to payment providerKoywe-branded checkout flow
Data CollectionYou collect customer dataKoywe collects customer data
Best ForIntegrated checkout experienceStandalone payment requests

Minimal Required Fields

That’s it! No contact, no payment method, no customer details needed. Just amount and description.

{ "type": "PAYMENT_LINK", // Order type "originCurrencySymbol": "COP", // Currency "destinationCurrencySymbol": "COP", // Same as origin "amountIn": 75000, // Amount to collect "description": "Invoice #789" // Shows to customer }

Optional Fields

{ "dueDate": "2025-11-14T23:59:59Z", // Link expiry "externalId": "invoice-789", // Your reference "successUrl": "https://yoursite.com/success", // Redirect after payment "failedUrl": "https://yoursite.com/failed" // Redirect on failure }

Complete Example

// Minimal example - just create and share! async function createPaymentLink(amount, description) { const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'PAYMENT_LINK', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'COP', amountIn: amount, description: description }, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } // Usage const link = await createPaymentLink(75000, 'Invoice #789 - Web Design'); console.log('Share this link:', link.paymentUrl); // Send via email, WhatsApp, SMS, or generate QR code await sendEmail(customerEmail, { subject: 'Payment Request - Invoice #789', body: `Please pay here: ${link.paymentUrl}` });
// Full example with all options async function createPaymentLinkWithOptions(invoiceData) { const dueDate = new Date(); dueDate.setHours(dueDate.getHours() + 24); // Expires in 24h const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'PAYMENT_LINK', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'COP', amountIn: invoiceData.amount, description: invoiceData.description, externalId: invoiceData.invoiceNumber, dueDate: dueDate.toISOString(), successUrl: 'https://yoursite.com/payment/success', failedUrl: 'https://yoursite.com/payment/failed' }, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } // Usage const link = await createPaymentLinkWithOptions({ amount: 150000, description: 'Monthly Subscription - November 2025', invoiceNumber: 'INV-2025-11-789' }); console.log('Payment link:', link.paymentUrl);
def create_payment_link(amount, description): response = requests.post( f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/orders', json={ 'type': 'PAYMENT_LINK', 'originCurrencySymbol': 'COP', 'destinationCurrencySymbol': 'COP', 'amountIn': amount, 'description': description }, headers={'Authorization': f'Bearer {token}'} ) return response.json() # Usage link = create_payment_link(75000, 'Invoice #789 - Web Design') print(f"Share this link: {link['paymentUrl']}")

Response:

{ "id": "ord_abc123", "type": "PAYMENT_LINK", "status": "PENDING", "paymentUrl": "https://checkout.koywe.com/pay/ord_abc123", "amountIn": 75000, "originCurrencySymbol": "COP", "description": "Invoice #789 - Web Design", "createdAt": "2025-11-13T15:00:00Z" }

Customer Experience: When customers open the payment link, they’ll see a Koywe-branded checkout where they can:

  1. Review payment details
  2. Enter their personal information
  3. Select their preferred payment method (PSE, PIX, Nequi, etc.)
  4. Complete the payment

Order Metadata and External IDs

External ID (Idempotency)

Use externalId to ensure idempotent order creation:

{ "externalId": "order-12345-20251113" // Your unique identifier }

Benefits:

  • Safe to retry failed requests
  • Prevents duplicate orders
  • Links to your internal systems

Metadata

Store custom data with orders:

{ "metadata": { "orderId": "12345", "customerId": "cust_67890", "source": "mobile_app", "campaign": "summer_sale" } }

Use cases:

  • Track order source
  • Store campaign information
  • Link to internal systems
  • Custom reporting fields

INTER_MERCHANT_TRANSFER - Move Funds Between Merchants

Move virtual-balance funds from one merchant to another merchant in the same organization, in the same currency, without hitting an external bank. Useful for treasury operations, fee settlement, and internal rebalancing across merchants you control.

When to Use

  • Consolidating balances across your own merchants within one organization
  • Settling internal commissions between a parent and child merchant
  • Rebalancing liquidity so a specific merchant has enough funds for an upcoming payout

Flow Diagram

Required Fields

  • typeINTER_MERCHANT_TRANSFER
  • destinationMerchantIdRequired. Merchant inside the same organization. Cross-organization transfers are rejected (IMT00002).
  • originCurrencySymbol / destinationCurrencySymbol — must be the same currency (IMT00008; same-currency is MVP behaviour).
  • amountIn or amountOut — one of the two (same rule as the other /orders types).

Example — Create Order

const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${sourceMerchantId}/orders`, { type: 'INTER_MERCHANT_TRANSFER', destinationMerchantId: 'mer_destination_abc', originCurrencySymbol: 'USD', destinationCurrencySymbol: 'USD', amountIn: 1000, description: 'July commission settlement' }, { headers: { 'Authorization': `Bearer ${token}` } } ); // Sandbox completes instantly like BALANCE_TRANSFER: console.log(response.data.status); // "COMPLETED"

Example — Response

{ "id": "ord_imt_xyz789", "type": "INTER_MERCHANT_TRANSFER", "status": "COMPLETED", "originMerchantId": "mer_source_123", "destinationMerchantId": "mer_destination_abc", "originCurrencySymbol": "USD", "destinationCurrencySymbol": "USD", "amountIn": 1000, "amountOut": 1000, "description": "July commission settlement", "createdAt": "2026-04-24T12:00:00Z", "completedAt": "2026-04-24T12:00:01Z" }

Listing & Filtering

The OpenAPI spec’s orders list filter enum omits INTER_MERCHANT_TRANSFER today. Despite that, the query parameter ?type=INTER_MERCHANT_TRANSFER does filter correctly against the API — the omission is a spec gap, not a runtime one.

# Via CLI (the CLI reflects all 7 types correctly): npx @koyweforest/cli orders list --type INTER_MERCHANT_TRANSFER --format table # Via raw HTTP: curl -H "Authorization: Bearer $TOKEN" \ "https://api-sandbox.koywe.com/api/v1/organizations/$ORG/merchants/$MERCHANT/orders?type=INTER_MERCHANT_TRANSFER"

Common Errors

CodeCauseFix
IMT00001Destination merchant not foundCheck destinationMerchantId exists
IMT00002Destination merchant is in a different organizationTransfers are restricted to same-org merchants
IMT00003Source and destination merchant are the sameUse BALANCE_TRANSFER for same-merchant currency exchange
IMT00004Destination merchant is disabledEnable the merchant or pick another destination
IMT00005Insufficient balance in source merchant accountFund the source account or reduce the amount
IMT00007destinationMerchantId missingRequired field for INTER_MERCHANT_TRANSFER
IMT00008Origin and destination currency don’t matchSame-currency only (MVP)

See the full Error Code Catalog for every IMT* code.


Next Steps

Last updated on