logo
StartInvoices

Invoices

Invoices are the core of the Merchant API. Create an invoice, redirect the customer to the hosted payment page, receive webhook updates, and track the invoice status from your backend.

Create an invoice

POST /api/v1/create-invoice

Creates a new pending invoice and returns a hosted payment_link.

Request body

FieldTypeRequiredDescription
amountstringYesPayment amount in fiat currency, e.g. "1500.00". Maximum 2 decimal places.
currency_codestringYesISO 4217 currency code, 3 uppercase letters, e.g. "UAH".
customer_idstringYesUnique customer identifier in your system. Maximum 128 characters.
external_idstringYesYour unique order ID. Must be unique per merchant. Maximum 128 characters.
purposestringNoPayment description shown on the hosted payment page. Maximum 512 characters.
callback_urlstringRequired*Webhook URL for status notifications. Overrides merchant default if passed.
success_urlstringRequired*Redirect URL after successful payment. Overrides merchant default if passed.
fail_urlstringRequired*Redirect URL after failed, expired, or canceled payment. Overrides merchant default if passed.

callback_url, success_url, and fail_url may be omitted only if default values are already configured in merchant settings. Otherwise the API returns 422 MISSING_REQUIRED_URLS.

Example request

curl -X POST https://api.ecca-ex.com/api/v1/create-invoice \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: your_api_key_here" \
  -d '{
    "amount": "1500.00",
    "currency_code": "UAH",
    "customer_id": "user_12345",
    "external_id": "order-2026-0001",
    "purpose": "Premium subscription",
    "callback_url": "https://yoursite.com/webhooks/payment",
    "success_url": "https://yoursite.com/payment/success",
    "fail_url": "https://yoursite.com/payment/failed"
  }'

Example response

{
  "invoice_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "external_id": "order-2026-0001",
  "amount": "1500.00",
  "currency": "UAH",
  "status": "pending",
  "payment_link": "https://pay.app.com/a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "customer_id": "user_12345",
  "purpose": "Premium subscription",
  "callback_url": "https://yoursite.com/webhooks/payment",
  "success_url": "https://yoursite.com/payment/success",
  "fail_url": "https://yoursite.com/payment/failed",
  "created_at": "2026-02-25T12:00:00+00:00",
  "expires_at": "2026-02-25T12:20:00+00:00",
  "finished_at": null
}

Unlike list/detail endpoints, POST /api/v1/create-invoice returns the invoice object directly and does not wrap it in successful / data.

Response fields

FieldTypeDescription
invoice_idstringSystem-generated invoice UUID. Use this value as {order_id} in GET /api/v1/invoices/{order_id}.
external_idstringYour external_id echoed back.
amountstringRequested fiat amount.
currencystringCurrency code.
statusstringInvoice status. Initially pending.
payment_linkstringHosted payment page URL. Redirect the customer here.
customer_idstringYour customer identifier.
purposestring | nullPayment description.
callback_urlstring | nullEffective webhook URL for this invoice.
success_urlstring | nullEffective success redirect URL.
fail_urlstring | nullEffective fail redirect URL.
created_atstringInvoice creation timestamp in ISO 8601 format.
expires_atstringInvoice expiration timestamp in ISO 8601 format.
finished_atstring | nullFinalization timestamp. null while pending.

Get invoice details

GET /api/v1/invoices/{order_id}

Returns the current invoice state for the authenticated merchant.

You can request the invoice using:

  • invoice_id — the UUID returned by POST /api/v1/create-invoice
  • external_id — your own order identifier from invoice creation

Use whichever identifier is more convenient in your system: invoice_id for the payment provider-side reference, or external_id for your internal order lookup.

Example request by invoice_id

curl -X GET https://api.ecca-ex.com/api/v1/invoices/a1b2c3d4-5678-90ab-cdef-1234567890ab \
  -H "X-Api-Key: your_api_key_here"

Example request by external_id

curl -X GET https://api.ecca-ex.com/api/v1/invoices/order-2026-0001 \
  -H "X-Api-Key: your_api_key_here"

Example response

{
  "successful": true,
  "data": {
    "invoice_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "external_id": "order-2026-0001",
    "customer_id": "user_12345",
    "purpose": "Premium subscription",
    "amount": "1500.00",
    "currency": "UAH",
    "status": "success",
    "callback_url": "https://yoursite.com/webhooks/payment",
    "success_url": "https://yoursite.com/payment/success",
    "fail_url": "https://yoursite.com/payment/failed",
    "payment_link": "https://pay.app.com/a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "created_at": "2026-04-26T12:00:00+00:00",
    "expires_at": "2026-04-26T12:20:00+00:00",
    "finished_at": "2026-04-26T12:08:31+00:00",
    "method_selected": true,
    "deal": {
      "deal_id": "8f1b2c3d-4e5f-6789-90ab-cdef12345678",
      "status": "completed",
      "sub_status": null,
      "payment_method_code": "monobank",
      "payment_method_name": "Monobank UA",
      "amount_fiat": "1537.50",
      "conversion_rate": "41.50",
      "merchant_usdt": "35.42",
      "expires_at": "2026-04-26T12:30:00+00:00",
      "finished_at": "2026-04-26T12:08:31+00:00",
      "mark_paid_at": "2026-04-26T12:07:55+00:00"
    }
  }
}

Response basics

FieldTypeDescription
successfulbooleanIndicates whether the request succeeded.
data.invoice_idstringInvoice UUID / order ID.
data.external_idstringYour original order ID from invoice creation.
data.statusstringInvoice status: pending, success, fail, expired, or canceled.
data.method_selectedbooleantrue if the customer has already selected a payment method and a deal exists.
data.dealobject | nullDeal-level details. null until the customer selects a payment method.

Deal fields

When method_selected=true, the deal object may contain:

FieldTypeDescription
deal_idstringInternal deal UUID.
statusstringDeal status such as pending, completed, canceled, failed, appeal, or expired.
sub_statusstring | nullMore detailed deal sub-status.
payment_method_codestring | nullSelected payment method code.
payment_method_namestring | nullHuman-readable payment method name.
amount_fiatstring | nullFinal fiat amount the customer had to send.
conversion_ratestring | nullLocked USDT/fiat conversion rate at deal creation.
merchant_usdtstring | nullUSDT amount credited to merchant after successful completion.
expires_atstring | nullDeal expiration timestamp.
finished_atstring | nullDeal completion timestamp.
mark_paid_atstring | nullTime when the customer marked the payment as sent.

List invoices

GET /api/v1/invoices

Returns a paginated list of invoices for the authenticated merchant.

Query parameters

FieldTypeRequiredDescription
pageintegerNoPage number. Default: 1.
per_pageintegerNoItems per page. Default: 20, maximum: 500.
statusstringNoFilter by invoice status: pending, success, fail, expired, canceled.
currencystringNoFilter by currency code, case-insensitive.
orderstringNoSort by created_at: desc or asc. Default: desc.

Example request

curl -X GET "https://api.ecca-ex.com/api/v1/invoices?page=1&per_page=20&status=success&currency=UAH&order=desc" \
  -H "X-Api-Key: your_api_key_here"

Example response

{
  "successful": true,
  "page": 1,
  "per_page": 20,
  "total": 42,
  "total_pages": 3,
  "data": [
    {
      "invoice_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "external_id": "order-2026-0001",
      "customer_id": "user_12345",
      "purpose": "Payment for Premium subscription",
      "amount": "1500.00",
      "currency": "UAH",
      "status": "success",
      "callback_url": "https://yoursite.com/webhooks/payment",
      "success_url": "https://yoursite.com/payment/success",
      "fail_url": "https://yoursite.com/payment/failed",
      "payment_link": "https://pay.app.com/a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "created_at": "2026-04-26T12:00:00+00:00",
      "expires_at": "2026-04-26T12:20:00+00:00",
      "finished_at": "2026-04-26T12:08:31+00:00",
      "method_selected": true,
      "deal": {
        "deal_id": "8f1b2c3d-4e5f-6789-90ab-cdef12345678",
        "status": "completed",
        "sub_status": null,
        "payment_method_code": "monobank",
        "payment_method_name": "Monobank UA",
        "amount_fiat": "1537.50",
        "conversion_rate": "41.50",
        "merchant_usdt": "35.42",
        "expires_at": "2026-04-26T12:30:00+00:00",
        "finished_at": "2026-04-26T12:08:31+00:00",
        "mark_paid_at": "2026-04-26T12:07:55+00:00"
      }
    }
  ]
}

Invoice lifecycle

Invoice-level statuses:

StatusDescriptionFinal
pendingInvoice created and waiting for the customer flow to completeNo
successPayment completed successfullyYes
failPayment flow ended with failureYes
expiredInvoice expired before successful completionYes
canceledInvoice was canceledYes

The top-level invoice status is different from nested deal.status. Invoice status describes the merchant-facing payment result. Deal status describes the internal payment deal state when a payment method has already been selected.


Idempotency

The external_id field acts as an idempotency key per merchant. If you try to create another invoice with the same external_id, the API returns 409 DUPLICATE_EXTERNAL_ID.

Use a stable internal order number for external_id. This prevents accidental duplicate invoice creation during retries.


Rate limiting

Invoice creation is rate-limited per customer. If a customer accumulates too many unpaid invoices within a configured time window, the API returns 403 CUSTOMER_RATE_LIMIT.

Example error

{
  "successful": false,
  "request_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "error": {
    "code": "CUSTOMER_RATE_LIMIT",
    "message": "Customer created too many unpaid invoices",
    "details": {
      "window_minutes": 60,
      "limit": 5,
      "next_allowed_at": "2026-02-26T15:30:00+00:00",
      "customer_id": "user_12345"
    }
  }
}

Wait until next_allowed_at before creating a new invoice for that customer.


Invoice errors

HTTPCodeDescription
409DUPLICATE_EXTERNAL_IDAn invoice with this external_id already exists for the merchant.
403CUSTOMER_RATE_LIMITToo many unpaid invoices were created for this customer.
422CURRENCY_INVALIDCurrency code is invalid or disabled.
422PAYMENT_METHOD_NOT_FOUNDNo active payment method exists for the selected currency and amount range.
422AMOUNT_BELOW_MINAmount is lower than the minimum supported for this currency.
422AMOUNT_ABOVE_MAXAmount exceeds the maximum supported for this currency.
422MISSING_REQUIRED_URLSRequired URLs are missing in both the request and merchant defaults.
503DEALS_SYSTEM_DISABLEDInvoice creation is temporarily unavailable.
404INVOICE_NOT_FOUNDThe specified invoice was not found.
404INVOICES_NOT_FOUNDNo invoices matched the merchant query filters.