## How it works

Create payments from your backend with POST /payments. Send an integer amount in the currency's minor unit and identify the shop with profile_id.

## Implementation

Request payment_link to obtain the hosted checkout link. Save payment_id against your order and wait for a verified succeeded event before fulfilment. GET /payments/{payment_id} retrieves the current result; /attempts exposes processor attempts. Manual capture uses /capture and amount_to_capture; /cancel releases an unpaid payment or remaining authorization. The hosted page handles update and confirm calls for you. A 2xx response may still contain a declined payment: inspect its status.

## Request fields

| Field | Type | Required | Meaning |
| --- | --- | --- | --- |
| `amount` | integer | Yes, unless selling catalog products | Minor units. |
| `currency` | string | Yes, unless selling catalog products | ISO 4217, such as `USD`. |
| `profile_id` | string | With several shops | The shop (`pro_…`); or send `X-Profile-Id`. |
| `payment_link` | boolean | No | `true` returns a hosted checkout in `payment_link.link`. |
| `return_url` | string | No | Where the buyer lands after paying. |
| `cancel_url` | string | No | Where the buyer lands after cancelling; overrides the shop default. |
| `test_mode` | boolean | No | `true` marks a [test payment](/docs/general/test-and-live/). Omitted: behavior depends on the deployed release and processor configuration; set it explicitly. |
| `customer` | object | No | Buyer `email` and `name`. |
| `customer_id` | string | No | An existing [customer](/docs/payment-api/customers/) (`cus_…`). |
| `description` | string | No | Order description. |
| `metadata` | object | No | Your keys, returned on the payment and in webhooks. |
| `capture_method` | string | No | `automatic` (default) or manual; see [Capture](#capture-a-payment). |
| `setup_future_usage` | string | No | `off_session` saves the method. |
| `session_expiry` | integer | No | Checkout lifetime in seconds, 60–7,890,000. Default: shop setting, else 900. |
| `locale` | string | No | Checkout language, such as `de` or `pt-BR`. |
| `confirm` | boolean | No | Confirm in the same call; for [own checkout](/docs/payment-api/embedded-checkout/). |
| `product_id`, `price_id`, `products` | | No | Price from your catalog; see [Products](/docs/payment-api/products/). |

## Capture a payment

| `capture_method` | Behavior |
| --- | --- |
| `automatic` | Capture right after authorization. Default. |
| `manual` | Stop at `requires_capture`; capture once, fully or partly. |
| `manual_multiple` | Stop at `requires_capture`; capture in several parts. |
| `sequential_automatic` | Authorize, then capture automatically in a separate step. |

## Release compatibility

The supplied SpicePay release notes state that newer plugin packages send `cancel_url` while the deployed API may reject it. The example omits that optional field. Confirm the deployed release before adding it. Header-based idempotency also needs a release check; see [Idempotency](/docs/payment-api/idempotency/).

## Related guides

- [Hosted checkout](/docs/payment-api/hosted-checkout/)
- [Webhook events](/docs/payment-api/webhooks/)
- [Idempotency](/docs/payment-api/idempotency/)
- [Test and live payments](/docs/general/test-and-live/)
- [Customers & saved methods](/docs/payment-api/customers/)

## Request examples

```bash
curl -X POST https://api.spicepay.net/payments \
  -H 'api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order_2042' \
  -d '{
    "amount": 5000,
    "currency": "USD",
    "profile_id": "pro_xxxxx",
    "payment_link": true,
    "return_url": "https://shop.example/return",
    "description": "Order #2042",
    "customer": { "email": "ada@example.com", "name": "Ada Lovelace" },
    "metadata": { "order_id": "2042" },
    "test_mode": true
  }'
```

```bash
curl https://api.spicepay.net/payments/pay_xxxxx \
  -H 'api-key: YOUR_API_KEY'
```

```bash
curl -X POST https://api.spicepay.net/payments/list \
  -H 'api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "limit": 20,
    "offset": 0,
    "status": ["succeeded"],
    "test_mode": false
  }'
```

```bash
curl -X POST https://api.spicepay.net/payments/pay_xxxxx/capture \
  -H 'api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"amount_to_capture": 2500}'
```

```bash
curl -X POST https://api.spicepay.net/payments/pay_xxxxx/cancel \
  -H 'api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"cancellation_reason": "requested_by_customer"}'
```
