> ## Documentation Index
> Fetch the complete documentation index at: https://docs.finhub.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication & Headers

> How to authenticate and which headers are required for every FinCard Virtual API call

# Authentication & Headers

Every FinCard Virtual API request must carry a valid **Bearer JWT** token and a set of **required context headers**. Missing any of them returns `HTTP 400 Missing required header(s)`.

***

## Step 1 — Obtain a Session Token

Call the login endpoint once to obtain a short-lived JWT. Pass it as `Authorization: Bearer <token>` in all subsequent requests.

```bash theme={null}
POST /api/auth/login
Content-Type: application/json
X-Tenant-ID: <your-tenant-id>
X-Forwarded-For: <client-ip>
X-Forwarded-From: <your-app-name>
platform: web
deviceId: <device-or-session-id>
```

**Request body:**

```json theme={null}
{
  "email": "user@your-domain.com",
  "password": "your-password",
  "tenantId": "your-tenant-id"
}
```

**Response:**

```json theme={null}
{
  "accessToken": "eyJ0eXAiOiJKV1Qi...",
  "tokenType": "Bearer",
  "expiresIn": 3600
}
```

<Note>
  `expiresIn` is in seconds. Tokens are valid for **1 hour**. Re-authenticate before expiry — there is no refresh token endpoint.
</Note>

***

## Step 2 — Include Headers on Every Request

All 46 FinCard Virtual endpoints require the following headers:

| Header             | Required | Example                     | Description                     |
| ------------------ | -------- | --------------------------- | ------------------------------- |
| `Authorization`    | **Yes**  | `Bearer eyJ0eXAi...`        | JWT from login                  |
| `Content-Type`     | **Yes**  | `application/json`          | Always JSON                     |
| `X-Tenant-ID`      | **Yes**  | `tenant_acme`               | Your tenant identifier          |
| `X-Forwarded-For`  | **Yes**  | `203.0.113.42`              | End-user IP address             |
| `X-Forwarded-From` | **Yes**  | `my-backend-service`        | Originating service name        |
| `platform`         | **Yes**  | `web` \| `ios` \| `android` | Client platform                 |
| `deviceId`         | **Yes**  | `device-abc-123`            | Unique device or session ID     |
| `User-Agent`       | No       | `MyApp/2.1`                 | Client user-agent (recommended) |

<Warning>
  `X-Forwarded-For`, `X-Forwarded-From`, `platform`, and `deviceId` are validated server-side. A `400 Missing required header(s)` error is returned if any are absent.
</Warning>

***

## Complete Request Example

```bash theme={null}
curl -X POST https://sandbox.finhub.cloud/api/v2.1/fincard/virtual/card/info \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1Qi..." \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: tenant_acme" \
  -H "X-Forwarded-For: 203.0.113.42" \
  -H "X-Forwarded-From: my-backend" \
  -H "platform: web" \
  -H "deviceId: device-abc-123" \
  -d '{ "cardNo": "FC-XXXX-XXXX" }'
```

***

## Response Envelope

Every response — success or error — is wrapped in the same envelope:

```json theme={null}
{
  "success": true,
  "code": 200,
  "msg": "Success",
  "data": { ... }
}
```

| Field     | Type            | Description                                                                   |
| --------- | --------------- | ----------------------------------------------------------------------------- |
| `success` | Boolean         | `true` = operation succeeded                                                  |
| `code`    | Integer         | `200` = OK, `-1` = business error, `401` = unauthorized, `500` = server error |
| `msg`     | String          | Human-readable status message                                                 |
| `data`    | Object \| Array | Response payload (varies per endpoint)                                        |

<Info>
  Even HTTP `200` responses can have `"success": false` for business-level errors (e.g. card not found, insufficient balance). Always check `success` **and** `code`.
</Info>

***

## Error Reference

| HTTP | `code` | Cause                                | Action                                  |
| ---- | ------ | ------------------------------------ | --------------------------------------- |
| 400  | 500    | Missing required header              | Add all required headers                |
| 401  | 401    | Missing or expired token             | Re-authenticate via `/api/auth/login`   |
| 401  | 401    | Empty authorization token            | Include `Authorization: Bearer <token>` |
| 200  | -1     | Business error (e.g. card not found) | Check `msg` for details                 |
| 200  | 200    | Success                              | Process `data` payload                  |

***

## SDK / Script Example (PowerShell)

```powershell theme={null}
# 1. Login
$loginBody = @{
    email    = "user@domain.com"
    password = "your-password"
    tenantId = "your-tenant-id"
} | ConvertTo-Json -Compress

$loginResp = Invoke-RestMethod -Uri "https://sandbox.finhub.cloud/api/auth/login" `
    -Method Post `
    -Headers @{
        "Content-Type"     = "application/json"
        "X-Tenant-ID"      = "your-tenant-id"
        "X-Forwarded-For"  = "127.0.0.1"
        "X-Forwarded-From" = "my-script"
        "platform"         = "web"
        "deviceId"         = "script-device-001"
    } `
    -Body $loginBody

# 2. Use token in all subsequent calls
$headers = @{
    "Authorization"    = "Bearer $($loginResp.accessToken)"
    "Content-Type"     = "application/json"
    "X-Tenant-ID"      = "your-tenant-id"
    "X-Forwarded-For"  = "127.0.0.1"
    "X-Forwarded-From" = "my-script"
    "platform"         = "web"
    "deviceId"         = "script-device-001"
}

# 3. Call any endpoint
$cardInfo = Invoke-RestMethod -Uri "https://sandbox.finhub.cloud/api/v2.1/fincard/virtual/card/info" `
    -Method Post -Headers $headers -Body '{"cardNo":"FC-XXXX-XXXX"}'
```
