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

# Authentication

> How to authenticate your requests in the Safefy API

Safefy uses **OAuth2 Client Credentials** for authentication. You must obtain a JWT token before making any other request.

<Info>
  Credential permissions (module-level read/write, including cashouts) are detailed in [Credential permissions](/en/credential-permissions).
</Info>

## How it works

```mermaid theme={null}
sequenceDiagram
    participant App as Your Application
    participant Safefy as Safefy API
    
    App->>Safefy: POST /v1/auth/token (credentials)
    Safefy-->>App: JWT token (expires in 1h)
    App->>Safefy: GET /v1/transactions (Authorization: Bearer token)
    Safefy-->>App: Transaction data
```

## Getting the token

```bash theme={null}
curl -X POST https://api-payment.safefypay.com.br/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grantType": "client_credentials",
    "publicKey": "pk_sandbox_abc123...",
    "secretKey": "sk_sandbox_xyz789..."
  }'
```

**Response:**

```json theme={null}
{
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "tokenType": "Bearer",
    "expiresIn": 3600,
    "environment": "Sandbox"
  }
}
```

## Using the token

Include the token in the `Authorization` header for all requests:

```bash theme={null}
curl https://api-payment.safefypay.com.br/v1/transactions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

<Warning>
  The token expires in **1 hour** (3600 seconds). Refresh it before expiration to avoid interruptions.
</Warning>

***

## Rate limiting

Token generation is limited to **10 requests per hour** per credential pair (`publicKey` + `secretKey`). If you exceed this limit, the API returns `429 Too Many Requests` with the error code `auth_rate_limit_exceeded`.

<Warning>
  **Do not generate a new token on every API call.** Cache the token and reuse it for its full 1-hour lifetime. Excessive token generation will trigger the rate limit and block your integration.
</Warning>

## Token caching

Implement token caching to avoid unnecessary requests and stay well within the rate limit:

```
1. Check if savedToken exists
2. If yes  check if (expiresAt - 5 minutes) > now
3. If still valid  reuse savedToken   no API call needed
4. If expired or not found  call POST /v1/auth/token
5. Save new token + calculated expiresAt  use it
```

<Tip>
  Treat the token as expired **25 minutes before** its actual expiry (`expiresIn - 300` seconds). This protects against clock skew between your server and Safefy's servers.
</Tip>

***

## Security best practices

<CardGroup cols={2}>
  <Card title="Never expose the secretKey" icon="shield">
    Keep the secretKey only on the backend. Never include it in frontend code or public repositories.
  </Card>

  <Card title="Use environment variables" icon="lock">
    Store credentials in environment variables or secret managers (AWS Secrets Manager, Vault, etc).
  </Card>

  <Card title="Refresh before expiration" icon="rotate">
    Implement logic to refresh the token before the 3600 seconds expire.
  </Card>

  <Card title="Restrict allowed IPs" icon="network-wired">
    In the Safefy dashboard, restrict credential usage to your server IPs.
  </Card>
</CardGroup>

***

## Common errors

| Code | Error               | Solution                                     |
| ---- | ------------------- | -------------------------------------------- |
| 401  | Invalid credentials | Check publicKey and secretKey                |
| 403  | Unauthorized IP     | Add the IP in the credential settings        |
| 429  | Rate limit exceeded | Wait for the time indicated in `Retry-After` |

<Card title="Test authentication" icon="play" href="/en/api-reference/auth/token">
  Try the authentication endpoint in the playground.
</Card>
