Automatic charging with domiciliación
Your customer authorizes once; every invoice is then debited from their bank account in bolívares at the day’s rate. No links to chase, no manual payments.
How it works
Domiciliación is a standing authorization the customer gives their bank to pay you. With collectionMethod: "charge_automatically", VEX Pay debits each invoice from the customer’s bank account in bolívares, at your account’s current rate (BCV or market) at the moment of the debit, without the customer doing anything. Prices stay in dollars.
- Send the authorization link
Create a setup session for the customer and send them its
url(by WhatsApp, email or a redirect from your app). - The customer authorizes
On the page “Domiciliación bancaria” they confirm their name, cédula/RIF, phone and bank and accept the authorization text. VEX Pay sends the request to their bank and attaches a payment method in status
pending. - The customer accepts in online banking
The last step happens at their bank: they open online banking and accept the domiciliación request. The page tells them so. Once accepted it is active right away and does not expire: it stays in place until the customer cancels it at their bank.
- Subscribe with automatic charging
Create the subscription with
charge_automatically. Each invoice is debited on its collection attempts; the first accepted debit makes the payment methodactive.
Step 01
Create the authorization link
curl --request POST "${API_URL}/v1/setup-sessions" \
--header "content-type: application/json" \
--header "x-api-key: ${VEXPAY_API_KEY}" \
--data '{
"customer": "cus_…",
"successUrl": "https://example.com/cuenta/listo"
}'const session = await vexpay.setupSessions.create({
customer: 'cus_…',
successUrl: 'https://example.com/cuenta/listo',
});
// Send session.url to the customer now: it is only returned here.session = vexpay.setup_sessions.create({
"customer": "cus_…",
"successUrl": "https://example.com/cuenta/listo",
})$session = $vexpay->setupSessions->create([
'customer' => 'cus_…',
'successUrl' => 'https://example.com/cuenta/listo',
]);{
"id": "seti_3fd84b2d9ad14f74a2d90f2f56984db5",
"object": "setup_session",
"url": "https://pay.vexwallet.co/billing/setup/7c1e…",
"customer": "cus_…",
"status": "open",
"paymentMethod": null,
"successUrl": "https://example.com/cuenta/listo",
"expiresAt": "2026-10-22T14:00:00.000Z",
"createdAt": "2026-10-21T14:00:00.000Z",
"livemode": false
}- The
urlis valid for 24 hours and only once, and it is returned only in this response — send it right away.GET /v1/setup-sessions/:idreturns the session without it. statusisopen,complete(authorized;paymentMethodis set) orexpired. Create a new session if it expired. Only the link expires: the domiciliación the customer authorizes with it does not.- Save the customer’s
phone,idNumberandbankCodeon the customer first, and the page arrives prefilled. successUrl(https) adds a “Volver a <your business>” button after the customer authorizes.
Step 02
What the customer sees
A page in your name titled Domiciliación bancaria with: holder name, cédula or RIF, the phone linked to their account, their bank, and this authorization, which they must tick:
After Autorizar domiciliación, the page shows Solicitud enviada and reminds them to accept the request in online banking. VEX Pay keeps the accepted text, time, IP and browser as proof of consent. If the bank refuses the request, the page says which field to check (for example the cédula) and the customer can try again.
You receive payment_method.attached with a pm_… in status pending. List a customer’s methods with GET /v1/customers/:id/payment-methods.
Step 03
Subscribe with automatic charging
curl --request POST "${API_URL}/v1/subscriptions" \
--header "content-type: application/json" \
--header "x-api-key: ${VEXPAY_API_KEY}" \
--data '{
"customer": "cus_…",
"price": "price_…",
"collectionMethod": "charge_automatically"
}'const subscription = await vexpay.subscriptions.create({
customer: 'cus_…',
price: 'price_…',
collectionMethod: 'charge_automatically',
});subscription = vexpay.subscriptions.create({
"customer": "cus_…",
"price": "price_…",
"collectionMethod": "charge_automatically",
})$subscription = $vexpay->subscriptions->create([
'customer' => 'cus_…',
'price' => 'price_…',
'collectionMethod' => 'charge_automatically',
]);- Without
paymentMethod, the subscription uses the customer’s most recent authorized method that is not inactive. With none, it answers 400payment_method_required. - An email is optional for automatic charging, but recommended: it is how the customer receives charge notices, receipts and, if a debit fails, the invoice to pay by hand.
- Switch an existing subscription with
POST /v1/subscriptions/:idand{ "collectionMethod": "charge_automatically" }; it applies from the next invoice. - The price must fit the per-charge limit at today’s rate (see below), otherwise create and switch answer 400
amount_exceeds_limit.
Each debit
- 3 days before a renewal the customer receives Aviso de cobro, with the dollar amount and a Bs estimate at today’s rate.
- On each collection attempt the Bs amount is calculated at your account’s current rate (BCV or market) and debited with the concept “Factura <number>”. The amount follows the rate, so it can differ from one period to the next.
- The bank usually confirms the debit within minutes. On success the invoice is paid, the payment method becomes
active, and the receipt shows the Bs debited and the rate. No invoice email is sent for a successful debit. - Only one debit per invoice is in flight at a time: while one is pending, later attempts wait for it.
- The money lands in your balance like any other bolívar payment, at your bolívar pay-in rate plus the billing fee (see Subscriptions & billing).
Per-charge limit: Bs 1,500,000
A single automatic debit can be at most Bs 1,500,000. Because prices are in dollars, the check uses your account’s current rate:
- Up front. Creating a
charge_automaticallysubscription, or switching one to it, for a price that is already above Bs 1,500,000 at today’s rate answers 400amount_exceeds_limit. The message gives the approximate USD maximum at today’s rate. Nothing is created or changed; usesend_invoicefor that price. - At charge time. If the rate moves and an invoice ends up above the limit, no debit is sent. You get
invoice.payment_failedwithfailureCode: "amount_exceeds_limit"(andpaymentId: null), the customer receives the invoice by email to pay on its page, and the remaining attempts for that invoice send reminders instead of debits.
When a debit fails
You receive invoice.payment_failed with a failureCode. The first time, the customer is also emailed the invoice so they can pay it another way. The next daily attempt debits again unless the method is inactive.
| failureCode | Meaning | What happens next |
|---|---|---|
affiliation_pending | The customer has not accepted the domiciliación in online banking yet | Retried on the next attempt — ask the customer to accept it |
insufficient_funds | Not enough balance | Retried on the next attempt |
payment_method_inactive | The customer canceled the domiciliación at their bank, or the bank suspended it | The method becomes inactive (payment_method.updated) and is never debited again; later attempts email the invoice instead. Send a new setup link |
amount_exceeds_limit | The Bs amount is above Bs 1,500,000 at the current rate (no debit was sent) | No debits for this invoice; it is emailed and later attempts send reminders |
| other | The bank rejected the debit; failureMessage has its reason in Spanish | Retried on the next attempt |
If every attempt fails, the subscription is canceled for non-payment like any other — and a late payment of its invoice reactivates it. See Subscriptions & billing.
Manage payment methods
| Status | Meaning |
|---|---|
pending | Authorized on the page; no accepted debit yet |
active | At least one debit was accepted |
inactive | The bank reported the authorization inactive; never debited again |
GET /v1/payment-methods/:idreturns one method; it showsphoneLast4andbankCode, never the full phone or cédula.DELETE /v1/payment-methods/:iddetaches it: it is never debited again (payment_method.detached). Subscriptions that used it keepcharge_automaticallyand their invoices are emailed until you set a new method withPOST /v1/subscriptions/:idandpaymentMethod.- A domiciliación does not expire. Customers can cancel it at any time in their online banking; the bank does not notify the cancellation, so you find out on the next debit: it fails with
payment_method_inactive, the method becomesinactive, and you getpayment_method.updated.
Test mode
With your Test key no bank is contacted and nothing needs to be enabled: setup sessions and charge_automatically always work, authorization always succeeds and each debit settles at once. The setup page shows “Modo de prueba”. The last 4 digits of the phone the customer enters on the setup page choose the outcome of every debit:
| Phone ends in | Result |
|---|---|
0001 | affiliation_pending (not accepted yet) |
0002 | insufficient_funds |
0003 | payment_method_inactive |
| anything else | Accepted: the invoice is paid |
Combine a suffix with a daily test price ("interval": "day") to watch failures, retries and cancellation play out over a few days. Test-mode emails only reach your business-profile email.