Server-to-Server Payments
Available via: API only (private key)
Overview
Server-to-server (S2S) payments let you collect card details on your own frontend and process the payment entirely through the API. This gives you full control over the checkout experience.
Important: S2S card payments require sending card data to
https://api-card.inflowpay.com(not the standard API URL). This endpoint handles PCI-compliant card tokenization.
Prerequisites
Server-to-server payments must be enabled on your account before you can use them. If S2S is not enabled, you will receive the error:
"Not authorized to create payment, server to server payment not enabled, please contact support"
Contact [email protected] to request activation.
When to Use S2S
| Approach | Best For |
|---|---|
| Hosted Checkout (payment links) | Simple integration, no frontend work needed |
| SDK (iframe card form) | Custom checkout with PCI compliance handled for you |
| Server-to-Server | Full control, custom UI, PCI-compliant infrastructure |
Payment Flow
Step 1: Create the Payment
curl -X POST https://api-card.inflowpay.com/api/server/payment \
-H "X-Inflow-Api-Key: inflow_priv_your_key" \
-H "Content-Type: application/json" \
-d '{
"products": [
{ "name": "Pro Plan", "price": 4999, "quantity": 1 }
],
"currency": "EUR",
"customerEmail": "[email protected]",
"billingCountry": "FR",
"postalCode": "75001",
"purchasingAsBusiness": false,
"firstName": "John",
"lastName": "Doe",
"autoConfirm": true,
"pricingMode": "TAX_EXCLUSIVE",
"threeDsSuccessUrl": "https://yoursite.com/3ds-success",
"threeDsFailureUrl": "https://yoursite.com/3ds-failure",
"metadatas": {
"orderId": "order_12345"
}
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
products | array | Yes | List of products (name, price in cents, quantity) |
currency | string | Yes | EUR or USD |
customerEmail | string | Yes | Customer's email address |
billingCountry | string | Yes | ISO 3166-1 alpha-2 country code (e.g., FR, DE, US) |
purchasingAsBusiness | boolean | Yes | Whether the customer is purchasing as a business |
postalCode | string | If US | Billing postal code (required for US customers) |
businessName | string | If business | Business name (required if purchasingAsBusiness is true) |
taxId | string | If business | Tax ID (required if purchasingAsBusiness is true) |
firstName | string | No | Customer first name (recommended for 3DS) |
lastName | string | No | Customer last name (recommended for 3DS) |
savePaymentMethod | boolean | No | Save the card for future use (default: false). See Saving and reusing payment methods below. |
useCustomerPaymentMethod | boolean | No | Use the customer's last saved payment method (default: false). See Saving and reusing payment methods below. |
autoConfirm | boolean | No | Auto-confirm if no 3DS required (default: false) |
pricingMode | string | No | TAX_EXCLUSIVE (default) or TAX_INCLUSIVE |
threeDsSuccessUrl | string | No | Redirect URL after successful 3DS |
threeDsFailureUrl | string | No | Redirect URL after failed 3DS |
metadatas | object | No | Custom metadata |
Response
{
"id": "pay_abc123",
"amountInCents": 4999,
"currency": "EUR",
"status": "INITIATION",
"customerEmail": "[email protected]",
"threeDsSessionUrl": null
}Step 2: Handle 3D Secure (If Required)
If threeDsSessionUrl is not null, the customer's bank requires 3DS authentication:
- Redirect the customer to the
threeDsSessionUrl. - The customer completes authentication with their bank.
- The customer is redirected to your
threeDsSuccessUrlorthreeDsFailureUrl.
Step 3: Confirm the Payment
After 3DS completion (or if no 3DS was required and autoConfirm is false), you must explicitly confirm the payment. You can check whether confirmation is needed by looking at the depositStatus field — if it shows "requires_confirmation", call:
curl -X POST https://api.inflowpay.xyz/api/server/payment/{paymentId}/confirm \
-H "X-Inflow-Api-Key: inflow_priv_your_key"If autoConfirm: true was set and no 3DS was required, the payment is confirmed automatically.
SDK users: If you use the Inflow SDK (iframe card form), the SDK handles confirmation automatically — you do not need to call this endpoint.
Step 4: Verify Payment Status
curl https://api.inflowpay.xyz/api/payment/{paymentId} \
-H "X-Inflow-Api-Key: inflow_priv_your_key"Or set up a webhook to receive automatic notifications when the payment status changes.
Saving and Reusing Payment Methods
You can save a customer's card for future purchases and reuse it without asking them to enter their card details again.
How it works
savePaymentMethod: true— When the customer pays with a card, that card is saved and linked to their email (customerEmail). Use this on the first payment when you want to allow one-click or faster checkout later.useCustomerPaymentMethod: true— For a returning customer, use their last saved card instead of collecting new card details. The customer must use the samecustomerEmailas when the card was saved.
You cannot use both parameters in the same request: either you save a new card, or you use an existing one.
Typical flow
- First purchase — Customer enters their card. Send
savePaymentMethod: trueto store it. - Later purchases — Customer returns (same email). Send
useCustomerPaymentMethod: trueand omit card details. The payment uses the saved card.
Important: last saved card is used
When useCustomerPaymentMethod: true is set, the system charges the last saved card for that customer. If a customer saves multiple cards over time, the most recently saved card becomes the active one.
Selecting a specific card among multiple saved payment methods is not currently supported but is planned. Contact [email protected] for updates.
Customer identification
The saved payment method is tied to customerEmail. For reuse to work, the customer must use the same email address across payments. If they have no saved card yet, useCustomerPaymentMethod: true will fail.
Update a Payment Before Confirmation
You can update a server payment before it's finalized:
curl -X POST https://api.inflowpay.xyz/api/server/payment/{paymentId} \
-H "X-Inflow-Api-Key: inflow_priv_your_key" \
-H "Content-Type: application/json" \
-d '{
"products": [
{ "name": "Updated Product", "price": 5999, "quantity": 1 }
]
}'Error Handling
If the payment fails, check the lastDepositAttempt field in the payment object:
{
"lastDepositAttempt": {
"status": "failed",
"amount": 4999,
"paymentMethod": "CARD",
"error": "card_declined",
"attemptedAt": "2025-01-15T10:31:00.000Z"
}
}See Error Handling for a complete list of error codes.
Minimum Payment Amounts
Each currency has a minimum payment amount. Payments below these thresholds will be rejected:
| Currency | Minimum Amount |
|---|---|
| EUR | €1.50 (150 cents) |
| GBP | £1.00 (100 cents) |
| USD | $2.00 (200 cents) |
Tips
- Always provide
firstNameandlastName— this significantly improves 3DS authentication success rates. - Use
autoConfirm: truefor a smoother flow when 3DS is not required. - Set up webhooks instead of polling for payment status updates.
- Tax is calculated automatically based on
billingCountry.
Updated about 20 hours ago