# Authentication

> How to authenticate with the FX-Port API using Bearer tokens, the key permissions, the key prefixes and the environments.

Source: https://fx-port.com/docs/authentication

Every request carries an API key as a bearer token in the `Authorization` header:

~~~http
Authorization: Bearer fxp_test_YOUR_KEY
~~~

Get your API keys at [fx-port.com/dashboard/api](https://fx-port.com/dashboard/api). The word `Bearer` is not case-sensitive.


> [!WARNING]
> Keys belong on your server. A Read+Write key can create bookings and debit your balance. Never put a key in a browser, a mobile app or a public repository: see [Security](https://fx-port.com/docs/security.md).


## The key

A key is a prefix followed by 32 lowercase hexadecimal characters (41 characters in all). FX-Port stores only a hash of it, so a lost key cannot be recovered: create a new one.

~~~text
fxp_live_<32 lowercase hexadecimal characters>
fxp_test_<32 lowercase hexadecimal characters>
~~~

| Prefix | Environment | What it does |
|---|---|---|
| `fxp_live_` | **Live** | Real agency data, real bookings, your real balance |
| `fxp_test_` | **Sandbox** | Isolated test bookings on the suppliers' test systems, no balance debit |

There is **one base URL** (`https://api.fx-port.com`) for both environments: the key decides. Every JSON body carries `"environment": "sandbox"` or `"live"`, and so does the `X-Environment` response header. A key resolves your agency by itself, so you never send an agency id. See [Environments and Postman](https://fx-port.com/docs/environments.md) and [Sandbox](https://fx-port.com/docs/sandbox.md).

## Permission levels

Each key is either **Read** or **Read+Write**.

| Permission | What it allows |
|---|---|
| **Read** | Everything that does not create, pay for or cancel something: searching, pricing, hotel content and rates, retrieving bookings and tickets, eSIM catalogue, usage and instructions, balances, history, suppliers |
| **Read+Write** | All of the above **plus** the endpoints that change data or money, listed below |

These endpoints need a Read+Write key. A Read key gets `403 read_write_permission_required`:

| Product | Endpoints |
|---|---|
| Flights | `POST /flights/book_flight`, `POST /flights/pay_order`, `POST /flights/cancel_order`, `POST /flights/confirm_cancel`, `POST /flights/upload_acd_documents` |
| Hotels | `POST /hotels/pre_book`, `POST /hotels/book_hotel`, `POST /hotels/cancel_hotel` |
| eSIMs | `POST /esims/orders`, `POST /esims/topups` |

Use a Read key wherever the code only displays results.

## IP restrictions

In the dashboard you can restrict a key to a list of IPv4 or IPv6 addresses or CIDR ranges. This works for any key, live or sandbox, and is recommended for production Read+Write keys. A request from another address gets `403 ip_not_allowed`, and the message names the address FX-Port saw.

## Your agency must be approved for live

A `fxp_live_` key only works once your agency is approved. Until then it answers `403 agency_not_active` and you keep building with the sandbox key, which works while the agency is pending.

## Changes take up to five minutes

Keys, permissions, IP lists and the agency status are cached for 5 minutes. After you revoke a key, change its permission or edit its IP list, allow up to five minutes before the change applies everywhere.

## When authentication fails

| Status | Code | Cause |
|---|---|---|
| 401 | `authentication_required` | No key was sent |
| 401 | `invalid_api_key_format` | The key is not shaped like an FX-Port key: `fxp_live_` or `fxp_test_` followed by 16 to 64 letters and digits |
| 401 | `invalid_api_key` | The key is unknown, revoked or expired |
| 403 | `ip_not_allowed` | The key has an IP list and the request came from another address |
| 403 | `agency_not_active` | The agency is not approved for this environment yet |
| 403 | `read_write_permission_required` | A Read key called an endpoint that needs Read+Write |

~~~json
{
  "environment": "sandbox",
  "success": false,
  "errors": [
    {
      "code": "read_write_permission_required",
      "type": "permission_error",
      "title": "Read+Write key required",
      "message": "This endpoint requires an API key with read_write permission.",
      "field": null,
      "details": {},
      "documentation_url": "https://fx-port.com/docs/errors#read_write_permission_required"
    }
  ],
  "meta": { "request_id": "req_8f3a9c1d2e4b", "status": 403 },
  "request_id": "req_8f3a9c1d2e4b"
}
~~~

When the key is missing or invalid, the body says `"environment": "live"`, because FX-Port cannot tell which environment a key it does not know belongs to. [Errors](https://fx-port.com/docs/errors.md) lists every code and the older bodies some endpoints still return next to `errors`.

## What not to send

- **`X-API-Key`** is reserved for FX-Port's own applications. If you send it, even by mistake, it takes precedence over your bearer key and the request fails with 401. Use `Authorization: Bearer` only.
- **`X-Environment`** is ignored for API keys: the key prefix decides.
- **A browser.** CORS is enabled for FX-Port's own sites only, so a browser app on another origin cannot read the answers. Call the API from your server.

## Security

Key handling, minimal-permission keys, booking-ownership checks and general API security hygiene have their own page: [Security](https://fx-port.com/docs/security.md).
