Skip to main content

Understanding Payment Orders

Every payment you process creates a payment order. Track the status, retrieve transaction details, and prevent duplicate charges automatically.

Create a Payment Order

Create a payment order to process card payments, SPEI transfers, or batch payments. Each payment type uses the same endpoint with different payment method configurations.
POST /payment-orders
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Card Payment Example

{
  "externalId": "order-123",
  "customer": {
    "externalId": "customer-abc",
    "firstName": "María",
    "lastName": "González",
    "email": "[email protected]",
    "phoneNumber": "+521555123456"
  },
  "billingAddress": {
    "address": "Av. Reforma 123",
    "city": "Mexico City",
    "state": "CDMX",
    "postalCode": "01000",
    "country": "MX"
  },
  "amount": 10000,
  "currency": "MXN",
  "description": "Order #12345",
  "paymentMethod": {
    "type": "card",
    "cardDetails": {
      "number": "4000000000002503",
      "expiryMonth": "12",
      "expiryYear": "25",
      "cvc": "123"
    }
  }
}
amount unit is the smallest currency unit (e.g., cents). So for MXN, 100 MXN = 10000 cents

Response

{
  "paymentOrder": {
    "id": "ord_abc123",
    "externalId": "order-123",
    "amount": 10000,
    "currency": "MXN",
    "status": "COMPLETED",
    "description": "Order #12345"
  },
  "customer": {
    "id": "cus_xyz789",
    "firstName": "María",
    "lastName": "González",
    "email": "[email protected]"
  },
  "paymentMethod": {
    "id": "pm_def456",
    "type": "card",
    "card": {
      "brand": "visa",
      "last4": "1111",
      "expiryMonth": "12",
      "expiryYear": "25"
    }
  }
}

Required Fields

FieldTypeRequiredDescription
externalIdstringYesYour unique order ID
amountintegerYesAmount in cents (10000 = $100.00)
currencystringYesISO currency code (MXN, USD)
customer.firstNamestringYesCustomer’s first name
customer.lastNamestringYesCustomer’s last name
customer.emailstringYesCustomer’s email address
paymentMethod.typestringYesPayment type (card, spei, etc.)

Order Status

Payment orders move through different states as they process:
StatusDescriptionAction
PENDINGPayment is being processedWait for completion
PROCESSINGPayment in progressWait for completion
AUTHORIZEDPayment authorized but not capturedCapture or void authorization
PARTIALLY_AUTHORIZEDPartial amount authorizedReview and process partial amount
ACTION_REQUIREDAdditional action neededCheck order details for next steps
COMPLETEDPayment successful ✓Fulfill the order
PARTIALLY_PAIDPartial payment receivedTrack remaining balance
FAILEDPayment declinedShow error to customer
PAYER_AUTHENTICATION_DEVICE_DATA_REQUIRED3DS device data collection neededShow invisible data collection iframe
PAYER_AUTHENTICATION_CHALLENGE_REQUIRED3DS challenge verification neededShow authentication challenge iframe
CANCELLATION_REQUESTEDCancellation in progressWait for cancellation to complete
CANCELLEDPayment cancelledOrder cancelled
REFUND_PROCESSINGRefund is being processedWait for refund completion
PARTIALLY_REFUNDEDPartial refund issuedUpdate order total
REFUNDEDFully refundedOrder fully refunded
Common Statuses: Most payment orders will only see PENDINGPROCESSINGCOMPLETED. The other statuses handle specific scenarios like 3DS authentication, authorizations, cancellations, and refunds.

Status Flow

Most successful payments go directly from PENDINGPROCESSINGCOMPLETED in 2-5 seconds.

3D Secure Flow (Summary)

When 3DS is required, the flow adds three steps:
  1. Collect device data (invisible iframe) when status is PAYER_AUTHENTICATION_DEVICE_DATA_REQUIRED.
  2. Check enrollment: POST /v2/payment-orders/:id/payer-authentication → result may be COMPLETED, FAILED, or PAYER_AUTHENTICATION_CHALLENGE_REQUIRED.
  3. If a challenge is required, display the challenge iframe using stepUpUrl and jwt, then validate with POST /v2/payment-orders/:id/payer-authentication/validate.
The authentication method (SMS, biometrics, app, etc.) is decided by the issuing bank, not by Cheqpay or the merchant, and can vary per transaction.

Full 3D Secure Guide

See detailed implementation steps and examples

Track Your Orders

Every payment order has two IDs:
  • Cheqpay ID - Our internal reference (e.g., ord_abc123)
  • External ID - Your order or transaction ID (e.g., order-12345)

Retrieve an Order

Use either ID to retrieve order details:
GET /payment-orders/:id
Authorization: Bearer YOUR_API_KEY

Example Request

curl -X GET https://prod.cheqpay.mx/payment-orders/ord_abc123 \
  -H "x-api-key: YOUR_API_KEY"

Example Response

{
  "id": "ord_abc123",
  "externalId": "order-12345",
  "status": "COMPLETED",
  "amount": 10000,
  "currency": "MXN",
  "description": "Product purchase",
  "customer": {
    "id": "cus_xyz789",
    "firstName": "María",
    "lastName": "González",
    "email": "[email protected]"
  },
  "paymentMethod": {
    "type": "card",
    "card": {
      "brand": "visa",
      "last4": "1111"
    }
  },
  "createdAt": "2025-10-30T10:00:00.000Z",
  "completedAt": "2025-10-30T10:00:05.000Z"
}

What’s Included

Current status and timestamps for all state changes
Complete customer details including contact information
Masked card information or payment method used
Original amount, refunded amounts, and net total
Created, processed, completed, and updated timestamps

Prevent Duplicate Charges

Cheqpay automatically prevents duplicate payments using the externalId field. If you send the same request twice, we’ll handle it intelligently:
{
  "externalId": "order-12345"
}

Smart Duplicate Detection

Payment Successful

Returns existing payment (no duplicate charge)

Payment Pending

Returns pending payment (no new request)

Payment Failed

Creates new payment (allows retry)

How It Works

1

First Request

You create a payment with externalId: "order-12345" and it succeeds.
2

Duplicate Request

Network issue causes the request to be sent again with the same externalId.
3

Protected

Cheqpay recognizes the duplicate and returns the existing successful payment. No duplicate charge.
Always use your order ID or transaction ID as the externalId. This protects your customers from being charged twice due to network issues or user errors.

Best Practice

// ✅ Good - Use your order ID
const payment = await createPayment({
  externalId: `order-${orderId}`,
  amount: 10000,
  // ...
});

// ❌ Bad - Random or missing ID
const payment = await createPayment({
  externalId: Math.random().toString(),
  amount: 10000,
  // ...
});

List Payment Orders

Retrieve a list of payment orders for reporting and reconciliation:
GET /payment-orders?limit=20&offset=0
Authorization: Bearer YOUR_API_KEY

Query Parameters

ParameterTypeDescription
limitintegerNumber of results (default: 20, max: 100)
offsetintegerPagination offset (default: 0)
statusstringFilter by status
customerIdstringFilter by customer ID
startDatedateFilter from date (ISO 8601)
endDatedateFilter to date (ISO 8601)

Monitoring Payment Status

You can check payment order status at any time using the GET endpoint to retrieve the latest information.

Next Steps