> For the complete documentation index, see [llms.txt](https://api-docs.visadoc.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api-docs.visadoc.co/authentication.md).

# Authentication

Every request except `POST /token` needs **two headers**: a Bearer token **and** `X-Data-Source`.

```http
Authorization: Bearer YOUR_TOKEN
X-Data-Source: YOUR_DATA_SOURCE
```

## Generate a token

Users with the **Admin** role on your VisaDoc instance generate API tokens with `POST /token`. It takes the Admin's email and password; no Bearer token is needed. Send your `X-Data-Source` header on this call as well.

```bash
curl -X POST https://api.visadoc.co/api:v3/token \
  -H "Content-Type: application/json" \
  -H "X-Data-Source: YOUR_DATA_SOURCE" \
  -d '{ "email": "admin@yourcompany.com", "password": "YOUR_PASSWORD", "expires_in": 2600000 }'
```

```json
{ "authToken": "eyJhbGciOi...", "expires_in": "2600000" }
```

| Field        | Required | Description                                                                                        |
| ------------ | -------- | -------------------------------------------------------------------------------------------------- |
| `email`      | Yes      | Email of a user with the **Admin** role                                                            |
| `password`   | Yes      | That user's password                                                                               |
| `expires_in` | No       | Token lifetime in **seconds**. Minimum `60`, maximum `2600000` (about 30 days). Default `2600000`. |

In the response, `authToken` is the token to send as `Authorization: Bearer …`, and `expires_in` echoes the lifetime as a **string**.

Only Admin users can generate tokens. If your Admin account has no password yet, ask VisaDoc for a password reset link.

## What a token can access

A token acts as the Admin who generated it: the same permissions and the same data they see in your VisaDoc instance.

## Lifetime and rotation

{% hint style="warning" %}
Generating a new token **immediately revokes that Admin's previous tokens**.
{% endhint %}

This decides how you run tokens in production:

* **Generate in one place.** If two systems each call `/token` with the same Admin account, each call revokes the other's token. Have one service generate the token and hand it to everything that needs it.
* **Rotate before expiry.** Tokens last at most about 30 days. Schedule regeneration well before that (for example weekly or every three weeks) and swap the new token in everywhere at once.
* **Compromised token?** Generate a new one. That revokes the compromised token straight away.
* There is **no refresh endpoint**: `/token` is how you get a new token.

## Required header: `X-Data-Source`

Each partner's data lives in its own isolated VisaDoc data source. `X-Data-Source` routes your request to yours. VisaDoc gives you the value when your instance is set up; it doesn't change, and it's the same for all your users.

A token belongs to one data source. If the header is missing, or names a different data source, the request is rejected:

```json
{
  "code": "ERROR_CODE_UNAUTHORIZED",
  "message": "This token belongs to a different datasource."
}
```

So if a token you know is valid returns `401`, check this header first. Header names aren't case-sensitive: `X-Data-Source` and `x-data-source` both work.

## A real call

Because searches are `POST`, a complete request looks like:

```bash
curl -X POST https://api.visadoc.co/api:v3/applications/search \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-Data-Source: YOUR_DATA_SOURCE" \
  -H "Content-Type: application/json" \
  -d '{ "page": 1, "per_page": 25, "filters": { "status": ["Documents"] } }'
```

## Trying requests

The Swagger UI at the base URL can't send custom headers, so calls from it fail without `X-Data-Source`. Use Postman, Insomnia or curl, or the **Test it** panel on this site's [API Reference](/api-reference/token.md) pages, where you can add the header.

## Good to know

* Call `/token` from your backend only. It takes an Admin's password, so never expose it in client-side code or source control. Treat the token itself like a password too.
* A missing, invalid or expired token, or a missing / wrong `X-Data-Source`, returns `401`. A valid token without rights to a specific resource returns `403`.
* Questions about API access: [**developers@visadoc.co**](mailto:developers@visadoc.co).

## Logging a traveller in without a password

To send a traveller into VisaDoc without a password, generate a magic link with `GET /magic_link`. See [Magic Link](/magic-link.md).
