# Request Headers

All public REST endpoints live under `/payments-api/v1`. This page documents every HTTP request header the API reads. Headers not listed here are ignored.

---

## Required headers

### `Authorization`

```http
Authorization: Bearer <token>
```

| Property | Value |
|----------|-------|
| Type | String |
| Required | Yes — all endpoints |
| Format | `Bearer ` followed by the seller bearer token (no quotes, no extra whitespace) |

Every request to `/payments-api/v1/*` is processed through `SellerAccountAuthMiddleware`, which reads this header and resolves the token to a seller account. There is no other authentication mechanism on the REST surface.

**Failure modes:**

| Condition | Status | Body (note: plaintext, not JSON) |
|-----------|--------|----------------------------------|
| Header absent or empty | `401` | `authorization token is required` |
| Token not recognized | `401` | `invalid authorization token` |
| Seller account inactive | `403` | `seller account is not active` |

> [!CAUTION]
> The `401` response from the auth middleware is **plain text**, not JSON. Once a request passes authentication and enters a handler, all subsequent errors are JSON `{"error": "..."}`.

---

### `Content-Type`

```http
Content-Type: application/json
```

| Property | Value |
|----------|-------|
| Type | String |
| Required | Yes — POST requests with a body |
| Format | `application/json` |

Required on all POST endpoints that accept a request body: `/initialize-payment`, `/finalize-payment`, `/payments/{id}/capture`, `/payments/{id}/refund`, `/payouts`, `/checkout`. GET requests do not require a `Content-Type` header.

---

### `Idempotency-Key`

```http
Idempotency-Key: 6f9b84e1-3b83-4fb9-9f42-a8ac27d11d6b
```

| Property | Value |
|----------|-------|
| Type | UUID string |
| Required | Yes — all POST endpoints (except `/payouts`; see note below) |
| Format | UUID v4, lower-case, hyphenated — e.g. `6f9b84e1-3b83-4fb9-9f42-a8ac27d11d6b` |

The idempotency key makes POST requests safe to retry. If the server has already processed a request with the same key for the same seller account, it returns the existing operation rather than creating a new resource.

**Validation:**

| Condition | Status | Body |
|-----------|--------|------|
| Header absent or empty | `400` | `{"error": "Idempotency-Key header is required"}` |
| Value is not a valid UUID | `400` | `{"error": "Idempotency-Key must be a valid UUID"}` |

**On `/initialize-payment`:** a matching idempotency key returns `200 OK` with the existing payment instead of the usual `202 Accepted`. For an active APM, Fynex re-reads the provider charge and includes the current buyer action again, including Multibanco `paymentInstructions` when available.

**On `/finalize-payment`:** the header is validated and must be a valid UUID, but the value is not used for idempotency lookup on this endpoint — it is discarded after validation.

> [!NOTE]
> `POST /payouts` uses an `idempotencyKey` field in the **request body** rather than this header. On `/payouts` the `Idempotency-Key` header is **optional**: the body field `idempotencyKey` is authoritative and drives deduplication, and the header is used only as a fallback when the body field is empty.

---

## Optional headers

### `X-Device-Fingerprint`

```http
X-Device-Fingerprint: <fingerprint-string>
```

| Property | Value |
|----------|-------|
| Type | String |
| Required | No |
| Format | Opaque string, trimmed of whitespace |

Device fingerprint forwarded to the upstream card processor as a risk signal. If present, it is stored on `GenericPayment.DeviceFingerprint` and included in the provider authorization request. Collecting a device fingerprint from the customer's browser and forwarding it here improves authorization rates on risk-sensitive transactions.

For device intelligence, first call `POST /payments-api/v1/device-intelligence/token`, initialize `@sumsub/fisherman` in the customer's browser with the returned `accessToken`, then send the returned `sessionId` as `deviceSessionId` in the `/initialize-payment` body. If your browser SDK also returns a visitor id, you may continue to send it as `X-Device-Fingerprint`.

---

### `X-Source-Channel`

```http
X-Source-Channel: api
```

| Property | Value |
|----------|-------|
| Type | Enum string |
| Required | No |
| Allowed values | `api` (default), `admin_panel` |

Identifies the origin channel of the request. The value is lower-cased before processing. Any value other than `admin_panel` — including an absent header — is treated as `api`. Stored on `GenericPayment.SourceChannel`.

Use `admin_panel` only when the request originates from a Fynex internal backoffice action. Partner integrations should omit this header or use `api`.

---

### `Accept-Language`

```http
Accept-Language: en-GB,en;q=0.9
```

| Property | Value |
|----------|-------|
| Type | String (standard HTTP) |
| Required | No |
| Format | Standard `Accept-Language` value per RFC 7231 |

Stored on `GenericPayment.AcceptLanguage` and may be forwarded to the upstream processor. Include when you want to pass the customer's preferred language for any provider-side communication or challenge pages.

---

## Headers the server does not set

The Fynex API does not currently set `X-Fynex-Request-Id` or `X-Fynex-Trace-Id` response headers. Do not rely on these for correlation — use the `paymentId` (your `externalOrderRef`) and the provider's `providerPaymentId` from the response body instead.

---

## Quick reference

| Header | Required | Endpoints |
|--------|----------|-----------|
| `Authorization: Bearer <token>` | Yes | All |
| `Content-Type: application/json` | Yes | POST with body |
| `Idempotency-Key: <uuid>` | Yes | All POST |
| `X-Device-Fingerprint: <string>` | No | All POST |
| `X-Source-Channel: api\|admin_panel` | No | All POST |
| `Accept-Language: <value>` | No | All POST |

---

## Example request with all headers

```http
POST /payments-api/v1/initialize-payment HTTP/1.1
Host: api.fynex.ai
Authorization: Bearer YOUR_SELLER_TOKEN
Content-Type: application/json
Idempotency-Key: 6f9b84e1-3b83-4fb9-9f42-a8ac27d11d6b
X-Device-Fingerprint: fp_a1b2c3d4e5f6
X-Source-Channel: api
Accept-Language: en-GB,en;q=0.9

{ ... }
```

Tokens are opaque strings with no prefix (e.g. no `sk_live_` or `sk_test_`). Replace `YOUR_SELLER_TOKEN` with the full token value provided by Fynex.

## See also

- **[Authentication](https://api.fynex.ai/payments-api/v2/docs#tag/authentication)** — How to obtain, use, and rotate seller bearer tokens.
- **[Idempotency](https://api.fynex.ai/payments-api/v2/docs#tag/idempotency)** — How the Idempotency-Key header prevents duplicate payments.
