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

# Service Token

> Obtain an OAuth2 Bearer token for machine-to-machine API integrations using the Client Credentials grant.

# POST /oauth/token

Exchange your integration credentials (`client_id` + `client_secret`) for a short-lived Bearer token. This is the recommended authentication method for all programmatic integrations.

<Note>
  This endpoint does not require prior authentication. Credentials are provisioned by your DokStamp account manager.
</Note>

***

## Request

```http theme={null}
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
```

| Parameter       | Type   | Required | Description                    |
| --------------- | ------ | -------- | ------------------------------ |
| `grant_type`    | string | Yes      | Must be `client_credentials`   |
| `client_id`     | string | Yes      | Your integration client ID     |
| `client_secret` | string | Yes      | Your integration client secret |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.dokstamp.com/oauth/token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch('https://api.dokstamp.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.DOKSTAMP_CLIENT_ID,
      client_secret: process.env.DOKSTAMP_CLIENT_SECRET,
    }),
  });
  const { access_token, expires_in } = await res.json();
  ```

  ```php PHP theme={null}
  $response = Http::asForm()->post('https://api.dokstamp.com/oauth/token', [
      'grant_type'    => 'client_credentials',
      'client_id'     => env('DOKSTAMP_CLIENT_ID'),
      'client_secret' => env('DOKSTAMP_CLIENT_SECRET'),
  ]);
  $token = $response->json('access_token');
  ```
</CodeGroup>

## Response `200`

```json theme={null}
{
  "token_type": "Bearer",
  "expires_in": 43200,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
}
```

| Field          | Type    | Description                                                          |
| -------------- | ------- | -------------------------------------------------------------------- |
| `access_token` | string  | Bearer token — include in `Authorization` header of all API requests |
| `expires_in`   | integer | Validity in seconds (`43200` = 12 hours)                             |
| `token_type`   | string  | Always `"Bearer"`                                                    |

## Error `401`

```json theme={null}
{
  "error": "invalid_client",
  "error_description": "Client authentication failed",
  "message": "Client authentication failed"
}
```

***

## Using the token

Add the token to every subsequent request:

```http theme={null}
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...
Accept: application/json
X-Tenant: your-tenant-identifier
```

***

## Token expiry and renewal

Service tokens expire after **12 hours**. There is no refresh token — request a new token when the current one expires. Recommended pattern: cache the token and renew it proactively \~60 seconds before expiry.

```javascript theme={null}
let token = null;
let expiresAt = null;

async function getToken() {
  if (token && Date.now() < expiresAt - 60_000) return token;

  const res = await fetch('https://api.dokstamp.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.DOKSTAMP_CLIENT_ID,
      client_secret: process.env.DOKSTAMP_CLIENT_SECRET,
    }),
  });

  const data = await res.json();
  token = data.access_token;
  expiresAt = Date.now() + data.expires_in * 1000;
  return token;
}
```

***

## Rotating credentials

If a `client_secret` is compromised, contact your DokStamp account manager to rotate the credentials. A new `client_id` / `client_secret` pair will be issued and all existing tokens for the old credentials will be immediately revoked.
