Accept a VPOS card payment
Submit card details from a PCI-appropriate server flow.
Create a payment
curl --request POST "${API_URL}/v1/payments/vpos" \
--header "content-type: application/json" \
--header "x-api-key: ${VEXPAY_API_KEY}" \
--data '{
"usdAmount": 24.00,
"cardNumber": "4111111111111111",
"expirationMonth": 12,
"expirationYear": 2030,
"cvv": "123",
"cardHolderName": "CLIENTE PRUEBA",
"cardHolderId": "V12345678",
"accountType": 0,
"cardType": 1,
"externalRef": "order_demo_1043"
}'accountType accepts 0, 10, or 20. cardType accepts 1, 2, or 3. cardPin is optional (4 digits); when omitted the gateway sends 0000. Debit or credit pricing is determined from the card and the account type the buyer selects: accountType 10 or 20 is charged the debit rate and accountType 0 the credit rate, but a card VEXPay knows to be a credit card is always charged the credit rate. Without an accountType, VEXPay goes by the card, and a card it can’t identify is charged the credit rate (see Pricing).
Test card
With a Test key, real cards are declined and never charged. You have two kinds of test card: this Débito Maestro card, which is sent to the bank's test environment and always succeeds, and the test card scenarios below, which return each approval and decline. Both are shown in your portal under Sandbox.
| Field | Value |
|---|---|
| Card brand | Débito Maestro |
| cardNumber | 6276093058088765 |
| expirationMonth / expirationYear | 12 / 2025 |
| cvv | 467 |
| cardPin | 1234 |
| cardHolderName | Julian Esteves |
| cardHolderId | V23000760 |
| accountType | 20 |
| cardType | 3 |
curl --request POST "${API_URL}/v1/payments/vpos" \
--header "content-type: application/json" \
--header "x-api-key: YOUR_TEST_API_KEY" \
--data '{
"vesAmount": 32.95,
"cardNumber": "6276093058088765",
"expirationMonth": 12,
"expirationYear": 2025,
"cvv": "467",
"cardPin": "1234",
"cardHolderName": "Julian Esteves",
"cardHolderId": "V23000760",
"accountType": 20,
"cardType": 3,
"externalRef": "test_card_1"
}'Test card scenarios. Like Stripe test cards: with a Test key, these numbers get a fixed answer from VEXPay without reaching the bank, so you can drive every outcome your checkout must handle. Use any expiry in the future and any CVV. Send cardPin 1234 or no PIN.
| cardNumber | Scenario | Result |
|---|---|---|
4242424242424242 | Succeeds (credit card) | COMPLETED payment |
4000056655665556 | Succeeds (debit card) | COMPLETED payment |
4000000000009995 | Insufficient funds | 422 G51 |
4000000000005506 | Incorrect PIN | 422 G55 |
4000000000000382 | PIN tries exceeded | 422 G38 |
4000000000000069 | Expired card | 422 G54 |
4000000000009987 | Lost card | 422 G41 |
4000000000009979 | Stolen card | 422 G43 |
4100000000000019 | Suspected fraud | 422 G59 |
4000000000000366 | Restricted card | 422 G36 |
4000000000000580 | Transaction not permitted | 422 G58 |
4000000000000002 | Refer to issuing bank | 422 G02 |
4000000000000119 | Bank system malfunction | 422 G96 |
4000000000000689 | Late bank response | 422 G68 |
4000000000000259 | Succeeds, then is charged back | COMPLETED, then payment.chargeback |
- A decline behaves exactly like a Live one: HTTP 422 with the bank code in
code, the paymentFAILEDwith the samefailureCode, and apayment.failedwebhook. - An approval completes like a Live charge:
payment.completed, your ledger credit, and the fee for that card type (the debit card uses your debit rate, the others your credit rate). - On any test card, an expiry in the past declines with
G54, and acardPinother than1234declines withG55. 4000000000000259completes, then receives a full chargeback within about a minute:payment.chargebackandpayment.reversedfire, and your Test balance is debited.- Declines count toward the card-testing protection: after 3 different failed cards for one
cardHolderIdwithin 24 hours, that payer gets 429CARD_VELOCITY_BLOCKEDfor the next 24 hours. Use a differentcardHolderIdfor each test run. - Hosted checkouts and payment links in Test show a "Tarjetas de prueba" list that fills in the card form.