> For the complete documentation index, see [llms.txt](https://docs.luganodes.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.luganodes.com/apis/settlex-flow/settlex-flow-gateway.md).

# Settlex Flow - Gateway

> **Base URL:** `settlex-gateway.luganodes.com`\
> **Protocol:** HTTP/REST\
> **Authentication:** API Key

## Prerequisites

Before using the gateway you must have a funded Settlex account. Set up is done through the [**Settlex AP**](/apis/settlex-flow/settlex-flow-onboarding.md)**I** (`/api` service):

| Step                     | API Call                                                                 | What You Get                 |
| ------------------------ | ------------------------------------------------------------------------ | ---------------------------- |
| 1. Create an account     | `POST /api/onboarding/signup`                                            | User account                 |
| 2. Log in                | `POST /api/onboarding/login`                                             | JWT token                    |
| 3. Create a Canton party | `POST /api/party/create` (Auth: Bearer token)                            | Ledger identity (`partyId`)  |
| 4. Generate an API key   | <p><code>POST /api/api-key/create</code> </p><p>(Auth: Bearer token)</p> | Raw API key (shown **once**) |
| 5. Fund your party       | Transfer Canton Coin to your party via the Canton Network                | Spendable balance            |

Once you have an **active API key** and a **funded balance**, you are ready to use the gateway.

## Authentication

Every gateway request must include your API key in the `x-settlex-api-key` header.

```http
x-settlex-api-key: <your_api_key>
```

The gateway verifies it against the database, and resolves your Canton party identity. The key header is **stripped** before the request is forwarded to the upstream provider — providers never see your Settlex credentials.

### Authentication Errors

| Status | Body                                           | Condition                                  |
| ------ | ---------------------------------------------- | ------------------------------------------ |
| `401`  | `{ "message": "Unauthorized" }`                | Missing header or unknown API key          |
| `403`  | `{ "message": "API Key is no longer active" }` | Key has been deactivated                   |
| `403`  | `{ "message": "User does not have a party" }`  | User has no Canton party onboarded with us |

### Making Requests

All requests follow one pattern:

```http
<METHOD> /gateway/<providerKey>/<upstream_path>
```

| Component         | Description                                            |
| ----------------- | ------------------------------------------------------ |
| `<METHOD>`        | Any HTTP method (`GET`, `POST`, `PUT`, `DELETE`, etc.) |
| `<providerKey>`   | The unique identifier of the registered provider       |
| `<upstream_path>` | The path the provider expects (forwarded as-is)        |

The gateway strips `/gateway/<providerKey>` from the path before forwarding. For example:

```http
POST /gateway/acme-ai/v1/chat/completions
```

is forwarded to the `acme-ai` provider as:

```http
POST /v1/chat/completions
```

The request body, query parameters, and most headers are forwarded transparently. The provider's response (status code, headers, body) is returned to you as-is.

#### Example

```bash
curl -X POST https://settlex-gateway.luganodes.com/gateway/acme-ai/v1/chat/completions \
  -H "x-settlex-api-key: your_api_key_here" \
  -H "idempotency-key: unique-request-id-001" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4",
    "messages": [{ "role": "user", "content": "Hello" }]
  }'
```

### Required Headers

Every gateway request **must** include both of these headers:

| Header              | Type   | Description                                                     |
| ------------------- | ------ | --------------------------------------------------------------- |
| `x-settlex-api-key` | string | Your Settlex API key                                            |
| `idempotency-key`   | string | A unique key for this request (see [Idempotency](#idempotency)) |

Any additional headers your provider expects (e.g. `Content-Type`) should be included as normal.

### Request Lifecycle

Every request passes through four stages before the provider response reaches you:

```
Client Request
  → 1. Authentication     Verify API key, resolve party
  → 2. Idempotency        Check for duplicate request
  → 3. Reservation         Reserve CC balance for this request
  → 4. Proxy               Forward to provider, return response
```

{% stepper %}
{% step %}

#### Authentication

Your API key is validated and your Canton party ID is resolved.
{% endstep %}

{% step %}

#### Idempotency

The `idempotency-key` is checked against existing reservations for the same provider. If a duplicate is found, the request is rejected with `409`.
{% endstep %}

{% step %}

#### Reservation

The provider's cost (in USD) is converted to Canton Coin at the current exchange rate. That amount is reserved from your available balance. A reservation record is created.
{% endstep %}

{% step %}

#### Proxy

The request is forwarded to the provider. On a successful upstream response (2xx/3xx), the reservation is marked `registered`. On failure, the reservation is marked `failed` and reserved funds are released back to your balance.
{% endstep %}
{% endstepper %}

## Error Responses

### Provider Errors

If the upstream provider **successfully sends a full HTTP response (success or error),** they are forwarded to you as-is. If the gateway encounters errors while communicating (internal or transport level error) with the provider for any reason, custom [errors](#gateway-errors) are sent by the gateway.

### Gateway Errors

All gateway errors return JSON in the format:

```json
{
  "message": "Human-readable error description"
}
```

| Status | Message                                                | Stage                     | Cause                                               |
| ------ | ------------------------------------------------------ | ------------------------- | --------------------------------------------------- |
| `400`  | `"Idempotency key is required"`                        | Idempotency               | Missing `idempotency-key` header                    |
| `400`  | `"Idempotency key must be a string, and not an array"` | Idempotency               | Header has multiple values                          |
| `400`  | `"Provider key is required"`                           | Reservation               | Invalid URL path                                    |
| `401`  | `"Unauthorized"`                                       | Auth                      | Missing or invalid API key                          |
| `403`  | `"API Key is no longer active"`                        | Auth                      | Deactivated API key                                 |
| `403`  | `"User does not have a party"`                         | Auth                      | No Canton party on account                          |
| `403`  | `"Party does not have enough balance"`                 | Reservation               | Insufficient CC balance                             |
| `403`  | `"Provider is not active"`                             | Reservation               | Provider is disabled or degraded                    |
| `404`  | `"Provider not found"`                                 | Reservation / Proxy       | Unknown `providerKey`                               |
| `409`  | `"Idempotency key already exists"`                     | Idempotency / Reservation | Duplicate request (see [Idempotency](#idempotency)) |
| `500`  | `"Internal server error"`                              | Any                       | Unexpected server error                             |
| `502`  | `"Bad gateway: provider unavailable"`                  | Proxy                     | Provider connection failed                          |
| `502`  | `"Bad gateway: upstream aborted response"`             | Proxy                     | Provider dropped the connection                     |
| `502`  | `"Bad gateway: upstream response stream error"`        | Proxy                     | Provider response stream broke                      |

> On any upstream failure (`4xx`, `5xx`, timeout, connection error), reserved funds are automatically released.

## Idempotency

Every request requires an `idempotency-key` header — a client-generated string that uniquely identifies the request. Idempotency keys are scoped to the combination of:

* **idempotency key** (your value)
* **provider key** (from the URL path)
* **party ID** (from your account)

This means the same idempotency key can be safely reused across different providers.

### Duplicate Request Response

If a reservation already exists for the same `(idempotencyKey, providerKey, partyId)` tuple, the gateway returns:

```json
{
  "message": "Idempotency key already exists",
  "reservation": {
    "idempotencyKey": "unique-request-id-001",
    "partyId": "party-abc123::1220...",
    "providerKey": "acme-ai",
    "costInUSD": 0.03,
    "status": "registered",
    "createdAt": "2025-06-15T10:30:00.000Z",
    "updatedAt": "2025-06-15T10:30:01.000Z"
  }
}
```

### Reservation Statuses

| Status              | Meaning                                                       |
| ------------------- | ------------------------------------------------------------- |
| `request_in_flight` | Request sent to provider, awaiting response                   |
| `registered`        | Provider responded successfully (2xx/3xx)                     |
| `failed`            | Provider returned an error or was unreachable; funds released |
| `queued`            | Processing has begun, awaiting ledger finalization            |
| `settled`           | Transaction completed on ledger                               |

## Balance & Billing

Each provider has a fixed cost per request in USD. When you make a request, the gateway:

1. Converts the USD cost to Canton Coin (CC) using the current exchange rate.
2. Checks that your **available balance minus reserved balance** is sufficient.
3. Atomically reserves the CC amount from your balance.

On **success**, the reservation stays and the funds are considered spent. On **failure**, the reserved amount is released back to your available balance.

You can check your current balance at any time via the Settlex API:

```bash
curl -X GET https://settlex-api.luganodes.com/api/balance \
  -H "Authorization: Bearer <your_jwt_token>"
```

```json
{
  "balance": 1000.50,
  "reservedBalance": 3.25
}
```

* `balance` — total available Canton Coin
* `reservedBalance` — amount currently locked for in-flight requests
* **Spendable** = `balance - reservedBalance`
