Online Payments
Key concept: Session vs Payment
It is essential to understand that the External API has two distinct concepts: the session and the payment. Although they are related, they represent different things and have independent lifecycles.
The session (sessionId)
The session is what your system creates when you call POST /payment/session. It represents the payment intent: amount, currency, return URLs, description, etc. When you create it, you receive a sessionId and a paymentUrl to redirect the customer.
When the customer completes the payment successfully, the session moves to completed status and closes.
The session is not modified once completed. Its job is done: it served so the customer could pay.
The payment (paymentReference)
The payment is the real transaction created when the customer successfully completes the payment form. It is the object the payment processor recognizes and on which operations can be performed.
The paymentReference (authorized payment reference) appears within the session once completed, in the paymentReference field and also in the attempts array.
The payment is what matters for subsequent operations. Refunds, captures, cancellations, and extensions are done on paymentReference, not on sessionId.
Visual relationship
Session (sessionId: "SHOP01-EXT-1719500000")
|
|-- Customer completes payment (status: "authorised") <-- THIS IS THE PAYMENT
|
Session status: "completed"
paymentReference: "KVGQSN3K2SKFNVNS" <-- real payment referenceIn summary
| Concept | What it is | Created when | Used for |
|---|---|---|---|
Session (sessionId) | Payment intent | Your system calls POST .../payment/session | Redirect customer, query status |
Payment (paymentReference) | Authorized transaction | Customer completes payment successfully | Refunds, captures, cancellations, reconciliation |
Practical rule: Use
sessionIdto query status and obtainpaymentReference. UsepaymentReferenceto modify the payment (refund, capture, cancel, extend).
---
Complete online payment flow
Before diving into endpoints, it is important to understand the full flow. An online payment involves three participants and three redirects:
Your system Avirato Payments Customer
| | |
| 1. POST /payment/session |
| (with urlOk and urlKo) | |
|------------------------->| |
| | |
| 2. Receive paymentUrl | |
|<-------------------------| |
| | |
| 3. Redirect customer to paymentUrl |
|------------------------->+---------------------------->
| | |
| 4. Customer sees payment page |
| and pays |
| |<--------------------------+
| | |
| 5. Avirato Payments redirects |
| to urlOk (success) or urlKo |
| +--------------------------->
| | |
| 6. Customer arrives at your urlOk or urlKo |
|<-------------------------+---------------------------+
| | |
| 7. Your system queries | |
| GET /payment/session/{id} |
|------------------------->| |
|<-------------------------| |Step by step
- Your system creates the session by calling
POST /payment/sessionwith the amount, currency, and two return URLs:urlOkandurlKo - You receive a
sessionIdand apaymentUrl. ThepaymentUrlis a link to the Avirato Payments secure payment page - Redirect the customer to
paymentUrl. You can use an HTTP 302 redirect or open a new tab, depending on your use case - The customer sees the payment page. There they enter their card, complete 3D Secure if needed, and confirm the payment. Your system does not intervene in this step
- Avirato Payments automatically redirects the customer to one of the two URLs you provided:
urlOkif the payment completed successfullyurlKoif the payment failed, was cancelled by the customer, or expired- The customer arrives at your page. On
urlOkyou can show a confirmation message. OnurlKoyou can inform them of the problem and, if it makes sense, create a new payment session to offer another attempt - Your system confirms the payment using the tools we provide: the encrypted data in the
dataparameter onurlOk(decryptable with your client secret), the webhook you will receive automatically a few seconds later, and optionally the queryGET /payment/session/{id}for additional verification
Test environment: The flow is identical. The only difference is that in step 4, the payment page is a simulated form (not connected to any real processor). The customer enters fictitious cards and the result is determined by the cardholder name (see Test cards).
The importance of urlOk and urlKo
These two URLs are the bridge back between our payment page and your system. They are mandatory and determine the customer experience after paying:
urlOk: Where the customer lands when the payment is successful. It should be a page on your system that shows confirmation (e.g. "Thank you, your payment has been completed"). The URL will receive adataparameter with encrypted payment information (decryptable with your client secret)urlKo: Where the customer lands if something fails (card declined, timeout, cancellation). It should be a page that informs them of the problem. If you want to offer another attempt, create a new payment session from your backend and redirect the customer to the newpaymentUrl
Practical recommendation: Use the
customReferencefield when creating the session to include your internal reference (e.g. order number, operation ID). This value is included in the encrypted redirect data and in webhooks, so you can automatically associate the result with the original operation in your system.
Do not rely only on the return URL: verify status with
GET /payment/session/{sessionId}and, above all, with webhooks. In Live the definitive payment status can evolve after the redirect or a previous query (for example, a chargeback notified by the processor). Treat webhooks as the business reference for late changes and query the API again if you need the persisted status (seeWebhooks).
---
Create payment session
Creates a payment session and returns a URL where you redirect the customer to complete the payment.
Live: POST https://aviratopayments.com/external/v1/payment/session
Test: POST https://aviratopayments.com/external/v1/test/payment/sessionBody parameters
| Field | Type | Required | Description |
|---|---|---|---|
webcode | string | Yes | Your business identifier |
amount.value | integer | Yes | Amount in cents (e.g. 10000 = 100.00 EUR) |
amount.currency | string | Yes | ISO 4217 3-letter uppercase code. Accepted values: EUR, GBP, USD |
urlOk | string | Yes | URL to redirect the customer when payment completes successfully. Must be a valid URL on your system |
urlKo | string | Yes | URL to redirect the customer when payment fails, is cancelled, or expires. Must be a valid URL on your system |
countryCode | string | No | ISO 3166-1 alpha-2 code (default: ES) |
shopperLocale | string | No | Payment page language, BCP-47 format (default: es-ES). Max 10 characters |
deliverAt | string | No | Service date in ISO 8601 format (e.g. 2026-07-15T14:00:00Z) |
description | string | No | Payment description. Max 255 characters |
customReference | string | No | Your internal reference for reconciliation. Max 100 characters. Included in encrypted redirect data |
isPreAuth | boolean | No | true for pre-authorization (no immediate capture). Default: false |
Request example (Live)
curl -X POST https://aviratopayments.com/external/v1/payment/session \
-H "X-API-KEY: your_live_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-12345-payment" \
-d '{
"webcode": "SHOP01",
"amount": {
"value": 15000,
"currency": "EUR"
},
"urlOk": "https://tu-sistema.com/pago-ok",
"urlKo": "https://tu-sistema.com/pago-error",
"countryCode": "ES",
"shopperLocale": "es-ES",
"description": "Pedido #12345 - Servicio premium",
"customReference": "ORD-2026-12345",
"isPreAuth": false
}'Request example (Test)
curl -X POST https://aviratopayments.com/external/v1/test/payment/session \
-H "X-API-KEY: your_test_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: test-order-12345-payment" \
-d '{
"webcode": "SHOP01",
"amount": {
"value": 15000,
"currency": "EUR"
},
"urlOk": "https://tu-sistema.com/pago-ok",
"urlKo": "https://tu-sistema.com/pago-error",
"description": "Pedido #12345 - Servicio premium",
"customReference": "ORD-2026-12345"
}'Successful response (201)
{
"success": true,
"data": {
"sessionId": "SHOP01-EXT-17195000001234",
"paymentUrl": "https://aviratopayments.com/pay-external/eyJhbGciOi...",
"status": "pending",
"amount": {
"value": 15000,
"currency": "EUR"
},
"description": "Pedido #12345 - Servicio premium",
"customReference": "ORD-2026-12345",
"isPreAuth": false,
"createdAt": "2026-06-28 10:30:00"
}
}
sessionIdformat: In Live the format is{webcode}-EXT-{timestamp}. In Test the format is{webcode}-EXTT-{timestamp}. This lets you identify at a glance which environment a session comes from.
paymentUrlin Test: The URL points to a simulated payment page (not connected to the real gateway). The form accepts fictitious cards and the result is determined by the cardholder name. See Test cards.
What to do with the response
- Save
sessionIdin your system, associated with the operation (order, service, etc.). You will need it to query status and obtainpaymentReferencewhen it completes - Redirect the customer to
paymentUrlimmediately. There they will see the secure payment page with available payment methods - Prepare your return pages (
urlOkandurlKo). The customer will arrive at one of them after paying
Time limit to pay
Once the customer opens paymentUrl, they have 5 minutes (300 seconds) to complete the payment. After that, the payment page expires automatically and the customer is redirected to urlKo.
The session itself does not have a fixed server-side expiration: what expires is the payment page in the customer's browser. If the customer never opens paymentUrl, the session remains in pending status indefinitely.
The payment page shows a visible countdown timer for the customer, so you do not need to inform them on your side.
Session lifecycle
The session (not the payment) goes through these states:
pending --> (customer completes payment) --> completed --> Payment exists, use paymentReference
--> (customer cancels) --> cancelled
--> (payment error) --> failed
--> (time expired) --> expired| Status | Description |
|---|---|
pending | Session created, waiting for customer to pay. Failed attempts may be in progress |
completed | A payment attempt was authorized. Session closes and paymentReference is available |
failed | All attempts failed without any being authorized |
expired | Session expired without completing |
cancelled | Cancelled before completing |
Important: A
completedsession will not change status. From that point on, what matters is the payment (paymentReference), which you can refund, capture, etc.
If payment fails
If payment fails (card declined, 3DS cancelled, timeout), the customer is redirected to your urlKo. To offer another attempt, create a new session and redirect the customer to the new paymentUrl.
---
Post-payment redirect: what happens when the customer finishes
Once the customer completes the payment form (or abandons/fails), Avirato Payments automatically redirects them to the corresponding URL:
- Successful payment -> Customer is redirected to your
urlOk - Failed, cancelled, or expired payment -> Customer is redirected to your
urlKo
The redirect is automatic: the customer briefly sees a "Redirecting..." message and lands on your page without needing to click anything.
The data parameter on urlOk
When the customer arrives at your urlOk, the URL includes a data parameter with a JWT containing encrypted payment information:
https://tu-sistema.com/pago-ok?data=eyJhbGciOiJIUzI1NiIs...To read this information:
- Extract the
dataparameter from the URL - Decode the JWT using your client secret as the key (see Authentication - Client Secret)
- The decrypted payload contains payment data: reference, amount, status, etc.
urlKodoes not include thedataparameter, since there is no successful payment to report. OnurlKoshow an appropriate message to the customer.
Test environment: The
dataparameter onurlOkworks exactly the same as in Live. It is encrypted with the Test environment client secret, and you decrypt it with that same secret. The content has the same structure.
Validating redirect data
When you receive the customer on urlOk with the data parameter, validate the encrypted information against the plain data:
- Decode the JWT with your client secret
- Compare payload data (amount, reference, status) with what you expect according to your business logic
- If data does not match, treat the operation as suspicious
This protects against manipulation: a user could change the URL manually, but cannot forge the JWT without your client secret.
What happens if the customer closes the browser
If the customer completes the payment but closes the browser before being redirected, the payment has still completed.
In this case, the customer never reaches your urlOk. To cover this scenario:
- You will receive a webhook a few seconds after the payment completes (see Webhooks)
- As an alternative, you can do periodic polling with
GET /payment/session/{sessionId}to detect sessions that moved tocompletedwithout the customer returning
Recommendation: Do not rely exclusively on redirect to
urlOkto confirm payments. Use webhooks as the primary confirmation source and the redirect as a user experience enhancement.
---
Test cards (Test environment)
In the Test environment, the payment page is a simulated form. It is not connected to any real processor. Payment result is determined by the cardholder name (holderName):
Successful payment
Use any name that is not one of the special values in the table below. Example: Juan Garcia, Test User, Maria Lopez.
Simulate failures
| Cardholder name (case-insensitive) | Result | Reason |
|---|---|---|
DECLINED | Payment declined | Generic decline |
CARD_EXPIRED | Payment declined | Expired card |
INVALID_CARD | Payment declined | Invalid card number |
NOT_ENOUGH_BALANCE | Payment declined | Not enough balance |
CVC_DECLINED | Payment declined | CVC declined |
FRAUD | Payment declined | Fraud detected |
ERROR | Processor error | Acquirer error |
Card data
The simulated form validates card format realistically:
- Number: Must have 13-19 digits and pass Luhn validation. Example:
4111 1111 1111 1111(Visa) - Expiry month:
MMformat (01-12), cannot be expired - Expiry year:
YYformat (2 digits), cannot be expired - CVC: 3 digits (Visa/Mastercard) or 4 digits (Amex)
- Cardholder name: Minimum 3 characters
Tip: For a quick successful flow, use
4111 1111 1111 1111, expiry12/30, CVC737, nameTest User.
---
Pre-authorizations
If you need to reserve an amount without capturing it immediately (e.g. security deposit), use isPreAuth: true.
With a pre-authorization you can later:
- Capture the full or partial amount:
POST /payment/capture - Cancel the pre-authorization:
POST /payment/cancel - Extend the period before it expires:
POST /payment/extend
See Modifications for more detail.
---
Accepted currencies
The External API currently accepts the following currencies:
| Code | Currency |
|---|---|
EUR | Euro |
GBP | Pound sterling |
USD | US dollar |
If you send an unsupported currency code, you will receive a 400 Bad Request error.
---
Common errors
| Code | HTTP | Cause |
|---|---|---|
| 12001 | 400 | Missing required field or invalid value (includes unsupported currency) |
| 12002 | 400 | deliverAt date in incorrect format (must be ISO 8601) |
| 12006 | 400 | Invalid countryCode format |
| 12009 | 400 | Country not supported |
| 11008 | 403 | API key without permissions or webcode mismatch |