> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wava.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Orders

> Create payment orders using the Wava API with any available gateway.

# Creating Orders

Once you have discovered the available gateways via [Gateway Discovery](/orders/gateway-discovery), you can create an order to initiate a payment.

## Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `amount` | number | Yes | Payment amount in the smallest currency unit (COP has no decimals). |
| `description` | string | Yes | Description shown to the buyer during payment. |
| `currency` | string | Yes | Currency code. Currently `COP` for Colombian gateways. |
| `shopper` | object | Yes, except Breb | Buyer data. **Optional for Breb**: see [Breb without shopper](#breb-orders-without-shopper). |
| `shopper.first_name` | string | No | Buyer's first name. |
| `shopper.last_name` | string | No | Buyer's last name. |
| `shopper.email` | string | Yes, except Breb | Buyer's email address. |
| `shopper.phone_number` | string | Yes, except Breb | Buyer's phone number. **Used as the payment identifier for Nequi.** |
| `shopper.country` | string | Yes, except Breb | ISO country code, e.g. `CO`. |
| `shopper.id_number` | string | Yes, except Breb | Buyer's national ID number (cedula). |
| `shopper.id_type` | integer | Yes, except Breb | Document type ID from [Document Types](/orders/document-types) endpoint. e.g. `1` for CC. |
| `payment_gateway.id_payment_gateway` | number | Yes | Gateway ID from [Gateway Discovery](/orders/gateway-discovery). |
| `order_key` | string | No | Your unique reference for this order (idempotency key, scoped to your store). See [Resending an order\_key](#resending-an-order-key). |
| `redirect_link` | string | No | URL to redirect buyer after successful payment. |
| `redirect_link_cancel` | string | No | URL to redirect buyer if payment is cancelled. |
| `redirect_link_failure` | string | No | URL to redirect buyer if payment fails. |

<Warning>
  **Nequi and Daviplata require the shopper.** Their direct orders must include `email`, `phone_number`, `country`, `id_number` and `id_type`; omitting any of them returns a `422` validation error.
</Warning>

### Breb orders without shopper

For **Breb**, the `shopper` object is optional: the QR code and transfer key are generated from the order, not from the buyer's data. You can omit `shopper` entirely or send only the fields you have.

* Fields you do send are still validated for format (an invalid `email` returns `422`), but none of them is required.
* Who actually paid is reported by the payer's bank after the transfer is confirmed, and it is best-effort (see [Payer data](/payment-flows/breb#payer-data)).
* In webhooks and when reading the order, shopper fields you did not send arrive as `null` (the whole `shopper` object can be `null`). After confirmation, `first_name` and `last_name` may be filled with the payer's name. Email and phone number are never guaranteed for Breb.

<Note>
  The API also accepts `national_id_number` and `id_national_document_type` as aliases for `id_number` and `id_type` respectively. Both formats are interchangeable.
</Note>

## Examples

<Note>
  The `id_payment_gateway` value in these examples is a placeholder. Always retrieve the correct ID for each gateway from the [Gateway Discovery](/orders/gateway-discovery) endpoint (`GET /v1/orders/paymentGateways`) — do not hardcode it.
</Note>

<Tabs>
  <Tab title="Nequi">
    Nequi uses the buyer's `phone_number` to send a push notification. National ID fields are still required for compliance.

    ```bash theme={null}
    curl -X POST "https://api.wava.co/v1/orders" \
      -H "merchant-key: YOUR_MERCHANT_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "amount": 50000,
        "description": "Premium subscription",
        "currency": "COP",
        "shopper": {
          "first_name": "Juan",
          "last_name": "Perez",
          "email": "juan@email.com",
          "phone_number": "+573001234567",
          "country": "CO",
          "id_number": "1234567890",
          "id_type": 1
        },
        "payment_gateway": {
          "id_payment_gateway": GATEWAY_ID
        },
        "order_key": "order-12345"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "result": {
        "id_order": 12345,
        "status": "processing",
        "payment_gateway": {
          "nequi": {
            "phone_number": "****567"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Daviplata">
    Daviplata uses the buyer's national ID to initiate the OTP flow. The buyer receives an OTP via SMS.

    Daviplata only accepts the following document types: **CC** (Cédula de Ciudadanía), **CE** (Cédula de Extranjería), and **TI** (Tarjeta de Identidad).

    ```bash theme={null}
    curl -X POST "https://api.wava.co/v1/orders" \
      -H "merchant-key: YOUR_MERCHANT_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "amount": 75000,
        "description": "Product purchase",
        "currency": "COP",
        "shopper": {
          "first_name": "Maria",
          "last_name": "Gonzalez",
          "email": "maria@email.com",
          "phone_number": "+573001234567",
          "country": "CO",
          "id_number": "12345678",
          "id_type": 1
        },
        "payment_gateway": {
          "id_payment_gateway": GATEWAY_ID
        },
        "order_key": "order-67890"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "result": {
        "id_order": 12346,
        "status": "processing",
        "daviplata_token_required": true,
        "payment_gateway": {
          "daviplata": {
            "national_id_number": "****678",
            "id_national_document_type": 1,
            "id_type": "CC"
          }
        }
      }
    }
    ```

    After receiving this response, you must submit the OTP. See [Daviplata flow](/payment-flows/daviplata) for the full OTP submission step.
  </Tab>

  <Tab title="Breb">
    Breb generates a QR code and transfer key from the order. It has no gateway-specific fields, and the `shopper` object is optional (see [Breb orders without shopper](#breb-orders-without-shopper)).

    The payer's data (name and masked document) arrives after the payment is confirmed and is best-effort. Email and phone number are not guaranteed for Breb payers.

    ```bash theme={null}
    curl -X POST "https://api.wava.co/v1/orders"       -H "merchant-key: YOUR_MERCHANT_KEY"       -H "Content-Type: application/json"       -d '{
        "amount": 100000,
        "description": "Invoice payment",
        "currency": "COP",
        "payment_gateway": {
          "id_payment_gateway": GATEWAY_ID
        },
        "order_key": "invoice-11111"
      }'
    ```

    **Response:**

    ```json theme={null}
    {
      "result": {
        "id_order": 12347,
        "status": "processing",
        "payment_gateway": {
          "breb": {
            "qr_code": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEA...",
            "key": "BREB-TXN-2025-ABCDEF123456"
          }
        }
      }
    }
    ```

    Display the QR code and key to the buyer. See [Breb flow](/payment-flows/breb) for display guidelines.
  </Tab>
</Tabs>

## Document types

The `POST /orders` response includes an `allowed_documents` array with the valid document types for the store's country. Use this field instead of calling `GET /v1/national-document-types/{countryCode}` separately.

```json theme={null}
"allowed_documents": [
  { "id_national_document_type": 1, "country_code": "CO", "type": "CC", "description": "Cédula de Ciudadanía" },
  { "id_national_document_type": 2, "country_code": "CO", "type": "CE", "description": "Cédula de Extranjería" },
  { "id_national_document_type": 3, "country_code": "CO", "type": "TI", "description": "Tarjeta de Identidad" }
]
```

The `id_type` field requires the integer ID (`id_national_document_type`) from this list. The legacy endpoint `GET /v1/national-document-types/{countryCode}` still works but is deprecated.

For Colombia, the most common types are:

| ID | Code | Description | Accepted by |
| - | - | - | - |
| 1 | CC | Cédula de Ciudadanía | All gateways |
| 2 | CE | Cédula de Extranjería | All gateways |
| 3 | TI | Tarjeta de Identidad | All gateways |

<Warning>
  **Daviplata** only accepts CC, CE, and TI document types. Sending a different document type will result in a payment error.
</Warning>

## What happens next

After creating the order, the payment flow depends on the selected gateway:

<CardGroup cols={2}>
  <Card title="Nequi" icon="mobile" href="/payment-flows/nequi">
    Buyer receives a push notification and approves in the Nequi app.
  </Card>

  <Card title="Daviplata" icon="message-sms" href="/payment-flows/daviplata">
    Buyer receives an OTP via SMS and submits it to confirm.
  </Card>

  <Card title="Breb" icon="qrcode" href="/payment-flows/breb">
    Buyer completes a transfer using a QR code or transfer key.
  </Card>

  <Card title="Stripe" icon="stripe" href="/payment-flows/stripe">
    Buyer is redirected to complete the card payment.
  </Card>
</CardGroup>

To track the order result, see [Order Status](/orders/order-status).

## Resending an order\_key

`order_key` identifies **one order** on your store. Use a unique `order_key` per order. Resending it is safe — it is how you retry after a timeout or a network error without creating a second order — and the response depends on the order that already exists for it.

A resend is the same order only if it has the **same `amount` and `currency`**. The rest of the body may change between attempts: a different `payment_gateway` (the buyer switches from Nequi to Daviplata), corrected `shopper` data or a new `description`.

| Existing order with that `order_key` | Response |
| - | - |
| None | A new order is created. |
| Different `amount` or `currency` | **`409 ORDER_KEY_CONFLICT`**. Nothing is created or changed. The body includes `existing_amount` and `existing_currency`. |
| Already paid (`confirmed` or `refunded`) | **`200`** with the existing order, `already_processed: true` and `api_code: "ORDER_ALREADY_PROCESSED"`. **No new payment is started**, and no payment data (push, OTP, QR) is returned. |
| `pending`, `processing` or `expired` | The payment is started again over **the same order**. A payment still in progress is cancelled first. |
| `cancelled` | Error `INVALID_ORDER_STATUS`: a cancelled order cannot be retried. Create a new order with a new `order_key`. |

```json Already paid theme={null}
{
  "status": "success",
  "result": {
    "id_order": 159537,
    "id_external": "order-12345",
    "purchase_date": "2026-09-01 10:00:00",
    "status": "confirmed",
    "total_price": "50000.00",
    "currency": "COP",
    "wava_fee": null,
    "net_to_merchant": null,
    "already_processed": true,
    "api_code": "ORDER_ALREADY_PROCESSED",
    "message": "Order already processed",
    "isDynamicLink": false
  }
}
```

<Warning>
  Do not reuse an `order_key` for a different payment — for example, several payments against the same invoice. A resend with another amount answers `409`, and one with the same amount resolves to the existing order. Use a distinct `order_key` per payment.
</Warning>

## Partners

If you are a partner creating orders on behalf of a store, the request body is identical. The only difference is the authentication headers. See [Partners — Creating Orders](/partners/creating-orders) for details.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.