# Server-to-Server Save card

Process a card payment and save the card for future use via the API without using the SDK. Includes mandate_data to establish customer consent for multi-use off-session charges.

## Use cases

- PCI-compliant server-side card save flows
- Establish mandate during initial server-side payment
- Migration from other payment providers
- Backend-only save card without customer-facing UI

## Steps

### 1. Create and confirm payment — `POST /payments`

Submit the payment with full card details, mandate_data, and confirm: true to process immediately in a single call.

Key parameters:
• confirm: true - Processes the payment immediately
• payment_method: "card" - Required when confirming
• payment_method_data.card - Full card details (number, expiry, CVV, holder name)
• mandate_data - Documents customer acceptance and multi-use mandate limits
• capture_method: "automatic" or "manual"
  - automatic: Authorise and capture in one step
  - manual: Authorise only, capture later
• authentication_type: "no_three_ds" or "three_ds"
  - three_ds: Response includes a next_action with a redirect URL for 3DS
• setup_future_usage: "off_session" - Saves the card for future use
• customer.id - Required to save the card

If 3DS is required, the response status will be "requires_customer_action" with a redirect URL in next_action.

Request body:

```json
{
  "amount": 6500,
  "currency": "ZAR",
  "confirm": true,
  "capture_method": "automatic",
  "authentication_type": "no_three_ds",
  "setup_future_usage": "off_session",
  "payment_method": "card",
  "payment_method_data": {
    "card": {
      "card_number": "4200000000000091",
      "card_exp_month": "01",
      "card_exp_year": "32",
      "card_cvc": "123",
      "card_holder_name": "Test Holder"
    }
  },
  "customer": {
    "id": "cus_new_user_muzj29cd",
    "email": "newuser@example.com",
    "name": "New Customer",
    "phone": "+27123456789"
  },
  "mandate_data": {
    "customer_acceptance": {
      "acceptance_type": "online",
      "accepted_at": "2026-06-05T13:33:13.337Z",
      "online": {
        "ip_address": "127.0.0.1",
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Cursor/3.5.17 Chrome/142.0.7444.265 Electron/39.8.1 Safari/537.36"
      }
    },
    "mandate_type": {
      "multi_use": {
        "amount": 100000,
        "currency": "ZAR"
      }
    }
  },
  "browser_info": {
    "os_type": "macOS",
    "referer": null,
    "language": "en-GB",
    "time_zone": -120,
    "ip_address": "102.207.202.48",
    "os_version": "10.15.7",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
    "color_depth": 24,
    "device_model": "Macintosh",
    "java_enabled": true,
    "screen_width": 2560,
    "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "screen_height": 1440,
    "accept_language": "en-GB,en-US;q=0.9,en;q=0.8",
    "java_script_enabled": true
  },
  "description": "Server-to-Server save card payment",
  "return_url": "https://example.com/flows/server-to-server-save-card?status=complete",
  "billing": {
    "address": {
      "line1": "123 Main Street",
      "line2": "Apartment 4B",
      "city": "Cape Town",
      "state": "Western Cape",
      "zip": "8001",
      "country": "ZA",
      "first_name": "John",
      "last_name": "Doe"
    },
    "phone": {
      "number": "821234567",
      "country_code": "+27"
    },
    "email": "john.doe@example.com"
  }
}
```

### 2. Handle 3DS (if required)

If authentication_type is "three_ds", the response will contain:

{
  "status": "requires_customer_action",
  "next_action": {
    "redirect_to_url": "https://..."
  }
}

Redirect the customer to the URL to complete 3DS authentication. After completion, they will be redirected to your return_url.

If authentication_type is "no_three_ds", this step is skipped and the payment is processed immediately.

### 3. Verify payment status — `GET /payments/{id}`

After 3DS completion (or immediately for no_three_ds), fetch the payment to verify its status.

Expected statuses:
• succeeded - Payment captured successfully
• requires_capture - Payment authorised (manual capture_method)
• failed - Payment was declined

The response also contains:
• payment_method_id - Use this for future off-session charges
• mandate_id - Reference for the established mandate
• customer_id - The customer the card was saved to

### 4. Create refund — `POST /refunds`

Refund the succeeded payment via POST /refunds using the payment_id from the previous step.

Request body:

```json
{
  "payment_id": "",
  "amount": 6500,
  "reason": "Customer requested refund"
}
```

## Response

Payment endpoints return the payment object. Key fields to read:

- `payment_id` — the payment identifier.
- `status` — current payment status (see the state transitions below).
- `client_secret` — pass to the SDK to complete the payment client-side.
- `next_action` — present when a redirect or 3-D Secure challenge is required.

## Key parameters

- confirm: true - Single API call to create and process
- mandate_data - Establishes multi-use customer consent
- No SDK required - full card details sent server-side
- PCI compliance required for handling raw card data
- 3DS handled via redirect when authentication_type is 'three_ds'

## Flow diagram

```mermaid
flowchart LR
    A[POST /payments<br/>confirm: true<br/>mandate_data] --> B{3DS Required?}
    B -->|Yes| C[Customer completes 3DS]
    C --> D[Verify Status]
    B -->|No| D
    D --> E{Status}
    E -->|succeeded| F[Payment Complete<br/>Card Saved]
    F --> I[Create Refund]
    E -->|requires_capture| G[Capture Later]
    E -->|failed| H[Handle Error]
```

## Payment state transitions

```mermaid
stateDiagram-v2
    [*] --> processing: Confirm Payment
    processing --> requires_customer_action: 3DS Required
    processing --> succeeded: No 3DS + Auto Capture
    processing --> requires_capture: No 3DS + Manual Capture
    processing --> failed: Declined
    requires_customer_action --> succeeded: 3DS Passed + Auto Capture
    requires_customer_action --> requires_capture: 3DS Passed + Manual Capture
    requires_customer_action --> failed: 3DS Failed
    requires_capture --> succeeded: Capture
    succeeded --> refunded: Create Refund
    refunded --> [*]
    failed --> [*]
```

---

Interactive version: https://playground.sandbox-next.peachpayments.com/flows/server-to-server-save-card
