Authentication
Every request must include the x-api-key header. Create and manage keys in Console under Settings → API Keys.
Authentication errors return 401 Unauthorized with { "error": "Unauthorized", "message": "Invalid API key" }.
A key acts in the account it was created in, your personal account or a team, with your role there, and can be limited to one project. See Organizations and projects.
GET /v1/deployments HTTP/1.1
Host: console-api.akash.network
x-api-key: YOUR_API_KEY
# 401 response when the key is missing or invalid:
{ "error": "Unauthorized", "message": "Invalid API key" }GET /v1/deployments HTTP/1.1
Host: console-api.akash.network
x-api-key: YOUR_API_KEY
# 401 response when the key is missing or invalid:
{ "error": "Unauthorized", "message": "Invalid API key" }Response envelope
Every JSON response is wrapped in a top-level data field. For list endpoints, data carries both the array and a pagination object.
# Single resource:
{ "data": { "...": "..." } }
# List resource:
{ "data": { "deployments": [ ... ], "pagination": { ... } } }# Single resource:
{ "data": { "...": "..." } }
# List resource:
{ "data": { "deployments": [ ... ], "pagination": { ... } } }Errors
The API uses standard HTTP status codes. All error responses share the same JSON shape.
| HTTP | Code string | Description |
|---|---|---|
| 400 | BadRequest | The request body or query parameters are invalid. Check message for details. |
| 401 | Unauthorized | x-api-key is missing, expired, or invalid. |
| 403 | Forbidden | Your role, the key's project, or a project budget does not allow the request. |
| 404 | NotFound | The resource (dseq) does not exist or is out of the caller's reach. |
| 429 | TooManyRequests | Request rate exceeded. Wait before retrying. |
| 500 | InternalServerError | Unexpected server error. Retry with exponential backoff. |
code names the precise reason, such as project_forbidden or project_budget_exceeded. The organization and project codes are listed under Organizations and projects.
# Error response schema:
{ "error": "string", "message": "string", "code": "string", "type": "string" }# Error response schema:
{ "error": "string", "message": "string", "code": "string", "type": "string" }API Versioning
Endpoints are prefixed with a version number (/v1/ or /v2/). Versions are independent — upgrading one endpoint version does not affect others.
| Version | Status | Endpoints |
|---|---|---|
| v1 | Stable | Deployments, bids, leases |
| v2 | Stable | Deployment settings (runtime limit) |
Future breaking changes are introduced as a new version prefix; prior versions remain available for a deprecation period announced in the changelog.
Pagination
GET /v1/deployments uses offset-based pagination via skip and limit. The response includes a pagination object with total, skip, limit, and hasMore so you can drive a paging loop without guessing when to stop.
| Parameter | Type | Default | Minimum | Maximum | Description |
|---|---|---|---|---|---|
| skip | integer | 0 | 0 | none | Number of records to skip (offset) |
| limit | integer | 100 | 1 | 100 | Maximum records to return per page |
# Stream every page sequentially:
SKIP=0
LIMIT=100
while :; do
curl -s "https://console-api.akash.network/v1/deployments?skip=$SKIP&limit=$LIMIT" \
-H "x-api-key: $AKASH_API_KEY" > page.json
jq -e '.data.pagination.hasMore' page.json > /dev/null || break
SKIP=$((SKIP + LIMIT))
done# Stream every page sequentially:
SKIP=0
LIMIT=100
while :; do
curl -s "https://console-api.akash.network/v1/deployments?skip=$SKIP&limit=$LIMIT" \
-H "x-api-key: $AKASH_API_KEY" > page.json
jq -e '.data.pagination.hasMore' page.json > /dev/null || break
SKIP=$((SKIP + LIMIT))
done POST /v1/deployments
Create a new deployment from an SDL manifest. Console funds it automatically from your account credits, so the request takes no deposit.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.sdl body string
required
| Deployment manifest in SDL (YAML) format, as a JSON string. May include a params.tee field (cpu/cpu-gpu) to request Confidential Compute |
data.runtimeLimitHours body number | Close the deployment after this many hours of runtime, counted from lease start. Omit for always-on funding |
data.projectId body string (uuid) | Project of the organization to file the deployment in. Omit it to use the only project you can deploy into, otherwise the organization's default project |
Response 201 Created
| Field | Description |
|---|---|
data.dseq string | Deployment sequence ID |
data.manifest string | Rendered manifest. You don't need to keep it: POST /v1/leases sends the provider a manifest built from the SDL Console recorded |
data.signTx.code number | Cosmos tx code (0 = success) |
data.signTx.transactionHash string | Broadcast transaction hash |
data.signTx.rawLog string | Raw chain log |
Request Confidential Compute (TEE) by adding aparams.teefield (cpuorcpu-gpu) to a service in the SDL —cpu-gpurequires GPU resources. See Confidential Compute (TEE).
400with codeproject_requiredmeans no project you can deploy into was found: passdata.projectIdorx-project-id.403with codeproject_budget_exceededmeans the deposit would take the project past its monthly budget, and nothing was created.503with codedeposit_price_unavailablemeans the deposit could not be priced against the project's budget; it is transient, so retry. An unknownprojectIdanswers404.
curl -X POST https://console-api.akash.network/v1/deployments \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "sdl": "version: \"2.0\"\n..." } }'curl -X POST https://console-api.akash.network/v1/deployments \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "sdl": "version: \"2.0\"\n..." } }' GET /v1/bids
List provider bids for a deployment. Poll until bids arrive.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq query string
required
| Deployment sequence ID returned by create deployment |
Response 200 OK
| Field | Description |
|---|---|
data[].bid.id.owner string | Owner address |
data[].bid.id.dseq string | Deployment sequence ID |
data[].bid.id.gseq number | Group sequence |
data[].bid.id.oseq number | Order sequence |
data[].bid.id.provider string | Provider address |
data[].bid.id.bseq number | Bid sequence (chain height) |
data[].bid.state string | Bid state (e.g. open) |
data[].bid.price.denom string | Chain denom (e.g. uact) |
data[].bid.price.amount string | Chain amount in micro-units, per block |
data[].bid.created_at string | Chain height at creation |
data[].bid.resources_offer array | Offered CPU / memory / storage / GPU / endpoints |
data[].escrow_account object | Provider's bid escrow account |
There is no flatbid.idstring — the bid is identified by the composite{owner, dseq, gseq, oseq, provider, bseq}. When creating a lease, copydseq,gseq,oseq, andproviderfrom this object.
While bids are pending, the endpoint returns { "data": [] }. Poll every few seconds. curl "https://console-api.akash.network/v1/bids?dseq=1234567" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/bids?dseq=1234567" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/leases
Accept one or more provider bids. Console creates the leases, then sends each provider the manifest built from the SDL it recorded when the deployment was created, so the request carries only the bids.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
leases body array
required
| One entry per bid to accept |
leases[].dseq body string
required
| Deployment sequence ID |
leases[].gseq body number
required
| Group sequence (from bid.id.gseq) |
leases[].oseq body number
required
| Order sequence (from bid.id.oseq) |
leases[].provider body string
required
| Provider address (from bid.id.provider) |
manifest body string | **Deprecated.** Leave it out: Console builds the manifest from the SDL it recorded |
Response 200 OK
Response is the full deployment object — same shape as GET /v1/deployments/{dseq}.A502with codeprovider_unreachablemeans no lease was created, so pick another bid. With codemanifest_not_deliveredthe lease exists but the provider didn't take the manifest: send the same request again to retry, or close the deployment to stop paying for it.
curl -X POST https://console-api.akash.network/v1/leases \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"leases": [
{ "dseq": "1234567", "gseq": 1, "oseq": 1, "provider": "akash1provider..." }
]
}'curl -X POST https://console-api.akash.network/v1/leases \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"leases": [
{ "dseq": "1234567", "gseq": 1, "oseq": 1, "provider": "akash1provider..." }
]
}' POST /v1/deposit-deployment
Deprecated. Console funds every deployment automatically for as long as your account has credits, so there is nothing for this endpoint to do. It still accepts requests so existing integrations keep working, and will be removed in a future release.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.dseq body string
required
| Deployment sequence ID |
data.deposit body number
required
| Deposit amount in USD. Minimum 0.5. Accepted but no longer needed |
Response 200 OK
Replaced by automatic funding. Add credits to your account instead. See How Funding Works.
curl -X POST https://console-api.akash.network/v1/deposit-deployment \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "dseq": "1234567", "deposit": 0.5 } }'curl -X POST https://console-api.akash.network/v1/deposit-deployment \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "dseq": "1234567", "deposit": 0.5 } }' GET /v1/deployments
List all deployments for the authenticated user, with pagination.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
skip query integer | Offset. Default 0 |
limit query integer | Records per page, from 1 to 100. Default 100 |
state query string | active (default) or closed |
search query string | Case-insensitive match against each deployment's name and dseq |
reverse query string | true lists the newest deployment first. Default false (oldest first) |
projectId query string (uuid) | Only the deployments filed in this project. A project you cannot reach lists nothing |
Response 200 OK
| Field | Description |
|---|---|
data.deployments[] array | One entry per deployment, same shape as GET /v1/deployments/{dseq} minus per-lease status |
data.deployments[].projectId string | null | Project the deployment is filed in |
data.pagination.total number | Total deployments for the user |
data.pagination.skip number | Skip value used |
data.pagination.limit number | Limit value used |
data.pagination.hasMore boolean | True when more pages are available |
curl "https://console-api.akash.network/v1/deployments?skip=0&limit=10" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/deployments?skip=0&limit=10" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/deployments/{dseq}
Retrieve full details for a single deployment by its sequence ID.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence ID |
Response 200 OK
| Field | Description |
|---|---|
data.deployment.id.owner string | Owner address |
data.deployment.id.dseq string | Deployment sequence ID |
data.deployment.state string | Deployment state (active, closed) |
data.deployment.hash string | Manifest hash |
data.deployment.created_at string | Chain height at creation |
data.leases[] array | Active leases (composite id + state, price, created_at, closed_on, status) |
data.escrow_account object | Deployment escrow account with funds[], deposits[], transferred[] (raw chain denoms) |
curl "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY" PATCH /v1/deployments/{dseq}
Change a running deployment in place: a service's image, command, arguments, environment variables, registry credentials, exposed ports or volume mounts, or the deployment's name. Console applies the patch to the SDL it recorded at create, so the request never carries an SDL, and only the services you name change.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence ID |
data.services.<name>.image body string | New image for the service, with an explicit tag |
data.services.<name>.env body object | Merged into the service's env by variable name. null removes a variable |
data.services.<name>.command body array | Replaces the container command |
data.services.<name>.args body array | Replaces the command arguments |
data.services.<name>.credentials body object | Private registry host, username and password. null clears them |
data.services.<name>.expose.<port> body object | Keyed by the container port the SDL declares: port, as, accept (custom domains) and httpOptions |
data.services.<name>.storage.<volume> body object | mount and readOnly only. Sizes are fixed at create |
data.name body string | Renames the deployment |
data.sealedSecrets body string | Compact JWE holding only the secret values this patch replaces, for env values written as ac-secret://NAME |
data.ifManifestVersion body string | Base64 manifest version you expect to be current. Answers 409 if the deployment has moved on |
Response 200 OK
| Field | Description |
|---|---|
data.deployment object | The deployment, as in GET /v1/deployments/{dseq} |
data.leases array | Its leases |
data.name string | Deployment name |
data.manifestVersion string | Base64 version of the manifest now current. Pass it as ifManifestVersion on the next patch |
Compute resources, replica counts, groups and globally exposed ports are fixed at create. A patch that would change them answers422with codedeployment_resources_changed; create a new deployment instead.
404 means Console holds no recorded SDL for this deployment, so there is nothing to patch.409with codedeployment_definition_changedmeans another change landed between this patch reading the deployment and writing it. Reload it and retry.
curl -X PATCH "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"services": {
"web": {
"image": "nginx:1.27.3",
"env": { "LOG_LEVEL": "debug", "OLD_FLAG": null }
}
}
}
}'curl -X PATCH "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"services": {
"web": {
"image": "nginx:1.27.3",
"env": { "LOG_LEVEL": "debug", "OLD_FLAG": null }
}
}
}
}' PUT /v1/deployments/{dseq}
Deprecated. Resubmits the whole SDL. Use PATCH /v1/deployments/{dseq} instead; this endpoint will be removed in a future release.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence ID |
data.sdl body string
required
| Updated SDL in YAML format, passed as a JSON string |
Response 200 OK
Refused with422and codedeployment_resources_changedwhen the SDL changes the groups, compute resources, replica counts or globally exposed ports the deployment was created with.
curl -X PUT "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "sdl": "version: \"2.0\"\n..." } }'curl -X PUT "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "sdl": "version: \"2.0\"\n..." } }' DELETE /v1/deployments/{dseq}
Close a deployment. Whatever it has not yet spent returns to your Console account balance once the chain settles.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence ID to close |
Response 200 OK
curl -X DELETE "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY"curl -X DELETE "https://console-api.akash.network/v1/deployments/1234567" \
-H "x-api-key: $AKASH_API_KEY" GET /v2/deployment-settings/{dseq}
Get the funding settings for a specific deployment, including its runtime limit. Settings are auto-created on first read.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence number |
userId query string | Defaults to authenticated user |
Response 200 OK
| Field | Description |
|---|---|
data.id string (uuid) | Setting record id |
data.userId string | Owning user id |
data.dseq string | Deployment sequence number |
data.autoTopUpEnabled boolean | Always true. Automatic funding cannot be turned off |
data.estimatedTopUpAmount number | Estimated top-up amount per cycle (USD) |
data.topUpFrequencyMs number | Top-up cadence in milliseconds |
data.runtimeLimitHours number \| null | Runtime limit in hours chosen at creation, or null for always-on funding |
data.runtimeEndsAt string \| null | When the runtime limit is reached, anchored at lease start; null until the lease starts or when no limit is set |
data.createdAt string | ISO-8601 creation time |
data.updatedAt string | ISO-8601 last update time |
curl "https://console-api.akash.network/v2/deployment-settings/1234567" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v2/deployment-settings/1234567" \
-H "x-api-key: $AKASH_API_KEY" POST /v2/deployment-settings
Create the settings row for a deployment when it does not yet exist. Automatic funding is on by default and cannot be turned off.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.dseq body string
required
| Deployment sequence number |
data.autoTopUpEnabled body boolean | Defaults to true when omitted. An explicit false is rejected |
data.userId body string (uuid) | Defaults to authenticated user |
Response 201 Created
curl -X POST https://console-api.akash.network/v2/deployment-settings \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "dseq": "1234567", "autoTopUpEnabled": true } }'curl -X POST https://console-api.akash.network/v2/deployment-settings \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "dseq": "1234567", "autoTopUpEnabled": true } }' PATCH /v2/deployment-settings/{dseq}
Update an existing settings row. Use this to set, extend, or remove a deployment's runtime limit.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence number |
userId query string (uuid) | Defaults to authenticated user |
data.autoTopUpEnabled body boolean | An explicit false is rejected |
data.runtimeLimitHours body number \| null | New total runtime limit in hours, counted from lease start. Send null to remove the limit and return the deployment to always-on funding. Lowering a limit is not supported |
Response 200 OK
curl -X PATCH https://console-api.akash.network/v2/deployment-settings/1234567 \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "runtimeLimitHours": 48 } }'curl -X PATCH https://console-api.akash.network/v2/deployment-settings/1234567 \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "data": { "runtimeLimitHours": 48 } }'Organizations and projects
Organizations and projects
Every request runs in one organization, your personal account or a team, and can be limited to one project of it. An API key acts in the organization it was created in, with your role there, and can be limited to one project. See Organizations and Projects through the API for a walkthrough.
| Header | Description |
|---|---|
x-organization-id | Id or slug of the organization. Optional with an API key, which already decides it: naming another organization answers 400 organization_mismatch. |
x-project-id | Limits the request to one project of the organization. A project out of your reach answers 403 project_forbidden. |
Owners and admins reach every project. Members and viewers reach every project or only the ones granted to them, and billing members reach none. Each endpoint below says who may call it.
| HTTP | code | Meaning |
|---|---|---|
| 400 | organization_mismatch | x-organization-id names another organization than the API key's. |
| 403 | organization_forbidden | The caller is not a member of the organization, for example after leaving it. |
| 403 | project_forbidden | x-project-id names a project out of reach or other than the key's, or the deployment is filed in a project the caller cannot change. |
| 400 | project_required | No project the caller can deploy into was named. |
| 403 | project_budget_exceeded | The deposit would take the project past its monthly budget. data.projectIds lists the projects. |
| 403 | project_limit_reached | The organization already has 10 projects, the default one included. data.limit holds the limit. |
| 403 | organization_limit_reached | The caller already has 3 organizations they created, the most one person can have. data.limit holds the limit. |
| 403 | session_required | The action needs a signed-in Console session. |
Reading a project, deployment, budget or grant outside the caller's reach answers 404, the same as one that does not exist.
Creating an organization (POST /v1/organizations), deleting it (DELETE /v1/organizations/{id}), leaving it (DELETE /v1/organizations/{id}/membership) and accepting an invitation (POST /v1/invitations/accept) need a signed-in Console session, so an API key gets 403 session_required. Do those in Console.
# List the deployments of one project
curl "https://console-api.akash.network/v1/deployments" \
-H "x-api-key: $AKASH_API_KEY" \
-H "x-project-id: 7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b"# List the deployments of one project
curl "https://console-api.akash.network/v1/deployments" \
-H "x-api-key: $AKASH_API_KEY" \
-H "x-project-id: 7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" GET /v1/organizations
List the organizations of the caller and their role in each. With an API key, the list holds only the key's organization.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
Response 200 OK
| Field | Description |
|---|---|
data[].id string (uuid) | Organization id |
data[].name string | Organization name |
data[].slug string | Slug, accepted by x-organization-id like the id |
data[].type string | personal or team |
data[].role string | The caller's role: owner, admin, member, billing or viewer |
data[].isActive boolean | Whether this request ran in this organization |
data[].hasPaymentMethod boolean | null | Whether the organization has a card saved. Null for one the request did not run in |
data[].createdAt string | ISO-8601 creation time |
curl "https://console-api.akash.network/v1/organizations" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/organizations" \
-H "x-api-key: $AKASH_API_KEY" PATCH /v1/organizations/{id}
Rename the active team organization. Owners and admins only.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Id of the active organization |
data.name body string
required
| New name, unique among the organizations the caller belongs to |
Response 200 OK
403with codepersonal_organizationfor a personal account.409with codeorganization_name_takenwhen the caller already belongs to an organization with this name.
curl -X PATCH "https://console-api.akash.network/v1/organizations/0b6c3f9e-8f1a-4d2b-9c7e-1a2b3c4d5e6f" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "Acme Platform"
}
}'curl -X PATCH "https://console-api.akash.network/v1/organizations/0b6c3f9e-8f1a-4d2b-9c7e-1a2b3c4d5e6f" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "Acme Platform"
}
}' GET /v1/organization-members
List the members of the active organization. Every member may call it.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
Response 200 OK
| Field | Description |
|---|---|
data[].id string (uuid) | Membership id, used by the member endpoints below |
data[].userId string (uuid) | User id, used to grant project access |
data[].username string | null | Username |
data[].email string | null | Email address |
data[].role string | owner, admin, member, billing or viewer |
data[].projectAccess string | null | all or selected for members and viewers, all for owners and admins, null for billing members |
data[].projectCount number | null | Projects granted to a member or viewer on selected |
data[].createdAt string | When they joined |
curl "https://console-api.akash.network/v1/organization-members" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/organization-members" \
-H "x-api-key: $AKASH_API_KEY" PATCH /v1/organization-members/{id}
Change a member's role, project access and project grants, all together or not at all. Owners and admins; only an owner can change anything about the owner role.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Membership id from GET /v1/organization-members |
data.role body string | owner, admin, member, billing or viewer |
data.projectAccess body string | all or selected. Required when someone becomes a member or viewer from another role |
data.projectGrants body array | [{ projectId, role }] with role viewer, member or admin. Replaces every grant of a member or viewer on selected |
Response 200 OK
Send at least one field. A member or viewer on selected needs at least one grant.400with codeproject_access_requiredwhen someone becomes a member or viewer withoutprojectAccess.403with codeowner_role_restrictedwhen a non-owner touches the owner role.409with codelast_ownerwhen the organization would be left without an owner.
curl -X PATCH "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"role": "member",
"projectAccess": "selected",
"projectGrants": [
{
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"role": "admin"
}
]
}
}'curl -X PATCH "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"role": "member",
"projectAccess": "selected",
"projectGrants": [
{
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"role": "admin"
}
]
}
}' DELETE /v1/organization-members/{id}
Remove a member from the active organization. Their access, and the API keys they created in it, stop working. Owners and admins; only an owner can remove an owner.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Membership id |
Response 204 No Content
409with codelast_ownerwhen the organization would be left without an owner.
curl -X DELETE "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d" \
-H "x-api-key: $AKASH_API_KEY"curl -X DELETE "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/organization-members/{id}/ownership-transfer
Make a member an owner of the active organization and step the calling owner down to admin. Owners only.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Membership id of the new owner |
Response 200 OK
curl -X POST "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d/ownership-transfer" \
-H "x-api-key: $AKASH_API_KEY"curl -X POST "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d/ownership-transfer" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/organization-members/{id}/project-grants
List the projects a member is granted, with the role on each. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Membership id |
Response 200 OK
| Field | Description |
|---|---|
data[].projectId string (uuid) | Granted project |
data[].role string | viewer, member or admin |
curl "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d/project-grants" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/organization-members/5a8b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d/project-grants" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/organization-invitations
List the pending invitations of the active organization. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
Response 200 OK
| Field | Description |
|---|---|
data[].id string (uuid) | Invitation id |
data[].email string | Invited address |
data[].role string | Role the invitation grants |
data[].projectAccess string | all or selected |
data[].projectGrants array | [{ projectId, role }] granted on joining |
data[].invitedBy object | null | { id, username } of the inviter |
data[].expiresAt string | When the link stops working, 7 days after it was sent |
curl "https://console-api.akash.network/v1/organization-invitations" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/organization-invitations" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/organization-invitations
Invite people to the active team by email. Each address gets an email with a link, valid for 7 days, that they accept in Console. Owners and admins; only an owner can invite an owner.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.emails body array<string>
required
| 1 to 20 addresses |
data.role body string
required
| owner, admin, member, billing or viewer |
data.projectAccess body string | all or selected. For a member or viewer, required unless projectGrants is given |
data.projectGrants body array | [{ projectId, role }] for a member or viewer on selected |
Response 201 Created
400with codeproject_access_requiredfor a member or viewer with neitherprojectAccessnor grants.409with codealready_memberwhen an address belongs to a member.403with codeinvitation_limit_reachedwhen the organization has too many pending invitations, and429with codeinvitation_email_limit_reachedwhen too many invitation emails were sent recently.
curl -X POST "https://console-api.akash.network/v1/organization-invitations" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"emails": [
"[email protected]"
],
"role": "member",
"projectAccess": "selected",
"projectGrants": [
{
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"role": "member"
}
]
}
}'curl -X POST "https://console-api.akash.network/v1/organization-invitations" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"emails": [
"[email protected]"
],
"role": "member",
"projectAccess": "selected",
"projectGrants": [
{
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"role": "member"
}
]
}
}' POST /v1/organization-invitations/{id}/resend
Email a pending invitation again, with a new link and a new expiry. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Invitation id |
Response 200 OK
curl -X POST "https://console-api.akash.network/v1/organization-invitations/2f3e4d5c-6b7a-4980-8f1e-2d3c4b5a6978/resend" \
-H "x-api-key: $AKASH_API_KEY"curl -X POST "https://console-api.akash.network/v1/organization-invitations/2f3e4d5c-6b7a-4980-8f1e-2d3c4b5a6978/resend" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/organization-invitations/{id}/link
Issue a new link for a pending invitation, to share it yourself. Every earlier link of the invitation stops working. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Invitation id |
Response 200 OK
| Field | Description |
|---|---|
data.url string | The invitation link |
curl -X POST "https://console-api.akash.network/v1/organization-invitations/2f3e4d5c-6b7a-4980-8f1e-2d3c4b5a6978/link" \
-H "x-api-key: $AKASH_API_KEY"curl -X POST "https://console-api.akash.network/v1/organization-invitations/2f3e4d5c-6b7a-4980-8f1e-2d3c4b5a6978/link" \
-H "x-api-key: $AKASH_API_KEY" DELETE /v1/organization-invitations/{id}
Revoke a pending invitation. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Invitation id |
Response 204 No Content
curl -X DELETE "https://console-api.akash.network/v1/organization-invitations/2f3e4d5c-6b7a-4980-8f1e-2d3c4b5a6978" \
-H "x-api-key: $AKASH_API_KEY"curl -X DELETE "https://console-api.akash.network/v1/organization-invitations/2f3e4d5c-6b7a-4980-8f1e-2d3c4b5a6978" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/projects
List the projects of the active organization the caller can reach, most recently active first.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
Response 200 OK
| Field | Description |
|---|---|
data[].id string (uuid) | Project id, for projectId and x-project-id |
data[].name string | Name, unique within the organization |
data[].slug string | Slug set from the name at creation |
data[].description string | null | Description |
data[].isDefault boolean | Whether it is the organization's default project |
data[].deployments object | null | activeCount and a preview of the newest active deployments. Null when the caller cannot read them |
data[].access.canDeploy boolean | Whether the caller may deploy into the project |
data[].access.canManage boolean | Whether the caller may rename the project and manage its access |
data[].lastActivityAt string | Newest activity the caller may read |
curl "https://console-api.akash.network/v1/projects" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/projects" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/projects
Create a project in the active organization. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.name body string
required
| Unique within the organization, whatever its case |
data.description body string | Optional description |
Response 201 Created
409with codeproject_name_takenwhen another project has this name.403with codeproject_limit_reachedwhen the organization already has 10 projects, the default one included;data.limitholds the limit.
curl -X POST "https://console-api.akash.network/v1/projects" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "checkout-api",
"description": "Payments backend"
}
}'curl -X POST "https://console-api.akash.network/v1/projects" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "checkout-api",
"description": "Payments backend"
}
}' GET /v1/projects/{id}
Get a project of the active organization the caller can reach.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Project id |
Response 200 OK
curl "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY" PATCH /v1/projects/{id}
Rename a project or change its description. Owners, admins and the project's admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Project id |
data.name body string | New name |
data.description body string | null | New description, or null to clear it |
Response 200 OK
curl -X PATCH "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "payments-api"
}
}'curl -X PATCH "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "payments-api"
}
}' DELETE /v1/projects/{id}
Delete a project that holds no open deployment. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Project id |
Response 204 No Content
409with codeproject_is_defaultfor the default project, orproject_not_emptywhile it holds open deployments. Close them or move them first.
curl -X DELETE "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY"curl -X DELETE "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/projects/{id}/members
List who was granted access to a project, and the members and viewers who reach every project.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Project id |
Response 200 OK
| Field | Description |
|---|---|
data[] array | Grants on the project: id (grant id), projectId, userId, username, email, role, createdAt |
membersWithAllProjects[] array | Members and viewers on all with no grant on this project. Owners and admins are not listed |
curl "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b/members" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/projects/7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b/members" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/project-members
Grant a member or viewer of the organization a role on a project. Owners, admins and the project's admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.projectId body string (uuid)
required
| Project id |
data.userId body string (uuid)
required
| userId of a member or viewer, from GET /v1/organization-members |
data.role body string
required
| viewer reads, member also deploys, admin also renames the project and manages its access |
Response 201 Created
409with codealready_granted,implicit_project_access(an owner or admin, who reaches every project) orbilling_role_not_grantable.
curl -X POST "https://console-api.akash.network/v1/project-members" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"userId": "9c1d2e3f-4a5b-4c6d-9e7f-8a9b0c1d2e3f",
"role": "member"
}
}'curl -X POST "https://console-api.akash.network/v1/project-members" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"userId": "9c1d2e3f-4a5b-4c6d-9e7f-8a9b0c1d2e3f",
"role": "member"
}
}' PATCH /v1/project-members/{id}
Change the project role a grant gives. Owners, admins and the project's admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Grant id |
data.role body string
required
| viewer, member or admin |
Response 200 OK
curl -X PATCH "https://console-api.akash.network/v1/project-members/4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"role": "viewer"
}
}'curl -X PATCH "https://console-api.akash.network/v1/project-members/4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"role": "viewer"
}
}' DELETE /v1/project-members/{id}
Revoke a grant, effective from the member's next request. Owners, admins and the project's admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Grant id |
Response 204 No Content
curl -X DELETE "https://console-api.akash.network/v1/project-members/4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8" \
-H "x-api-key: $AKASH_API_KEY"curl -X DELETE "https://console-api.akash.network/v1/project-members/4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/project-budgets
List the project budgets the caller can read, with this month's committed spend. Owners, admins, billing members and the project's admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
projectId query string (uuid) | Only the budget of this project |
Response 200 OK
| Field | Description |
|---|---|
data[].id string (uuid) | Budget id |
data[].projectId string (uuid) | Project id |
data[].monthlyAmountUsd number | Deposits allowed per calendar month (UTC), in USD |
data[].alertThresholdPercent number | Share of the budget at which owners and admins are emailed, once a month |
data[].stopTopUps boolean | Whether top-ups of running deployments also stop at the budget |
data[].currentPeriod.committedUsd number | Deposits recorded this month, the figure new deposits are judged against |
curl "https://console-api.akash.network/v1/project-budgets?projectId=7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/project-budgets?projectId=7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/project-budgets
Set a monthly budget for a project. New deployments that would pass it are refused with project_budget_exceeded; top-ups are refused too when stopTopUps is on. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.projectId body string (uuid)
required
| Project id |
data.monthlyAmountUsd body number
required
| From 1 to 10000000, in whole cents |
data.alertThresholdPercent body integer | From 1 to 100. Default 80 |
data.stopTopUps body boolean | Also refuse top-ups of the project's running deployments past the budget. Default false |
Response 201 Created
409with codeproject_budget_existswhen the project already has a budget. Change it withPATCHinstead.
curl -X POST "https://console-api.akash.network/v1/project-budgets" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"monthlyAmountUsd": 500,
"alertThresholdPercent": 80,
"stopTopUps": false
}
}'curl -X POST "https://console-api.akash.network/v1/project-budgets" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b",
"monthlyAmountUsd": 500,
"alertThresholdPercent": 80,
"stopTopUps": false
}
}' PATCH /v1/project-budgets/{id}
Change a project's monthly budget. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Budget id |
data.monthlyAmountUsd body number | New monthly amount |
data.alertThresholdPercent body integer | New alert threshold |
data.stopTopUps body boolean | Whether top-ups also stop at the budget |
Response 200 OK
curl -X PATCH "https://console-api.akash.network/v1/project-budgets/8a9b0c1d-2e3f-4a5b-b6c7-d8e9f0a1b2c3" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"monthlyAmountUsd": 750
}
}'curl -X PATCH "https://console-api.akash.network/v1/project-budgets/8a9b0c1d-2e3f-4a5b-b6c7-d8e9f0a1b2c3" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"monthlyAmountUsd": 750
}
}' DELETE /v1/project-budgets/{id}
Remove a project's monthly budget. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
id path string (uuid)
required
| Budget id |
Response 204 No Content
curl -X DELETE "https://console-api.akash.network/v1/project-budgets/8a9b0c1d-2e3f-4a5b-b6c7-d8e9f0a1b2c3" \
-H "x-api-key: $AKASH_API_KEY"curl -X DELETE "https://console-api.akash.network/v1/project-budgets/8a9b0c1d-2e3f-4a5b-b6c7-d8e9f0a1b2c3" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/project-spend
Report the active organization's spend per project over a date range. Callers see the projects they can reach; the organization total is for owners, admins and billing members.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
startDate query string | First UTC day (YYYY-MM-DD), inclusive. Defaults to the first day of endDate's month |
endDate query string | Last UTC day, inclusive. Defaults to today. The range spans at most 366 days |
Response 200 OK
| Field | Description |
|---|---|
data.projects[] array | projectId, name, isDefault, isDeleted and the amounts below, per project |
data.projects[].committedUsd number | Deposits signed for the project's deployments in the range |
data.projects[].consumedUsd number | What their leases cost over the range, including estimatedConsumedUsd |
data.projects[].estimatedConsumedUsd number | Part of consumedUsd accrued since the last on-chain settlement |
data.unassigned object | null | Spend of deployments filed in no project. Null for a caller limited to some projects |
data.total object | null | The organization's whole spend. Null for a caller limited to some projects |
data.isEstimated boolean | Whether any figure includes an estimate |
curl "https://console-api.akash.network/v1/project-spend?startDate=2026-10-01&endDate=2026-10-31" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/project-spend?startDate=2026-10-01&endDate=2026-10-31" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/deployment-spend
Report what the active organization's deployments consumed over a date range, per deployment and per project and day. Takes the same startDate and endDate as GET /v1/project-spend.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
startDate query string | First UTC day (YYYY-MM-DD), inclusive |
endDate query string | Last UTC day, inclusive |
Response 200 OK
| Field | Description |
|---|---|
data.projects[] array | The projects the caller can see, and deleted ones with spend in the range |
data.days[] array | date, projectId and consumedUsd per project and UTC day, leaving out days with no spend |
data.deployments[] array | dseq, name, projectId, consumedUsd, hours, gpuHours and gpuModels per deployment, most spent first |
curl "https://console-api.akash.network/v1/deployment-spend?startDate=2026-10-01&endDate=2026-10-31" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/deployment-spend?startDate=2026-10-01&endDate=2026-10-31" \
-H "x-api-key: $AKASH_API_KEY" GET /v1/organization-activities
List what happened in the active organization, newest first, within the projects the caller can reach. A key that is not bound to a project also sees organization-wide events, such as members joining.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
projectId query string (uuid) | Only the activities of this project |
limit query integer | Activities per page, at most 100. Default 20 |
cursor query string | nextCursor of the previous page |
Response 200 OK
| Field | Description |
|---|---|
data[].type string | organization_created, organization_renamed, project_created, member_invited, member_joined, member_updated, member_granted, member_revoked, deployment_created, deployment_closed or deployment_moved |
data[].projectId string | null | Project the activity happened in, null for an organization-wide one |
data[].actor object | null | { id, username } of who did it, null for the system or a deleted user |
data[].payload object | Values for the activity text, per type, such as dseq and name |
nextCursor string | null | Pass it as cursor for the next page. Null on the last page |
curl "https://console-api.akash.network/v1/organization-activities?projectId=7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b&limit=20" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/organization-activities?projectId=7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b&limit=20" \
-H "x-api-key: $AKASH_API_KEY" PATCH /v1/deployments/{dseq}/project
Move a deployment to another project of the active organization. It keeps running; only the project it is filed in changes. Owners and admins.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence ID |
data.projectId body string (uuid)
required
| Target project |
Response 200 OK
| Field | Description |
|---|---|
data.dseq string | Deployment sequence ID |
data.projectId string (uuid) | Project the deployment is now filed in |
Other roles get403. An unknown deployment or project answers404.
curl -X PATCH "https://console-api.akash.network/v1/deployments/1234567/project" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b"
}
}'curl -X PATCH "https://console-api.akash.network/v1/deployments/1234567/project" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b"
}
}' GET /v1/deployment-locations/{dseq}
Find the organization and project a deployment is filed in. With an API key, it only looks within the key's organization and reach.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
dseq path string
required
| Deployment sequence ID |
Response 200 OK
| Field | Description |
|---|---|
data.organizationId string (uuid) | Organization id |
data.organizationSlug string | Organization slug |
data.projectId string | null | Project id, null when the deployment is filed in no project |
curl "https://console-api.akash.network/v1/deployment-locations/1234567" \
-H "x-api-key: $AKASH_API_KEY"curl "https://console-api.akash.network/v1/deployment-locations/1234567" \
-H "x-api-key: $AKASH_API_KEY" POST /v1/api-keys
Create an API key in the active organization, optionally limited to one of its projects. A project-bound key cannot manage members, invitations, projects, billing or API keys.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.name body string
required
| Key name |
data.expiresAt body string | ISO 8601 date-time, in the future and at most one year from now. Defaults to one year after creation. A later date: 400 |
data.projectId body string (uuid) | Limits the key to this project of the organization. Unknown or out of reach: 404 |
Response 201 Created
| Field | Description |
|---|---|
data.apiKey string | The secret, returned only here |
data.organizationId string (uuid) | Organization the key acts in |
data.projectId string | null | Only project the key reaches, or null for every project its owner can reach |
GET /v1/api-keyslists your keys with the sameorganizationIdandprojectIdfields, without the secret.
curl -X POST "https://console-api.akash.network/v1/api-keys" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "checkout-api CI",
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b"
}
}'curl -X POST "https://console-api.akash.network/v1/api-keys" \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "checkout-api CI",
"projectId": "7d2e4a61-3b9c-4f0e-a5d8-6c1b2e3f4a5b"
}
}'JWT for provider access
JWT for provider access
The Console API and the provider share a JWT-based access model for lease-scoped operations (logs, events, status, shell). Mint a short-lived token from the Console API, then call the provider directly with it.
TTL: tokens are short-lived (default 1800 s in the Console UI). There is no refresh endpoint — re-call POST /v1/create-jwt-token to extend lifetime.
Scope: grant the narrowest set you need. Missing scope → 401 from the provider. Valid values: send-manifest, get-manifest, logs, shell, events, status, restart, hostname-migrate, ip-migrate.
Spec: JWT payload follows AEP-64. The provider validates it the same way regardless of who minted it.
Stability:POST /v1/create-jwt-tokenis Swagger-only / Tier 2 — observed in production but not in the official API reference. It may change without notice. Self-custody users sign locally with@akashnetwork/chain-sdkand bypass this endpoint entirely.
POST /v1/create-jwt-token
Mint a short-lived, lease-scoped JWT for accessing provider endpoints.
| Parameter | Description |
|---|---|
x-api-key header string
required
| Your API key |
data.ttl body number
required
| Token TTL in seconds (Console UI default: 1800) |
data.leases.access body enum
required
| One of full, scoped, or granular |
data.leases.scope body array<string> | Required when access is scoped. Any of send-manifest, get-manifest, logs, shell, events, status, restart, hostname-migrate, ip-migrate |
data.leases.permissions body array<object> | Required when access is granular. Per-provider, per-deployment rules |
Response 201 Created
| Field | Description |
|---|---|
data.token string (JWT) | Bearer token to send to provider endpoints as Authorization: Bearer |
Swagger-only / Tier 2 endpoint — may change without notice.
No refresh endpoint exists. To extend a token's lifetime, re-call this endpoint and discard the old token.
JWT=$(curl -sX POST https://console-api.akash.network/v1/create-jwt-token \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"ttl": 1800,
"leases": {
"access": "scoped",
"scope": ["status", "logs", "events", "shell"]
}
}
}' | jq -r .data.token)JWT=$(curl -sX POST https://console-api.akash.network/v1/create-jwt-token \
-H "x-api-key: $AKASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"ttl": 1800,
"leases": {
"access": "scoped",
"scope": ["status", "logs", "events", "shell"]
}
}
}' | jq -r .data.token)Lease operations (provider)
Provider-side lease endpoints
These endpoints are served by the provider, not by console-api.akash.network. Resolve the provider's hostUri via GET /v1/providers/{address} (network-data API), then call the provider directly with the JWT in Authorization: Bearer <token>.
TLS / cert pinning: provider certificates are self-signed against the provider's on-chain wallet address — browsers will reject them. Server-side, you have to look the cert up on-chain: the CN must be the provider's bech32 wallet address, and the chain's MsgCreateCertificate record for that (address, serial number) must match the leaf cert's fingerprint. That lookup is a chain query, so it has to happen after the TLS handshake — Node's checkServerIdentity is synchronous and can't await. The canonical pattern (used by Console) is to disable Node's default verification, then validate the peer cert asynchronously against the chain. See the provider-proxy CertificateValidator for a reference implementation. In a browser, route through a provider-proxy service.
events vs kubeevents gotcha: Console UI accepts events as a path component and rewrites it to kubeevents client-side. The wire path on the provider is always kubeevents — use that directly to avoid surprises.
Common errors:
401— JWT scope doesn't include the requested operation (e.g. calling/logswithoutlogsin scope).- Empty log stream — the deployment hasn't started yet, or the named service isn't running.
- TLS handshake failure — you're missing the cert-pinning agent, or the provider has rotated keys.
GET https://{hostUri}/lease/{dseq}/{gseq}/{oseq}/status
Provider
Polled status of each service in a lease: ready/total replicas, forwarded ports, IPs, restart counts.
| Parameter | Description |
|---|---|
Authorization header string
required
| Bearer |
dseq path string
required
| Deployment sequence ID |
gseq path number
required
| Group sequence |
oseq path number
required
| Order sequence |
Response 200 OK
| Field | Description |
|---|---|
services.<name>.ready_replicas number | Replicas currently passing readiness checks |
services.<name>.available_replicas number | Replicas marked available by the Kubernetes controller |
services.<name>.replicas number | Current replicas |
services.<name>.total number | Desired replicas |
services.<name>.uris array<string> | Accessible URIs for the service (when leasing endpoints) |
forwarded_ports.<name> array<object> | Provider-side port forwards, keyed by service name (top-level — not nested under services) |
ips.<name> array<object> | Public IPs assigned to the service, keyed by service name (top-level, when leasing IP endpoints) |
Same shape as deployment.leases[].status in the Console API, but freshly polled from the provider.JWT scope must include status. # -k skips TLS verification (provider certs are self-signed against the
# on-chain wallet). For production, validate the cert against the chain
# out-of-band — see the provider-endpoints preface.
curl -k "https://${HOSTURI#https://}/lease/${DSEQ}/${GSEQ}/${OSEQ}/status" \
-H "Authorization: Bearer $JWT"# -k skips TLS verification (provider certs are self-signed against the
# on-chain wallet). For production, validate the cert against the chain
# out-of-band — see the provider-endpoints preface.
curl -k "https://${HOSTURI#https://}/lease/${DSEQ}/${GSEQ}/${OSEQ}/status" \
-H "Authorization: Bearer $JWT" WSS wss://{hostUri}/lease/{dseq}/{gseq}/{oseq}/logs
Provider
Stream container logs for a lease. Send follow=true to tail continuously.
| Parameter | Description |
|---|---|
Authorization header string
required
| Bearer (scope must include logs) |
dseq path string
required
| Deployment sequence ID |
gseq path number
required
| Group sequence |
oseq path number
required
| Order sequence |
tail query number | Number of lines to tail from the end of the log |
follow query boolean | Stream new logs continuously when true |
service query string | Filter to a specific service name |
| Field | Description |
|---|---|
(stream) binary | Stream of text chunks; one chunk ≈ one log line |
JWT scope must include logs.In a browser, the self-signed provider cert will be rejected — route through a provider-proxy.
# --insecure skips TLS verification (provider certs are self-signed).
# Requires websocat 1.13+. See provider-endpoints preface for production
# cert validation.
websocat --insecure "wss://${HOSTURI#https://}/lease/${DSEQ}/${GSEQ}/${OSEQ}/logs?follow=true&tail=200" \
-H "Authorization: Bearer $JWT"# --insecure skips TLS verification (provider certs are self-signed).
# Requires websocat 1.13+. See provider-endpoints preface for production
# cert validation.
websocat --insecure "wss://${HOSTURI#https://}/lease/${DSEQ}/${GSEQ}/${OSEQ}/logs?follow=true&tail=200" \
-H "Authorization: Bearer $JWT" WSS wss://{hostUri}/lease/{dseq}/{gseq}/{oseq}/kubeevents
Provider
Stream Kubernetes events for the lease (pod scheduling, container restarts, etc.).
| Parameter | Description |
|---|---|
Authorization header string
required
| Bearer (scope must include events) |
dseq path string
required
| Deployment sequence ID |
gseq path number
required
| Group sequence |
oseq path number
required
| Order sequence |
| Field | Description |
|---|---|
(stream) JSON objects | One Kubernetes Event per message frame |
The wire path iskubeevents, notevents. Some client tools accepteventsand rewrite it client-side, but the provider only responds onkubeevents.
JWT scope must include events. # --insecure skips TLS verification (provider certs are self-signed).
websocat --insecure "wss://${HOSTURI#https://}/lease/${DSEQ}/${GSEQ}/${OSEQ}/kubeevents" \
-H "Authorization: Bearer $JWT"# --insecure skips TLS verification (provider certs are self-signed).
websocat --insecure "wss://${HOSTURI#https://}/lease/${DSEQ}/${GSEQ}/${OSEQ}/kubeevents" \
-H "Authorization: Bearer $JWT" WSS wss://{hostUri}/lease/{dseq}/{gseq}/{oseq}/shell
Provider
Interactive kubectl exec-style shell. Binary multiplexed stream of stdin/stdout/stderr/resize. Advanced — prefer the SDK helpers for most use cases.
| Parameter | Description |
|---|---|
Authorization header string
required
| Bearer (scope must include shell) |
dseq path string
required
| Deployment sequence ID |
gseq path number
required
| Group sequence |
oseq path number
required
| Order sequence |
service query string
required
| Service name to exec into |
podIndex query number
required
| Pod index (zero-based) |
tty query number
required
| 1 to allocate a TTY, 0 otherwise |
stdin query number
required
| 1 to attach stdin, 0 otherwise |
cmd0, cmd1, … query string
required
| Command and each argument as separate numbered params, e.g. cmd0=/bin/sh&cmd1=-c&cmd2=ls. There is no single (or base64) cmd param. |
| Field | Description |
|---|---|
(stream) binary | Multiplexed binary frames; the first byte is the stream code — 100=stdout, 101=stderr, 102=result (JSON, e.g. {\"exit_code\":0}), 103=failure. Client→server uses 104=stdin, 105=terminal-resize. |
JWT scope must include shell.Command and arguments are passed as separate numbered query params (cmd0,cmd1, …) — there is no single base64-encodedcmdparam.ttyandstdinare required.
The example above is a one-shot command (tty=0&stdin=0). For an interactive session, settty=1&stdin=1, stream keystrokes as104-prefixed binary frames, and send terminal resizes as105frames. Most users should use the Akash CLI (provider-services lease-shell --tty) or SDK helpers instead of driving this directly — see Shell Access.
Console UI uses xterm.js on the client side to render the stream.For programmatic shells, use the provider's kubectl exec-style protocol via the SDK helpers rather than constructing this WebSocket by hand. See also
- Getting Started — full workflow with examples
- Quickstart — end-to-end deployment in five API calls
- SDL Reference — SDL syntax and options
- Console — visual interface for managing deployments
- GitHub: akash-network/console — source and issues