Developer guide
VEXPay siteAPI reference
Browse documentation

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.

  1. 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).

  2. 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.

  3. 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.

  4. 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 method active.

Step 01

Create the authorization link

curlbash
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"
  }'
Node SDKjavascript
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.
Python SDKpython
session = vexpay.setup_sessions.create({
    "customer": "cus_…",
    "successUrl": "https://example.com/cuenta/listo",
})
PHP SDKphp
$session = $vexpay->setupSessions->create([
    'customer' => 'cus_…',
    'successUrl' => 'https://example.com/cuenta/listo',
]);
Responsejson
{
  "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 url is valid for 24 hours and only once, and it is returned only in this response — send it right away. GET /v1/setup-sessions/:id returns the session without it.
  • status is open, complete (authorized; paymentMethod is set) or expired. 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, idNumber and bankCode on 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

curlbash
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"
  }'
Node SDKjavascript
const subscription = await vexpay.subscriptions.create({
  customer: 'cus_…',
  price: 'price_…',
  collectionMethod: 'charge_automatically',
});
Python SDKpython
subscription = vexpay.subscriptions.create({
    "customer": "cus_…",
    "price": "price_…",
    "collectionMethod": "charge_automatically",
})
PHP SDKphp
$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 400 payment_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/:id and { "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_automatically subscription, or switching one to it, for a price that is already above Bs 1,500,000 at today’s rate answers 400 amount_exceeds_limit. The message gives the approximate USD maximum at today’s rate. Nothing is created or changed; use send_invoice for 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_failed with failureCode: "amount_exceeds_limit" (and paymentId: 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.

failureCodeMeaningWhat happens next
affiliation_pendingThe customer has not accepted the domiciliación in online banking yetRetried on the next attempt — ask the customer to accept it
insufficient_fundsNot enough balanceRetried on the next attempt
payment_method_inactiveThe customer canceled the domiciliación at their bank, or the bank suspended itThe method becomes inactive (payment_method.updated) and is never debited again; later attempts email the invoice instead. Send a new setup link
amount_exceeds_limitThe 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
otherThe bank rejected the debit; failureMessage has its reason in SpanishRetried 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

StatusMeaning
pendingAuthorized on the page; no accepted debit yet
activeAt least one debit was accepted
inactiveThe bank reported the authorization inactive; never debited again
  • GET /v1/payment-methods/:id returns one method; it shows phoneLast4 and bankCode, never the full phone or cédula.
  • DELETE /v1/payment-methods/:id detaches it: it is never debited again (payment_method.detached). Subscriptions that used it keep charge_automatically and their invoices are emailed until you set a new method with POST /v1/subscriptions/:id and paymentMethod.
  • 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 becomes inactive, and you get payment_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 inResult
0001affiliation_pending (not accepted yet)
0002insufficient_funds
0003payment_method_inactive
anything elseAccepted: 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.