# Admin and Risk Limit Management

## Generate API auth token

<mark style="color:green;">`POST`</mark> `/api/reset_auth_token/`

Delete old token, generate and return new token.

{% tabs %}
{% tab title="500: Internal Server Error Unknown server error" %}

```json
{
    "error": "Internal server error"
}
```

{% endtab %}

{% tab title="200: OK Success" %}

```json
{
    "new_token": "4b933af81699070ae624ed4651eea343910108ec"
}
```

{% endtab %}

{% tab title="422: Unprocessable Entity Unexpected failure to persist changes" %}

```json
{
    "error": "Error message."
}
```

{% endtab %}
{% endtabs %}

## Risk Limits

These endpoints allow administrators to programmatically manage trading restrictions (pair blocks and notional limits). All endpoints require admin privileges - the authenticated user must be `is_staff` or `is_superuser`.

All endpoints require the `Authorization: Token <API_KEY>` header. Write operations also require `Content-Type: application/json`.

If your organization has the **approval workflow** enabled (`REQUIRE_TRADING_LIMIT_APPROVAL`), create/edit/delete operations will not apply immediately. Instead, they create pending change requests that must be approved by a different admin via the review endpoint.

***

### Approval workflow

If the approval workflow is enabled, restriction changes require approval from a **different** admin user before taking effect.

This means programmatic automation requires **two API tokens** belonging to two different staff/superuser accounts:

**Step 1 - Request a change (Token A)**

Submit a create, edit, or delete call. The restriction is not yet active. You receive a `202 Accepted` response with a `request_id`.

```
POST /api/admin/trading_restrictions
Authorization: Token <TOKEN_A>
Content-Type: application/json

{
    "restriction_type": "PAIR_BLOCK",
    "pair": "BTC-USDT",
    "venue": "binance",
    "reason": "Trading halt"
}
```

```json
{
    "request_created": true,
    "request_id": "b2c3d4e5-6789-01bc-defg-2345678901bc",
    "message": "Restriction submitted for approval"
}
```

**Step 2 - Approve the change (Token B, different user)**

A second admin reviews and approves the pending request. The restriction is now applied.

```
POST /api/admin/trading_restriction_change_requests/b2c3d4e5-6789-01bc-defg-2345678901bc/review
Authorization: Token <TOKEN_B>
Content-Type: application/json

{
    "action": "approve"
}
```

```json
{
    "message": "Change request approved and applied",
    "request_id": "b2c3d4e5-6789-01bc-defg-2345678901bc"
}
```

> **Key rules:**
>
> * A user **cannot approve their own request** - the API returns `400` if attempted.
> * A user **can reject (withdraw) their own request** - the pending request is deleted.
> * If approval is **not enabled**, create/edit/delete calls apply immediately and return `200`/`201` as normal.

***

### Get trading restrictions

`GET` `/api/admin/trading_restrictions`

Returns all active trading restrictions, with optional filtering.

**Query Parameters**

| Name               | Type   | Description                                          |
| ------------------ | ------ | ---------------------------------------------------- |
| `restriction_type` | string | Filter by type: `PAIR_BLOCK` or `MAX_ORDER_NOTIONAL` |
| `pair`             | string | Filter by pair (e.g., `BTC-USDT`). Case-insensitive. |
| `venue`            | string | Filter by venue (e.g., `binance`). Case-insensitive. |

**200: OK**

```json
{
    "restrictions": [
        {
            "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
            "restriction_type": "MAX_ORDER_NOTIONAL",
            "pair": "BTC-USDT",
            "venue": null,
            "user_id_scope": null,
            "user_scope_username": null,
            "account_id_scope": null,
            "account_name": null,
            "value": "50000.00000000",
            "metadata": null,
            "reason": "Risk limit for BTC",
            "is_active": true,
            "pending_request": null,
            "created_by": "admin",
            "created_by_id": 1,
            "created_at": "2026-01-15T10:30:00Z",
            "updated_by": null,
            "updated_at": null
        }
    ],
    "count": 1,
    "requires_approval": false
}
```

**403: Forbidden**

```json
{
    "error": "You are not authorized to perform this action"
}
```

***

### Create trading restriction

`POST` `/api/admin/trading_restrictions`

Create a new trading restriction. If the approval workflow is enabled, this creates a pending change request instead (HTTP 202).

**Request Body**

| Name               | Type          | Required    | Description                                                                                                    |
| ------------------ | ------------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
| `restriction_type` | string        | Yes         | `PAIR_BLOCK` or `MAX_ORDER_NOTIONAL`                                                                           |
| `pair`             | string        | Conditional | Trading pair (e.g., `BTC-USDT`) or base asset (e.g., `BTC`). Required for `PAIR_BLOCK`. Omit for global scope. |
| `venue`            | string        | No          | Exchange name (e.g., `binance`, `okx`). Omit to apply across all venues.                                       |
| `user_id_scope`    | integer       | No          | User ID to scope restriction to a specific user. Omit to apply to all users.                                   |
| `account_id_scope` | string (UUID) | No          | Account UUID to scope restriction to a specific account. Omit to apply to all accounts.                        |
| `value`            | decimal       | Conditional | Maximum notional value. Required and must be positive for `MAX_ORDER_NOTIONAL`. Ignored for `PAIR_BLOCK`.      |
| `reason`           | string        | No          | Human-readable explanation for the restriction.                                                                |
| `metadata`         | object        | No          | Arbitrary JSON object for additional context.                                                                  |

**Pair matching behavior:** A full pair like `BTC-USDT` matches that exact pair. A base asset like `BTC` (no hyphen) matches any pair where the base asset is BTC (e.g., `BTC-USDT`, `BTC-USDC`). Omitting `pair` creates a global restriction across all pairs.

**201: Created** - Restriction applied immediately (approval workflow disabled)

```json
{
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "restriction_type": "PAIR_BLOCK",
    "pair": "BTC-USDT",
    "venue": "binance",
    "user_id_scope": null,
    "user_scope_username": null,
    "account_id_scope": null,
    "account_name": null,
    "value": null,
    "metadata": null,
    "reason": "Trading halt on BTC-USDT",
    "is_active": true,
    "pending_request": null,
    "created_by": "admin",
    "created_by_id": 1,
    "created_at": "2026-01-15T10:30:00Z",
    "updated_by": null,
    "updated_at": null
}
```

**202: Accepted** - Submitted for approval (approval workflow enabled)

```json
{
    "request_created": true,
    "request_id": "b2c3d4e5-6789-01bc-defg-2345678901bc",
    "message": "Restriction submitted for approval"
}
```

**400: Bad Request** - Validation error

```json
{
    "error": "restriction_type must be one of: ['PAIR_BLOCK', 'MAX_ORDER_NOTIONAL']"
}
```

```json
{
    "error": "pair is required for PAIR_BLOCK restrictions"
}
```

```json
{
    "error": "value is required for MAX_ORDER_NOTIONAL restrictions"
}
```

```json
{
    "error": "value must be a positive number"
}
```

**409: Conflict** - Duplicate restriction

```json
{
    "error": "An active restriction with the same scope already exists",
    "existing_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
```

**403: Forbidden**

```json
{
    "error": "You are not authorized to perform this action"
}
```

***

### Update trading restriction

`PATCH` `/api/admin/trading_restrictions/{id}`

Update an existing restriction's value, reason, or metadata. If the approval workflow is enabled, this creates a pending edit request instead (HTTP 202).

**Path Parameters**

| Name | Type | Description        |
| ---- | ---- | ------------------ |
| `id` | UUID | The restriction ID |

**Request Body**

At least one field must be provided.

| Name       | Type    | Description                                       |
| ---------- | ------- | ------------------------------------------------- |
| `value`    | decimal | Updated maximum notional value. Must be positive. |
| `reason`   | string  | Updated reason.                                   |
| `metadata` | object  | Updated metadata.                                 |

**200: OK** - Restriction updated immediately (approval workflow disabled)

```json
{
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
    "restriction_type": "MAX_ORDER_NOTIONAL",
    "pair": "BTC-USDT",
    "venue": null,
    "value": "75000.00000000",
    "reason": "Increased limit",
    "is_active": true,
    "updated_by": "admin",
    "updated_at": "2026-01-16T14:00:00Z"
}
```

**202: Accepted** - Submitted for approval (approval workflow enabled)

```json
{
    "request_created": true,
    "request_id": "c3d4e5f6-7890-12cd-efgh-3456789012cd",
    "message": "Edit submitted for approval"
}
```

**404: Not Found**

```json
{
    "error": "Restriction not found"
}
```

**409: Conflict** - Pending edit exists

```json
{
    "error": "A pending edit request already exists. Withdraw it first.",
    "pending_request_id": "c3d4e5f6-7890-12cd-efgh-3456789012cd"
}
```

***

### Delete trading restriction

`DELETE` `/api/admin/trading_restrictions/{id}`

Soft-delete (deactivate) a trading restriction. If the approval workflow is enabled, this creates a pending delete request instead (HTTP 202).

**Path Parameters**

| Name | Type | Description        |
| ---- | ---- | ------------------ |
| `id` | UUID | The restriction ID |

**200: OK** - Restriction deactivated

```json
{
    "message": "Restriction deactivated",
    "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
```

**202: Accepted** - Submitted for approval (approval workflow enabled)

```json
{
    "request_created": true,
    "request_id": "d4e5f6g7-8901-23de-fghi-4567890123de",
    "message": "Delete submitted for approval"
}
```

**404: Not Found**

```json
{
    "error": "Restriction not found"
}
```

**409: Conflict** - Pending delete exists

```json
{
    "error": "A pending delete request already exists",
    "pending_request_id": "d4e5f6g7-8901-23de-fghi-4567890123de"
}
```

***

### Get change requests

`GET` `/api/admin/trading_restriction_change_requests`

List pending, approved, or rejected change requests. Only relevant when the approval workflow is enabled.

**Query Parameters**

| Name     | Type   | Description                                                               |
| -------- | ------ | ------------------------------------------------------------------------- |
| `status` | string | Filter by status: `PENDING`, `APPROVED`, or `REJECTED`. Case-insensitive. |

**200: OK**

```json
{
    "requests": [
        {
            "id": "b2c3d4e5-6789-01bc-defg-2345678901bc",
            "action": "create",
            "restriction_id": null,
            "payload": {
                "restriction_type": "PAIR_BLOCK",
                "pair": "BTC-USDT",
                "venue": "binance",
                "user_id_scope": null,
                "account_id_scope": null,
                "value": null,
                "metadata": null,
                "reason": "Trading halt"
            },
            "status": "PENDING",
            "requested_by": "admin",
            "requested_by_id": 1,
            "requested_at": "2026-01-15T10:30:00Z",
            "reviewed_by": null,
            "reviewed_by_id": null,
            "reviewed_at": null,
            "review_notes": null
        }
    ],
    "count": 1
}
```

**Payload contents by action type:**

| Action   | Payload contains                                                                                                                 |
| -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `create` | Full restriction fields: `restriction_type`, `pair`, `venue`, `user_id_scope`, `account_id_scope`, `value`, `metadata`, `reason` |
| `edit`   | Only changed fields: `value`, `reason`, `metadata`                                                                               |
| `delete` | Empty object `{}`                                                                                                                |

**403: Forbidden**

```json
{
    "error": "You are not authorized to perform this action"
}
```

***

### Review change request

`POST` `/api/admin/trading_restriction_change_requests/{id}/review`

Approve or reject a pending change request. Approval executes the restriction change. A user can reject (withdraw) their own request, but cannot approve their own request.

**Path Parameters**

| Name | Type | Description           |
| ---- | ---- | --------------------- |
| `id` | UUID | The change request ID |

**Request Body**

| Name     | Type   | Required | Description            |
| -------- | ------ | -------- | ---------------------- |
| `action` | string | Yes      | `approve` or `reject`  |
| `notes`  | string | No       | Optional review notes. |

**200: OK** - Approved

```json
{
    "message": "Change request approved and applied",
    "request_id": "b2c3d4e5-6789-01bc-defg-2345678901bc",
    "restriction": {
        "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
        "restriction_type": "PAIR_BLOCK",
        "pair": "BTC-USDT",
        "venue": "binance",
        "is_active": true
    }
}
```

**200: OK** - Rejected

```json
{
    "message": "Change request rejected",
    "request_id": "b2c3d4e5-6789-01bc-defg-2345678901bc"
}
```

**200: OK** - Withdrawn (self-rejection)

```json
{
    "message": "Change request withdrawn",
    "request_id": "b2c3d4e5-6789-01bc-defg-2345678901bc"
}
```

**400: Bad Request**

```json
{
    "error": "action must be 'approve' or 'reject'"
}
```

```json
{
    "error": "Cannot approve your own request"
}
```

```json
{
    "error": "Request is already APPROVED"
}
```

**404: Not Found**

```json
{
    "error": "Change request not found"
}
```

***

### Useful endpoints for scoping restrictions

If your automation needs user or account IDs to scope restrictions:

| Endpoint                   | Purpose                                  |
| -------------------------- | ---------------------------------------- |
| `GET /api/users/`          | Get user IDs for `user_id_scope`         |
| `GET /api/admin/accounts/` | Get account UUIDs for `account_id_scope` |
