# 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`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.luganodes.com/apis/settlex-flow/settlex-flow-gateway.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
