Admin Endpoints
Endpoints available to the Admin role only (role JWT with role = "admin" required).
Create BD Account
POST /api/v1/broker/admin/bd
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Request Body
{
"username": "alice_bd",
"display_name": "Alice",
"initial_password": "s3cur3pass"
}
| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Must be unique |
display_name | string | No | |
initial_password | string | Yes | Plaintext — bcrypt-hashed server-side |
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "alice_bd",
"display_name": "Alice",
"role": "bd",
"status": "active"
}
Errors
| HTTP | Description |
|---|---|
| 400 | Username already exists |
List BD Accounts
GET /api/v1/broker/admin/bds
Authorization: Bearer <admin_jwt>
Returns array of BD account objects (same schema as Create BD Account response), ordered by created_at DESC.
Edit BD Account
Update a BD's display_name and/or status.
PUT /api/v1/broker/admin/bd/:id
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | BD account ID |
Request Body
{
"display_name": "Alice (updated)",
"status": "disabled"
}
| Field | Type | Required | Description |
|---|---|---|---|
display_name | string | No | New display name |
status | string | No | "active" or "disabled" |
Response
{ "id": "550e8400-..." }
Admin Dashboard
Global platform summary.
GET /api/v1/broker/admin/dashboard
Authorization: Bearer <admin_jwt>
Response
{
"bd_count": 5,
"kol_count": 120,
"total_fee": "50000.00",
"total_nominal_rebate": "35000.00",
"total_kol_rebate": "30000.00",
"platform_net_retention": "5000.00"
}
| Field | Type | Description |
|---|---|---|
bd_count | int | Active BD accounts |
kol_count | int | Active KOLs |
total_fee | decimal | Sum of all fee_amount across all rebate records |
total_nominal_rebate | decimal | Sum of gross rebates owed |
total_kol_rebate | decimal | Sum of net KOL rebates paid |
platform_net_retention | decimal | total_nominal_rebate − total_kol_rebate |
Admin KOL List
GET /api/v1/broker/admin/kols[?bd_id=<uuid>]
Authorization: Bearer <admin_jwt>
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
bd_id | string (UUID) | No | Filter by BD. Returns up to 200 KOLs if omitted. |
Response
[
{
"broker_id": "550e8400-...",
"wallet_address": "0xabc...",
"nickname": "Alice",
"bd_owner_id": "bd-uuid-...",
"level": 1,
"rebate_rate": "0.70",
"parent_broker": null,
"invitee_count": 25,
"status": "active"
}
]
| Field | Type | Description |
|---|---|---|
broker_id | string (UUID) | |
wallet_address | string | |
nickname | string | null | |
bd_owner_id | string (UUID) | |
level | int | null | Tier level. null for sub-KOLs. |
rebate_rate | string (decimal) | |
parent_broker | string | null | Parent KOL's wallet address (only for sub-KOLs) |
invitee_count | int | Count of bound downlines |
status | string | "active" or "frozen" |
Adjust KOL
Update a KOL's level, rebate_rate, and/or status. Fields are updated individually if present.
Sub-KOLs (those with
parent_broker_idset) cannot have theirlevelorrebate_rateadjusted — their rate is fixed by the parent's invite code. Onlystatuscan be updated for Sub-KOLs.
PUT /api/v1/broker/admin/kol/:id
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Broker ID |
Request Body (all fields optional)
{
"level": 2,
"rebate_rate": 0.75,
"status": "frozen"
}
| Field | Type | Description |
|---|---|---|
level | int | New tier level (KOLs only) |
rebate_rate | float | New rebate rate (KOLs only) |
status | string | "active" or "frozen" |
Response
{ "broker_id": "550e8400-...", "updated": true }
Errors
| HTTP | Description |
|---|---|
| 400 | Cannot adjust level/rebate_rate for sub-KOLs |
Set KOL Tier
Set the rebate tier for a KOL (not Sub-KOL) by selecting a pre-configured tier. The rebate_rate is updated to match the tier's configured value.
Sub-KOLs (those with
parent_broker_idset) cannot use this endpoint — their rate is fixed by the parent's invite code.
PUT /api/v1/broker/admin/kol/:id/tier
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Broker ID |
Request Body
{
"tier_level": 2
}
| Field | Type | Required | Description |
|---|---|---|---|
tier_level | int | Yes | Must match a level defined in tier_thresholds config |
Response
{
"broker_id": "550e8400-...",
"tier_level": 2,
"rebate_rate": "0.75",
"label": "Gold"
}
Errors
| HTTP | Description |
|---|---|
| 400 | Cannot set tier for sub-KOLs |
| 400 | tier_level does not exist in configuration |
| 500 | tier_thresholds not configured |
Reassign KOL
Move a KOL to a different BD. Audit log entry is created.
PUT /api/v1/broker/admin/kol/:id/reassign
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Request Body
{
"new_owner": "bd-uuid-...",
"reason": "BD left the company"
}
| Field | Type | Required | Description |
|---|---|---|---|
new_owner | string | Yes | BD UUID, or "__company__" to remove BD affiliation |
reason | string | No | Audit note |
Response
{
"broker_id": "550e8400-...",
"new_bd_id": "bd-uuid-..."
}
Bulk Reassign KOLs
Transfer all KOLs from a given BD to another BD (or company). Optionally disable the source BD.
POST /api/v1/broker/admin/bd/:id/bulk-reassign
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Source BD ID |
Request Body
{
"new_owner": "target-bd-uuid",
"disable_bd": true,
"reason": "BD resigned"
}
| Field | Type | Required | Description |
|---|---|---|---|
new_owner | string | Yes | Target BD UUID or "__company__" |
disable_bd | bool | No | If true, sets source BD status = 'disabled'. Default false. |
reason | string | No | Audit note |
Response
{
"moved_kol_count": 12,
"new_owner": "target-bd-uuid",
"bd_disabled": true
}
Trigger Settlement
Manually trigger the daily rebate settlement for a specific date (T+0). Idempotent: re-running for the same period recalculates from pre_settlement records.
POST /api/v1/broker/admin/rebate/calculate
Authorization: Bearer <admin_jwt>
Content-Type: application/json
Request Body
{
"period": "2026-05-28",
"mode": "daily"
}
| Field | Type | Required | Description |
|---|---|---|---|
period | string | Yes | Date in YYYY-MM-DD format |
mode | string | No | Reserved — ignored currently |
Response
{
"period": "2026-05-28",
"total_brokers": 120,
"total_records": 3840,
"total_nominal": "35000.00",
"total_customer_rebate": "7000.00",
"total_share": "3500.00",
"total_kol_net": "24500.00"
}
| Field | Type | Description |
|---|---|---|
period | string | Settlement date |
total_brokers | int | KOLs with at least one record |
total_records | int | Rebate records created |
total_nominal | decimal | Sum of gross rebates |
total_customer_rebate | decimal | Sum returned to customers |
total_share | decimal | Sum shared to parent KOLs |
total_kol_net | decimal | Sum net KOL rebates |
Errors
| HTTP | Description |
|---|---|
| 400 | Invalid period format (not YYYY-MM-DD) |
Payout List
Paginated list of rebate records for payment processing.
GET /api/v1/broker/admin/rebate/payout-list
Authorization: Bearer <admin_jwt>
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
period | string | No | Filter by settlement date (YYYY-MM-DD). All periods if omitted. |
status | string | No | "pending" (default), "paid", or "all" |
page | int | No | Page number, minimum 1 (default 1) |
per_page | int | No | Records per page, max 500 (default 100) |
Response
{
"total": 3840,
"page": 1,
"per_page": 100,
"records": [
{
"id": "record-uuid-...",
"broker_id": "broker-uuid-...",
"downline_wallet": "0xabc...",
"period": "2026-05-28",
"fee_amount": "10.00",
"kol_rebate_rate": "0.70",
"share_ratio": "0.10",
"nominal_rebate": "7.00",
"share_amount": "0.70",
"kol_net_rebate": "5.25",
"payment_status": "pending",
"payment_tx_hash": null
}
]
}