OAuth — API reference
The person’s side of AI-agent connections (OAuth 2.1). An agent starts at
GET /oauth/authorize on this host (metadata: /.well-known/oauth-authorization-server);
the dashboard’s consent page reads the request, the person chooses permissions, spend
limits and expiry, and connected agents are listed, limited or revoked here.
| Method | Path | Summary |
|---|---|---|
GET | /v1/oauth/requests/{requestId} | An agent’s authorization request, for the consent page |
POST | /v1/oauth/requests/{requestId}/decision | Approve or deny an agent’s authorization request |
GET | /v1/oauth/grants | Connected agents |
PATCH | /v1/oauth/grants/{grantId} | Change a connected agent’s limits or expiry |
DELETE | /v1/oauth/grants/{grantId} | Disconnect an agent |
Base URL https://api.tenergy.me/v1, or https://api-nile.tenergy.me/v1 on Nile (Environments). Every request below is signed as in Authentication unless its Auth line says otherwise.
An agent’s authorization request, for the consent page
GET /v1/oauth/requests/{requestId} · getOAuthRequest
Auth: Dashboard session cookie + X-CSRF-Token.
What an AI agent asked for through GET /oauth/authorize: the client (name, host, where
its metadata came from), the requested permissions, the resource the token is for, and the
defaults the page pre-fills. api_keys.manage and webhooks.manage are opt-in
(opt_in: true, unchecked). Live for ten minutes and until decided. Dashboard session only.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
requestId | path | string | yes |
Responses
| Status | Meaning |
|---|---|
200 | OK |
401 | Missing, malformed or rejected credentials. |
404 | 3029 oauth_request_not_found: unknown, decided, or expired. |
Response fields (OAuthRequest)
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
expires_at | string (date-time) | yes | |
client | object | yes | |
client.client_id | string | yes | A registered id, or the URL of the client’s metadata document. |
client.name | string | yes | |
client.host | string | yes | |
client.source | enum: dcr, cimd | yes | |
client.client_uri | string | null | yes | |
client.logo_uri | string | null | yes | |
redirect_uri | string | yes | |
resource | string | yes | The API or MCP URL the token will be for. |
scopes | array of object | yes | |
scopes[].scope | enum: prices.read, balance.read, balance.topup_address, orders.read, orders.create, orders.reclaim, subscriptions.read, api_keys.manage, webhooks.manage | yes | A permission an agent may be granted. The first seven are the API key scopes of the same name; api_keys.manage (list, create, revoke API keys) and webhooks.manage (read and change webhook endpoints) are opt-in. Withdrawals, members and sign-in methods are never grantable. |
scopes[].opt_in | boolean | yes | |
scopes[].checked | boolean | yes | Pre-checked on the consent page. |
defaults | object | yes | |
defaults.spend_limit_day_sun | integer | yes | |
defaults.spend_limit_month_sun | integer | yes | |
defaults.expires_in_days | integer | yes | |
step_up | enum: off, email, telegram, wallet | yes | The person’s 2-step channel. |
Approve or deny an agent’s authorization request
POST /v1/oauth/requests/{requestId}/decision · decideOAuthRequest
Auth: Dashboard session cookie + X-CSRF-Token.
approve: true creates the grant with the chosen scopes (a subset of the requested ones)
and a one-time code, and answers the client URL to send the browser to
(code, state, iss). approve: false answers the client URL with
error=access_denied. Granting orders.create needs both spend limits (omitted = 100 TRX
a day and 1,000 TRX a month; null is refused). expires_in_days omitted = 30, null =
no expiry. With 2-step on, a grant holding orders.create, api_keys.manage or
webhooks.manage answers 1020 step_up_required first. Ordering and managing keys or
webhooks need the editor role. Dashboard session only.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
requestId | path | string | yes | |
X-Step-Up | header | string | A 2-step approval: details.step_up_id of a 1020 step_up_required answer, approved with POST /v1/step-up/{id}/approve. Sent on the repeat of the identical request; used once. Only a dashboard session whose person switched 2-step on is ever asked for it. |
Request body
JSON (OAuthDecisionRequest), required.
| Field | Type | Required | Description |
|---|---|---|---|
approve | boolean | yes | |
scopes | array of enum: prices.read, balance.read, balance.topup_address, orders.read, orders.create, orders.reclaim, subscriptions.read, api_keys.manage, webhooks.manage | Required when approving; a subset of the requested scopes. | |
spend_limit_day_sun | integer | null | ||
spend_limit_month_sun | integer | null | ||
expires_in_days | integer | null |
Responses
| Status | Meaning |
|---|---|
200 | Decided; send the browser to redirect_to. |
400 | Malformed request — bad JSON, unknown field, wrong type. |
401 | Missing, malformed or rejected credentials. |
403 | 1020 step_up_required, 1021 step_up_invalid, 1005 insufficient_scope (role), 1014 csrf_token_invalid. |
404 | 3029 oauth_request_not_found. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
redirect_to | string (uri) | yes |
Connected agents
GET /v1/oauth/grants · listOAuthGrants
Auth: Dashboard session cookie + X-CSRF-Token.
The account’s live agent grants (not revoked, not expired), newest first. Dashboard session only.
Responses
| Status | Meaning |
|---|---|
200 | OK |
401 | Missing, malformed or rejected credentials. |
Response fields
| Field | Type | Required | Description |
|---|---|---|---|
data | array of object (OAuthGrant) | yes | |
data[].id | string | yes | |
data[].client_id | string | yes | |
data[].client_name | string | yes | |
data[].client_host | string | yes | |
data[].resource | string | yes | |
data[].scopes | array of enum: prices.read, balance.read, balance.topup_address, orders.read, orders.create, orders.reclaim, subscriptions.read, api_keys.manage, webhooks.manage | yes | |
data[].spend_limit_day_sun | integer | null | yes | |
data[].spend_limit_month_sun | integer | null | yes | |
data[].expires_at | string (date-time) | null | yes | |
data[].created_at | string (date-time) | yes | |
data[].last_used_at | string (date-time) | null | yes | |
data[].last_ip | string | null | yes | |
data[].user_id | string | yes | The member who connected the agent. |
Change a connected agent’s limits or expiry
PATCH /v1/oauth/grants/{grantId} · updateOAuthGrant
Auth: Dashboard session cookie + X-CSRF-Token.
Lowering a limit or shortening the expiry applies at once; raising a limit, extending the
expiry or removing it needs a step-up when 2-step is on. Spend limits exist only on a grant
holding orders.create and cannot be removed. The person who connected the agent or the
account owner. Dashboard session only.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grantId | path | string | yes | |
X-Step-Up | header | string | A 2-step approval: details.step_up_id of a 1020 step_up_required answer, approved with POST /v1/step-up/{id}/approve. Sent on the repeat of the identical request; used once. Only a dashboard session whose person switched 2-step on is ever asked for it. |
Request body
JSON (OAuthGrantPatch), required.
| Field | Type | Required | Description |
|---|---|---|---|
spend_limit_day_sun | integer | ||
spend_limit_month_sun | integer | ||
expires_in_days | integer | null | From now; null = no expiry. |
Responses
| Status | Meaning |
|---|---|
200 | Saved. |
400 | Malformed request — bad JSON, unknown field, wrong type. |
401 | Missing, malformed or rejected credentials. |
403 | 1020 step_up_required, 1021 step_up_invalid, 1005 insufficient_scope, 1014 csrf_token_invalid. |
404 | 3030 oauth_grant_not_found. |
422 | 2002 empty_patch. |
Response fields (OAuthGrant)
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
client_id | string | yes | |
client_name | string | yes | |
client_host | string | yes | |
resource | string | yes | |
scopes | array of enum: prices.read, balance.read, balance.topup_address, orders.read, orders.create, orders.reclaim, subscriptions.read, api_keys.manage, webhooks.manage | yes | |
spend_limit_day_sun | integer | null | yes | |
spend_limit_month_sun | integer | null | yes | |
expires_at | string (date-time) | null | yes | |
created_at | string (date-time) | yes | |
last_used_at | string (date-time) | null | yes | |
last_ip | string | null | yes | |
user_id | string | yes | The member who connected the agent. |
Disconnect an agent
DELETE /v1/oauth/grants/{grantId} · revokeOAuthGrant
Auth: Dashboard session cookie + X-CSRF-Token.
Revokes the grant and every token it issued, at once. Dashboard session only.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
grantId | path | string | yes |
Responses
| Status | Meaning |
|---|---|
204 | Revoked. |
401 | Missing, malformed or rejected credentials. |
403 | 1005 insufficient_scope (not yours and not the owner), 1014 csrf_token_invalid. |
404 | 3030 oauth_grant_not_found. |