Skip to main content

Gateway API Reference

The Gateway is the off-chain service that turns an HTTP request into work on the AETRON mesh. It authenticates the caller, checks the Neuronet's on-chain capacity, picks a miner, sends the job over libp2p, returns the answer, and records the served request for settlement. The chain itself has no job-issuance calls, so this HTTP surface is the entry point for anyone using a Neuronet.

Anyone can run a Gateway, so the host depends on who serves your Neuronet. On testnet the managed one is public at https://gateway-testnet.aetron.ai; on mainnet no managed host is published yet. The routes below are the same wherever it runs. See Networks and Endpoints for the current addresses.

Base Path and Routing​

Every data-plane route is scoped to a Neuronet id:

POST /n/{id}/v1/{task}/infer
POST /n/{id}/v1/{task}/infer/stream
GET /n/{id}/v1/requests/{req_id}
POST /n/{id}/v1/training
GET /n/{id}/v1/training/{tid}
GET /healthz
GET /metrics

{id} is the Neuronet id (unsigned 32-bit). {task} is the task id inside that Neuronet (unsigned 16-bit). CORS is permissive, so browser clients on another origin can call the Gateway directly.

GET /healthz takes no auth and returns the plain string ok. GET /metrics exposes Prometheus counters for the same Gateway.

Authentication​

Two identity paths are accepted, resolved from request headers.

Coldkey Challenge (Owner)​

The Owner signs a canonical payload with the coldkey that owns the Neuronet, using sr25519 with the standard Substrate signing context.

HeaderMeaning
x-aetron-accountSS58 address of the signer
x-aetron-signaturehex sr25519 signature, 64 bytes, optional 0x prefix
x-aetron-timestampunix seconds used in the payload

The signed payload is the ASCII string AETRON-owner-auth:v1, followed by the Neuronet id as little-endian u32, followed by the timestamp as little-endian u64, for 32 bytes total. Binding the payload to the Neuronet id means a signature cannot be replayed against a different Neuronet.

The timestamp must be within 300 seconds of the Gateway's clock in either direction. Browser wallets that wrap data with <Bytes> before signing are supported: the Gateway checks the signature against both the raw payload and the wrapped form.

API Key (End User)​

An end user calls with x-api-key: ak_live_.... The key is issued by the control plane against one tenant and one Neuronet, so the Gateway does not apply the on-chain ownership check to it. A key carries a daily request budget. When no x-api-key header is present, the request falls through to the coldkey path.

API keys are accepted on the inference endpoints only. Training requires the Owner's coldkey, since starting a training run spends the Owner's capacity.

POST /n/{id}/v1/{task}/infer​

Runs one inference job and returns the result synchronously.

Request body:

{
"input": "string",
"params": {}
}

input is the prompt or payload; its schema is decided by the Neuronet's task. params is an optional free-form JSON object passed through to the miner. The job is sent to the miner with a 30000 ms deadline.

Response, HTTP 200:

{
"id": "64-hex job id",
"output": "text answer",
"verification": { "status": "pending", "receipt": "vrc_..." }
}

id is the job id, a 64-character hex string, and the value you pass to the request-status endpoint. receipt is vrc_ followed by the first 16 hex characters of the job id.

When the miner returns bytes that are not valid UTF-8, such as an image from a diffusion task, output is an empty string and two extra fields appear: output_b64 with the raw bytes in base64, and content_type. The type is sniffed from the leading bytes and is one of image/png, image/jpeg, or application/octet-stream. On the text path neither field is present at all, so older clients see an unchanged response.

What Happens Behind the Request​

The handler runs a fixed sequence, and each stage has its own failure code: suspension check, authentication, per-account rate limit, per-key daily quota, admission control, Neuronet active check, ownership check, capacity gate, miner selection, dispatch, and settlement recording. Verification starts afterwards and never blocks the response.

Dispatch makes up to three attempts on different miners. The job id is derived from the Neuronet id, task id, and a hash of the input, so it stays the same across attempts and a retry is idempotent for the miner. A miner that fails or times out is pushed into the circuit breaker and excluded from the remaining attempts. If the task's privacy level is at least P1, the input is sealed for the selected miner with its on-chain X25519 key; a miner without a registered encryption key is skipped rather than sent plaintext.

Once the reply is accepted, the Gateway samples the job against the task's replay rate to decide whether to start verification. The pallet default for that rate is 70000 parts per million, which is 7 percent of requests.

POST /n/{id}/v1/{task}/infer/stream​

The same call as infer, with token deltas delivered as they are generated. Same body, same authentication, same gates. The response is a Server-Sent Events stream with HTTP 200, and three event types appear on it:

EventPayload
deltaA chunk of generated output. Several arrive in order while the miner works.
resultThe final JSON, byte for byte the same object the plain infer route returns.
errorThe job failed after the stream had opened.

Because SSE has to answer 200 before anything can be written, an authentication or capacity failure that would be a 4xx on the plain route is reported inside the stream instead. Clients that need the status code, and clients that do not care about partial output, should call infer.

The job id is derived from the Neuronet id, the task id, and a hash of the input, so it is known before the job finishes. That is what lets the stream poll the miner for deltas while the authoritative request is still in flight, and it is why a retried request keeps the same id.

GET /n/{id}/v1/requests/{req_id}​

Looks up the verification state of one earlier inference request. req_id is the full 64-hex job id returned as id by the infer endpoint, with or without a 0x prefix.

Response, HTTP 200:

{
"id": "64-hex job id",
"verification": { "status": "pending", "votes": 3, "quorum": 20 }
}

votes and quorum appear only while votes are still being collected. quorum is the number of verifier votes the protocol requires; the Gateway falls back to 20 when the chain does not answer. Status values:

StatusMeaning
pendingVerifiers have been assigned and votes are accumulating, but the quorum has not finalized
verifiedThe quorum finalized the job as Honest
flaggedThe quorum finalized the job as Fraud
not_sampledThe job was not selected for replay, or the verdict was Abstain

A malformed req_id returns HTTP 500 with error internal.

POST /n/{id}/v1/training​

Starts a training run. Owner coldkey only; an API key is rejected with not_owner.

Request body:

{
"task_id": 0,
"dataset_hash": "64-hex",
"n_steps": 1000,
"round_nonce": 0,
"method": "lora",
"lr": 0.0001,
"seed": 42
}

task_id, dataset_hash, and n_steps are required. round_nonce defaults to 0, method defaults to lora, and lr and seed are optional. Accepted methods include full, lora, sft, dpo, orpo, and qlora. Choosing qlora restricts the miner pool to NVIDIA hardware, because its 4-bit path only runs there. Miner selection for training filters by Pulse tier rather than latency, requiring tier 2 or higher, then takes the most capable miner: backward passes and optimizer state are beyond what lower tiers can carry.

Response, HTTP 202:

{
"training_id": "64-hex",
"miner": "SS58 hotkey",
"checkpoint_root": "64-hex",
"n_steps": 1000,
"status": "dispatched"
}

The dispatched status means the miner acknowledged the job over the mesh. It does not mean an on-chain commitment exists yet.

GET /n/{id}/v1/training/{tid}​

Returns the live training status, derived from chain state rather than from the Gateway's own memory. tid is the 64-hex training id.

{
"training_id": "64-hex",
"verification": { "status": "committed" },
"checkpoint_root": "64-hex"
}

checkpoint_root appears only once the miner has committed the trajectory on chain, since that is the value the miner's bond stands behind.

StatusMeaning
dispatchedSent to a miner, no on-chain commitment yet
committedThe trajectory commitment is recorded on chain
trainingIn progress, carries a pct field
challengedA step was challenged and witness verdicts are being collected
verifiedThe witness quorum matched
flaggedThe trajectory did not match, or the miner missed the challenge deadline, in which case reason is miner_timeout

An unknown tid returns HTTP 500 with error internal.

Error Codes​

Errors return a JSON body with an error field naming the condition.

HTTPerrorCause
401unauthorizedMissing, malformed, stale, or invalid signature
402tenant_suspendedManaged tenant suspended, checked before anything else
403not_ownerCaller is authenticated but does not own the Neuronet
409neuronet_frozenThe Neuronet is not active on chain
422pulse_floor_unmetThe Pulse floor for the task is not met
429capacity_exceededOn-chain capacity for the epoch is exhausted
429rate_limitedPer-account request rate exceeded
429quota_exceededThe API key's daily budget is spent
500internalMalformed identifier or an unclassified failure
502miner_errorThe miner replied with an error; the text is in detail
503no_miner_availableNo eligible miner in the task's pool
503overloadedGateway in-flight limit reached
504miner_timeoutNo miner answered within the dispatch attempts

capacity_exceeded adds capacity, used, and reset_epoch, so a client can see how full the epoch is and when the budget resets. quota_exceeded adds limit, used, and reset_at, and carries no Retry-After, because the daily budget returns at UTC midnight rather than in a second. overloaded and rate_limited add retry_after in the body and a Retry-After: 1 header.

Limits​

These are the built-in defaults. Deployments may override them.

  • Per-account rate limit: 20 requests per second sustained, burst of 40.
  • Admission: 64 requests in flight across the Gateway, 16 per Neuronet. Beyond that, requests are shed with overloaded instead of queuing.
  • Challenge freshness window: 300 seconds.
  • Dispatch attempts per request: 3, each on a different miner.
  • Miner deadline per inference job: 30000 ms.

Capacity is metered in slots. An inference request costs 1 slot by default, and training costs more, as set by the task. The Gateway counts slots it has dispatched in the current epoch on top of the on-chain figure, because the on-chain counter only advances at settlement. See Staking for how stake sets a Neuronet's capacity, and Task Configuration for the per-task settings referenced here.