Skip to main content
A payment order collects a debt right away from the bank account the user registered with TapiPay. In a single request, POST /v2/debts/orders registers the debt and requests the charge to their account.

When to use a payment order

Payment order

A one-off charge you want to trigger now, with the account the user already registered. For example, an extra charge or a payment the user approved in your app.

Direct debit

If the debts of a product should be collected automatically every time they are due.

Debt

If the user pays whenever they want, through its paymentUrl, with the method they choose.
A payment order does not require the user to be subscribed to a product (POST /adhesions). It only requires them to have their bank account registered.

Prerequisites

  • Your company must have payment orders and direct debit enabled (configured with your Tapi account executive).
  • The user must exist as a contact. This endpoint does not create contacts inline.
  • The user must have registered their bank account on the enrollment page (not through the API). You can check it with GET /payment-methods.

Create a payment order

Fields

string
required
Your unique identifier for the order, up to 250 characters. It is the idempotency key: if you retry, use the same value. The debtId of the resulting debt is debt_<externalRequestId>. See Retries.
string
required
The user’s identifier, the same one used when they registered their account. It must match an existing contact.
number
required
Amount to charge in pesos, with up to 2 decimal places (minimum 0.01), same as in debts.
string
required
Which method is charged. For now the only value is BANK_ACCOUNT (the registered bank account).
string
The account to charge, as returned by GET /payment-methods. It must be an active account of the user and of the type set in paymentMethodType. If you do not send it, the user’s default account is charged.
string
Due date of the debt, in YYYY-MM-DD format. If you do not send it, today’s date in Mexico City plus 7 days is used.
string
Free text of up to 255 characters. It cannot be empty.
object
Plain object with your own data. It follows the same rules as in debts. See API conventions.
string
Only if your client has several companies. See API conventions.
The endpoint only accepts these fields. Any other one returns 400 INVALID_REQUEST, with the rejected field in details[].field.

The response

201 response
The response has two objects:
  • debt: the debt that was registered. It is a debt like any other: you can read it with GET /debts/{debtId}. It does not allow partial payments.
  • order: the charge to the user’s account. estimatedProcessingDate is the estimated charge date (YYYY-MM-DD). For now it is always null.

Order statuses

The charge is processed asynchronously: the order starts in PROCESSING and changes status when the bank responds. The result of the charge reaches you through a webhook: see Order payment. You can also query the order with GET /v2/debts/orders.

Query an order

200 response
externalRequestId is required and is the same one you sent when creating the order. data has the same shape as order in the creation response. If there is no order with that externalRequestId, the response is 404 RESOURCE_NOT_FOUND.

Retries and idempotency

externalRequestId is the idempotency key of the order. This is how a retry with the same value behaves:
On a 500 INTERNAL_ERROR from POST /v2/debts/orders, you do not know whether the charge was requested. Always retry with the same externalRequestId, never with a new one: this way you avoid charging the user twice. If the retry responds 409, query the order.

Errors

In these two endpoints, a companyCode that is not yours responds 403 with the error envelope (error.code: RESOLUTION_ERROR and requestId), not 422 as in the rest of the API. See Error handling.