Card payments (H2H)
Accept card data on your own page and drive the 3-D Secure flow through the API
Before you start
Authorization
How to sign your requests with the API token.
Create payment
The base order request that this page extends.
This payment method is not enabled for all merchants. Check availability with your manager.
Overview
There are two ways to accept cards:
| Option | Who collects card data | Requirements |
|---|---|---|
| Hosted payment page (default) | Our payment page | None: create a regular order |
| Host-to-host (H2H), this page | Your page | PCI DSS compliance, enabled by manager |
With H2H you create an order, send the card data to the API and drive the verification (3-D Secure, SMS code) yourself. The payer never leaves your site.
Flow
Send card data
POST /v1/orders/{orderId}/h2h/card| Field | Type | Required | Description |
|---|---|---|---|
cardNumber | string | ✅ Yes | Card number |
expiryDate | string | ✅ Yes | Expiry date, MM/YY |
cardholderName | string | ✅ Yes | Cardholder name |
cvv | string | ✅ Yes | CVV / CVC code |
curl -X POST "https://api.riopay.online/v1/orders/{orderId}/h2h/card" \
-H "Content-Type: application/json" \
-H "X-Api-Token: YOUR_API_TOKEN" \
-d '{
"cardNumber": "4111111111111111",
"expiryDate": "12/25",
"cardholderName": "John Doe",
"cvv": "123"
}'If the response contains the order object, the card data was accepted. Next, check whether an SMS code is required.
Check the H2H status
GET /v1/orders/{orderId}/h2h/statuscurl -X GET "https://api.riopay.online/v1/orders/{orderId}/h2h/status" \
-H "X-Api-Token: YOUR_API_TOKEN"{
"isSmsRequired": true,
"status": "PROCESSING"
}| Field | Description |
|---|---|
isSmsRequired | true: ask the payer for the code from their bank SMS |
status | Current H2H status, see H2H statuses |
Poll this endpoint while the status is INITIALIZING or PROCESSING.
Send the SMS code (if required)
You pass the code that the payer received from their bank to the API. This endpoint does not send an SMS to the payer.
POST /v1/orders/{orderId}/h2h/codecurl -X POST "https://api.riopay.online/v1/orders/{orderId}/h2h/code" \
-H "Content-Type: application/json" \
-H "X-Api-Token: YOUR_API_TOKEN" \
-d '{ "code": "123456" }'After a successful response keep checking the H2H status. If isSmsRequired becomes true again, the code was wrong: ask the payer for a new one.
Wait for the final order status
SUCCESS at the H2H level means the card stage is complete, not that the funds arrived. The final result comes as the order status via webhook or GET /v1/orders/{orderId}.
Order status and webhooks
H2H statuses
H2H statuses describe the card verification stage only and are not the order statuses. Always confirm the final result with the order status.
| Status | Final | Description |
|---|---|---|
INITIALIZING | No | H2H session is initializing |
PROCESSING | No | Processing: validation, 3-D Secure, anti-fraud checks |
SUCCESS | Yes | H2H stage completed successfully; wait for the final order status via webhook |
CANCELLED | Yes | H2H payment cancelled |
FAILED | Yes | H2H failed with an error |
EXPIRED | Yes | H2H session expired |
- Poll while
INITIALIZINGorPROCESSING. - On
SUCCESS, wait for the order webhook. - On
CANCELLED,FAILEDorEXPIRED, stop polling and record the failure; create a new order to retry.
Card details in the order request
Some terminals accept card details directly in POST /v1/orders through the card object, together with full payer details. This also requires PCI DSS compliance and is enabled per merchant.
Card fields
| Field | Type | Required | Description |
|---|---|---|---|
cardholderName | string | ✅ Yes | Cardholder name |
cardNumber | string | ✅ Yes | Card number |
cvv | string | ✅ Yes | CVV / CVC code |
expiryDate | string | ✅ Yes | Expiry date, MM/YY |
Customer fields
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ Yes | Payer email |
phone | string | ✅ Yes | Phone number |
firstName | string | ✅ Yes | First name |
lastName | string | ✅ Yes | Last name |
birthday | string | ✅ Yes | Date of birth, YYYY-MM-DD |
country | string | ✅ Yes | Country, ISO 3166-1 alpha-2 |
city | string | ✅ Yes | City |
region | string | ✅ Yes | State or region |
postcode | string | ✅ Yes | Postal code |
address | string | ✅ Yes | Street address |
Request example
{
"amount": "10.99",
"currency": "EUR",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"card": {
"cardholderName": "Jane Doe",
"cardNumber": "4444444444444444",
"cvv": "123",
"expiryDate": "12/26"
},
"customer": {
"email": "customer@example.com",
"phone": "1999999999",
"firstName": "Jane",
"lastName": "Doe",
"birthday": "2000-05-05",
"country": "PT",
"city": "Maia",
"region": "Porto",
"postcode": "4450",
"address": "Rua Example 1"
}
}Some terminals only need the payer's email for card payments on the hosted page:
{
"amount": "10.99",
"currency": "EUR",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"customer": {
"email": "customer@example.com"
}
}Which of these request shapes applies to you depends on the terminal. Confirm with your manager before integrating.