> ## Documentation Index
> Fetch the complete documentation index at: https://next-developers.opencard.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Set up OAuth2 account_client machine-to-machine credentials for your EMS integration, request bearer tokens, and pick the right scopes for OpenCard endpoints.

EMS integrations authenticate with an **`account_client`** OAuth client — machine-to-machine credentials tied to your partner account.

<Note>
  This docs site covers **account\_client** only. Other client types (`organization_client`, `account_user`, etc.) exist internally but are not part of the EMS integration path.
</Note>

***

## Get a token

```
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
```

```bash theme={null}
curl -X POST https://sandbox-api.opencard.io/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Accept: application/json" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=organizations-read organizations-write webhooks-write"
```

**Response:**

```json theme={null}
{
  "token_type": "Bearer",
  "expires_in": 31536000,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
```

Use on every API call:

```
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...
Accept: application/json
```

<Warning>
  Always send `Accept: application/json` on Application API and OAuth requests. Without it, auth failures may return an HTML login page instead of a JSON error body.
</Warning>

***

## Create an account\_client

**Dashboard:** Account → OAuth Clients → Create New

Or via API (requires an existing client with `oauth-clients-write`):

```
POST /accounts/{accountId}/oauthclients
```

Response includes `secret` in **plain text** — shown once. Store it immediately.

Update scopes later:

```
PUT /accounts/{accountId}/oauthclients/{oauthclientId}
{ "scopes": ["organizations-read", "organizations-write", "webhooks-write"] }
```

Clients created on an account **without** an `organization_id` are `account_client` — this is what you want.

***

## Recommended scopes for EMS

Start with this set:

```
account-tpas-read account-tpas-write account-tpa-signatories-write account-tpa-identities-read
organizations-read organizations-write
card-holders-read card-holders-write
webhooks-read webhooks-write webhook-events-read
public-records-read
account-card-issuers-read account-card-issuers-write
oauth-clients-read
billings-write
receipts-write
```

Request only what you need. Scopes are space-separated in the token request.

***

## All account\_client scopes

| Scope                                                              | What it unlocks                    |
| ------------------------------------------------------------------ | ---------------------------------- |
| `accounts-read` / `accounts-write`                                 | Your account settings              |
| `oauth-clients-read` / `oauth-clients-write`                       | Manage OAuth clients               |
| `public-records-read`                                              | Company registry lookup            |
| `account-tpas-read` / `account-tpas-write` / `account-tpas-delete` | TPAs                               |
| `account-tpa-signatories-read` / `-write` / `-delete`              | TPA signatories                    |
| `account-tpa-identities-read`                                      | Identities on a TPA                |
| `account-card-issuers-read` / `-write` / `-delete`                 | Enable card programs               |
| `organizations-read` / `-write` / `-delete`                        | Organizations                      |
| `card-holders-read` / `-write` / `-delete`                         | Card holders                       |
| `webhooks-read` / `webhooks-write`                                 | Webhooks                           |
| `webhook-events-read`                                              | Webhook delivery log               |
| `webhook-headers-read` / `-write` / `-delete`                      | Custom webhook headers             |
| `webhook-groups-read` / `-write` / `-delete`                       | Buyer-party webhook filters        |
| `billings-read` / `billings-write`                                 | Billing profiles                   |
| `receipts-write`                                                   | Receipt OCR scan                   |
| `files-read`                                                       | Download files (e.g. receipt URLs) |
| `card-issuers-read`                                                | List available card programs       |
| `environmental-impacts-read`                                       | CO₂ data on transactions           |
| `account-users-read` / `-write` / `-delete`                        | Account user management            |
| `account-statistics-read`                                          | Account statistics                 |

***

## Access control

Your `account_client` token is tied to your **account**. The API checks:

1. Token has the required scope for the route
2. Token owner has access to `accountId` / `organizationId` in the URL

You can only access your own account's resources.

***

## Errors

| Status | Meaning                                                |
| ------ | ------------------------------------------------------ |
| `401`  | Invalid or expired token                               |
| `403`  | Valid token but missing scope or no access to resource |
| `404`  | Resource doesn't exist (or you can't see it)           |
