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

# BRP API: Conventions

> Pagination, error handling, timestamps, delivery periods, and rate limiting

<h3 id="pagination">
  Pagination
</h3>

All list endpoints support cursor-based pagination using two parameters:

| Parameter | Type    | Description                                                                        |
| --------- | ------- | ---------------------------------------------------------------------------------- |
| `limit`   | integer | Max items per page (default: 10, max: 100)                                         |
| `after`   | string  | Cursor for the next page — pass the `next_cursor` value from the previous response |

Paginated responses include a `pagination` object with a `next_cursor` field:

```json theme={null}
{
  "contracts": [ ... ],
  "pagination": {
    "limit": 10,
    "has_more": true,
    "next_cursor": "con_a1b2c3d4"
  }
}
```

When `has_more` is `true`, pass the `next_cursor` value as the `after` parameter to fetch the next page. When there are no more pages, `next_cursor` is `null`.

**Example flow:**

1. `GET /v1/transactions?limit=10` — returns records 1–10, `"next_cursor": "txn_abc123"`
2. `GET /v1/transactions?limit=10&after=txn_abc123` — returns records 11–20, `"next_cursor": "txn_xyz789"`
3. `GET /v1/transactions?limit=10&after=txn_xyz789` — returns records 21–25, `"has_more": false`, `"next_cursor": null`

The collection key in the response mirrors the resource name (e.g., `"contracts"`, `"transactions"`, `"nominations"`, `"customers"`).

<h3 id="timestamps">
  Timestamps
</h3>

All timestamps are ISO 8601 in UTC:

```
2025-07-15T14:30:00Z
```

<h3 id="delivery-periods">
  Delivery Periods
</h3>

Energy delivery uses the standard **PTU (Programme Time Unit)** convention with 15-minute intervals:

```json theme={null}
{
  "delivery_date": "2025-07-15",
  "period_from": "2025-07-15T14:00:00Z",
  "period_to": "2025-07-15T14:15:00Z"
}
```

Each delivery day typically has 96 quarter-hour slots (numbered 1–96). On DST transition days, this may be 92 or 100 slots. Slot-based filtering is available on transaction and nomination endpoints via the `slot_number_from` and `slot_number_to` parameters.

<h3 id="error-responses">
  Error Responses
</h3>

All errors follow [RFC 9457 — Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457) and are returned with `Content-Type: application/problem+json`:

```json theme={null}
{
  "type": "https://brp.otark.team/errors/balance_group_tso_not_enabled",
  "title": "Balance Group TSO Not Enabled",
  "status": 400,
  "detail": "The requested TSO is not enabled for this balance group.",
  "instance": "/v1/customers/cust_r8s9t0u1"
}
```

Validation errors include a field-level `errors` array:

```json theme={null}
{
  "type": "https://brp.otark.team/errors/validation",
  "title": "Validation Failed",
  "status": 400,
  "instance": "/v1/customers/cust_r8s9t0u1",
  "errors": [
    {
      "field": "balance_group.tso",
      "code": "invalid_enum_value",
      "message": "Invalid enum value. Expected 'DE_AMPRION' | 'DE_TENNET' | 'DE_TRANSNET_BW' | 'DE_50HERTZ'"
    }
  ]
}
```

Field-level error codes: `unknown_field`, `read_only_field`, `required`, `invalid_type`, `invalid_enum_value`, `invalid_format`, `invalid_literal`, `value_too_small`, `value_too_large`, `validation_failed`.

Standard HTTP status codes are used:

| Code  | Description                                                   |
| ----- | ------------------------------------------------------------- |
| `400` | Bad request — validation error or business rule violation     |
| `401` | Unauthorized — missing or invalid API key                     |
| `403` | Forbidden — API key lacks required scopes                     |
| `404` | Not found — resource does not exist or caller has no access   |
| `409` | Conflict — operation cannot be completed in the current state |
| `429` | Too many requests — rate limit exceeded                       |
| `500` | Internal server error                                         |

<h3 id="rate-limiting">
  Rate Limiting
</h3>

API requests are rate-limited to **300 requests per 60-second window**. Every response includes the following headers:

| Header                  | Example | Description                              |
| ----------------------- | ------- | ---------------------------------------- |
| `x-ratelimit-limit`     | `300`   | Maximum requests allowed per window      |
| `x-ratelimit-remaining` | `299`   | Remaining requests in the current window |
| `x-ratelimit-reset`     | `60`    | Seconds until the window resets          |

When the limit is exceeded, the API returns `429 Too Many Requests`.
