# Authentication

### Overview

| Level       | Mechanism | Header                                    | Use                                        |
| ----------- | --------- | ----------------------------------------- | ------------------------------------------ |
| **Partner** | API key   | `Authorization: Api-Key dm_live_skey_...` | Token generation, partner limits, API keys |
| **User**    | JWT       | `Authorization: Bearer <jwt>`             | Positions, quotes, user limits             |
| **Public**  | None      | —                                         | Market browsing                            |

API keys are environment-scoped. Production keys start with `dm_live_skey_`; sandbox keys start with `dm_sbx_skey_` and only work against `https://api-sandbox.dimes.fi`. See [Environments](/for-developers/environments.md) for the full comparison.

***

### API keys

API keys are issued by the Dimes team on request — reach out via the Telegram link on [dimes.fi](https://dimes.fi). Each key is scoped to a single partner and a single environment, and identifies all requests as coming from that integration.

{% tabs %}
{% tab title="REST API" %}

```bash
curl https://api.dimes.fi/v1/prediction-markets/partners/limits \
  -H "Authorization: Api-Key dm_live_skey_your_api_key"
```

```javascript
const headers = {
  "Authorization": `Api-Key ${process.env.DIMES_API_KEY}`,
  "Content-Type": "application/json",
};
```

{% endtab %}

{% tab title="SDK" %}

```typescript
import { DimesClient, ApiKeyAuth } from "@dimes-dot-fi/sdk";

const client = new DimesClient({
  auth: new ApiKeyAuth({
    apiKey: process.env.DIMES_API_KEY,
    walletAddress: "0x1234...abcd",
  }),
});
```

{% endtab %}
{% endtabs %}

API keys follow the format `<env_prefix>_skey_` followed by a random string:

* `dm_live_skey_...` — production keys, valid against `https://api.dimes.fi`.
* `dm_sbx_skey_...` — sandbox keys, valid against `https://api-sandbox.dimes.fi`.

A key is only valid against the base URL it was issued for. Cross-environment requests are rejected. You can have up to **two active keys** per environment at a time, enabling zero-downtime rotation.

***

### User JWTs

User-scoped endpoints require a JWT, generated via the partner API key. The JWT scopes all queries to a specific `(wallet_address, partner_id)` pair.

#### Generating a token

{% tabs %}
{% tab title="REST API" %}

```bash
curl -X POST https://api.dimes.fi/v1/prediction-markets/tokens \
  -H "Authorization: Api-Key dm_live_skey_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "wallet_address": "0x1234...abcd" }'
```

**Response: `201 Created`**

```json
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_at": "2025-06-01T11:00:00.000Z"
}
```

| Field        | Description                                  |
| ------------ | -------------------------------------------- |
| `token`      | JWT to use in `Authorization: Bearer` header |
| `expires_at` | Token expiry (1 hour from creation)          |
| {% endtab %} |                                              |

{% tab title="SDK" %}
`ApiKeyAuth` handles token generation and refresh automatically. When you create a client with `ApiKeyAuth`, it exchanges your API key and wallet address for a JWT behind the scenes and refreshes it before expiry.

```typescript
import { DimesClient, ApiKeyAuth } from "@dimes-dot-fi/sdk";

const client = new DimesClient({
  auth: new ApiKeyAuth({
    apiKey: process.env.DIMES_API_KEY,
    walletAddress: "0x1234...abcd",
  }),
});

// No manual token management needed — just make requests
const positions = await client.getPositions();
```

{% endtab %}

{% tab title="React" %}

```tsx
import { DimesProvider } from "@dimes-dot-fi/sdk/react";
import { ApiKeyAuth } from "@dimes-dot-fi/sdk";

function App() {
  return (
    <DimesProvider
      auth={
        new ApiKeyAuth({
          apiKey: process.env.DIMES_API_KEY,
          walletAddress: "0x1234...abcd",
        })
      }
    >
      <YourApp />
    </DimesProvider>
  );
}
```

{% endtab %}
{% endtabs %}

#### Using the token

{% tabs %}
{% tab title="REST API" %}

```bash
curl https://api.dimes.fi/v1/prediction-markets/positions \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
```

```javascript
const userHeaders = {
  "Authorization": `Bearer ${jwt}`,
  "Content-Type": "application/json",
};
```

Tokens are valid for 1 hour. Your backend should generate a new token for each user session or when the current one approaches expiry.
{% endtab %}

{% tab title="SDK" %}
Point `JwtAuth` at your backend's token endpoint. It fetches, caches, and auto-refreshes tokens before they expire:

```typescript
import { DimesClient, JwtAuth } from "@dimes-dot-fi/sdk";

const client = new DimesClient({
  auth: new JwtAuth({ tokenUrl: "https://your-backend.com/api/dimes-token" }),
});
```

Your endpoint should call `POST /v1/prediction-markets/tokens` with your API key server-side and return the `{ token, expires_at }` response.
{% endtab %}
{% endtabs %}

JWTs are safe to pass to your frontend — they scope queries to a single wallet and expire after 1 hour. API keys must never leave your backend.

***

### Key security

Your API key carries full access to your integration — including the ability to generate user tokens and view partner limits. Treat it like a password.

**Do:**

* Store keys in environment variables or a secrets manager.
* Make all Dimes API calls from your backend server.
* Rotate keys immediately if you suspect a leak.

**Don't:**

* Embed keys in client-side code (JavaScript bundles, mobile apps).
* Commit keys to version control.
* Share keys over unencrypted channels.

***

### Key rotation

Zero-downtime rotation with two active keys:

1. Request a new key from the Dimes team via the Telegram link on [dimes.fi](https://dimes.fi).
2. Deploy the new key to your servers.
3. Verify requests succeed with the new key.
4. Ask us to revoke the old key.

Both keys are valid simultaneously until the old one is revoked. There is no automatic expiry.

***

### Error responses

All authentication errors follow the standard error format:

| Status | Type                    | Code                                   | Meaning                          |
| ------ | ----------------------- | -------------------------------------- | -------------------------------- |
| `401`  | `AUTHENTICATION_ERROR`  | `unauthorized`                         | Missing or invalid API key / JWT |
| `400`  | `INVALID_REQUEST_ERROR` | `customer_auth_invalid_wallet_address` | Wallet address failed validation |

```json
{
  "error": {
    "type": "AUTHENTICATION_ERROR",
    "code": "unauthorized",
    "message": "Unauthorized"
  }
}
```

For the full error taxonomy, see [Error Handling](/for-developers/error-handling.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.dimes.fi/for-developers/authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
