API Quickstart
This page walks a developer from zero to a first answer out of a Neuronet. You call an AETRON gateway, the gateway picks a miner, runs your request, and returns the result. Verification of that result happens afterwards, so the verdict is fetched by a second call using the request id. Everything below is taken from the gateway's HTTP surface as it is implemented today.
Before You Start
You need three things:
- A gateway host. On testnet the managed gateway is public at
https://gateway-testnet.aetron.ai, and the examples below use it. On mainnet no managed gateway is published yet, so the host comes from whoever runs the gateway serving your Neuronet, or it is your own address if you run one. Swap the host in the examples for that address. All public addresses are listed in Networks and Endpoints. - A Neuronet id. An integer. It appears in every data-plane path as
/n/{id}/. - A task id. An integer identifying which task inside the Neuronet you are calling. A Neuronet can host several tasks (a language model and an image model, for example), each with its own model and verification settings. See Task Configuration.
Check that a gateway is reachable before anything else:
curl https://gateway-testnet.aetron.ai/healthz
# ok
Authentication
There are two ways to authenticate, and they grant different things.
API key. End-user integrations send the key in the x-api-key header. Keys are issued by the control plane and carry a prefix that tells you which environment they belong to: ak_live_ for production keys and ak_test_ for test keys. A key is bound to one Neuronet, so calling a different Neuronet id with it is rejected. The gateway checks the key against the control plane and caches the verdict briefly. If the control plane cannot be reached, the key is refused rather than let through.
-H "x-api-key: ak_live_YOUR_KEY"
Owner coldkey signature. The Neuronet owner authenticates by signing a challenge with the coldkey that owns the Neuronet, using three headers: x-aetron-account (the ss58 address), x-aetron-signature (hex sr25519), and x-aetron-timestamp (unix seconds). The signed payload is the constant AETRON-owner-auth:v1 followed by the Neuronet id and the timestamp, both little-endian. The signature is accepted only within 300 seconds of the current time, which stops replay. Browser wallets wrap the payload in <Bytes>...</Bytes> before signing, and the gateway accepts both the wrapped and the raw form.
API keys give the inference path. Starting a training job requires the owner signature.
Send an Inference Request
curl -X POST https://gateway-testnet.aetron.ai/n/7/v1/1/infer \
-H "x-api-key: ak_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "Explain gradient clipping in two sentences.",
"params": {}
}'
The body has two fields. input is a string, and how it is interpreted (plain text or base64) depends on the Neuronet's own schema. params is a free-form JSON object passed through to the miner, and it may be omitted.
A successful call returns HTTP 200:
{
"id": "9f2c...c41a",
"output": "Gradient clipping caps the norm of the gradient ...",
"verification": {
"status": "pending",
"receipt": "vrc_9f2cbe4471a0d3e2"
}
}
id is the request id, a 64-character hex string. Keep it: it is the handle for the verification lookup. receipt is a short reference built from the same id.
If the task produces binary output (an image, for example), output is an empty string and two extra fields appear: output_b64 with the raw bytes in base64 and content_type with the sniffed type such as image/png. On the text path those fields are absent entirely, so a client that only reads output keeps working.
Under the hood the gateway picks a miner, and if that miner fails to answer it retries the same job on a different one, up to three attempts, before giving up. The job carries a 30 second deadline.
Fetch the Verification Verdict
The model answer comes back in the infer response, but its verdict does not. Verification runs after the fact: only a sampled fraction of requests is replayed by other miners, and the quorum needs time to report. That is why the verdict is a separate call keyed by the request id.
curl https://gateway-testnet.aetron.ai/n/7/v1/requests/9f2c...c41a
{
"id": "9f2c...c41a",
"verification": {
"status": "pending",
"votes": 3,
"quorum": 20
}
}
Four statuses are possible:
pending: the request was sampled and checkers are still voting.votesandquorumshow the progress.verified: the quorum settled on an honest verdict.flagged: the quorum settled on fraud.not_sampled: this request was not selected for replay, so there is nothing to report on it. Most requests end here by design, since replaying everything would double the cost of the network.
not_sampled is not a failure. Sampling is what keeps verification cheap, and Proof of Intelligence explains how a partial sample still makes systematic cheating unprofitable.
Start a Training Job
Training is asynchronous end to end. The call dispatches the job and returns immediately with HTTP 202, and you poll a second endpoint by the training id. This path requires the owner coldkey signature, not an API key.
curl -X POST https://gateway-testnet.aetron.ai/n/7/v1/training \
-H "x-aetron-account: 5Dt..." \
-H "x-aetron-signature: 0x..." \
-H "x-aetron-timestamp: 1750000000" \
-H "Content-Type: application/json" \
-d '{
"task_id": 2,
"dataset_hash": "3ab1...9f0d",
"n_steps": 1000,
"method": "lora"
}'
dataset_hash is 64 hex characters. method defaults to lora and accepts full, lora, sft, dpo, orpo and qlora. lr, seed and round_nonce are optional.
{
"training_id": "5b70...ee13",
"miner": "5Dt...",
"checkpoint_root": "0f44...a2c8",
"n_steps": 1000,
"status": "dispatched"
}
Then poll:
curl https://gateway-testnet.aetron.ai/n/7/v1/training/5b70...ee13
The status advances from dispatched to committed once the miner's commitment is visible on chain, then through the challenge to a final verdict. A checkpoint_root appears in the response only after the commitment exists on chain, because before that there is nothing the miner has staked its bond against. See Proof of Training for what is being proven.
Errors
Every error response carries an error field with a stable string code.
| HTTP | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing, malformed or expired credentials. |
| 402 | tenant_suspended | The tenant's plan is not paid. |
| 403 | not_owner | The caller does not own this Neuronet. |
| 409 | neuronet_frozen | The Neuronet is not active. |
| 422 | pulse_floor_unmet | The Neuronet is below its required activity floor. |
| 429 | rate_limited | Per-account burst limit. |
| 429 | capacity_exceeded | On-chain capacity for the epoch is used up. Adds capacity, used and reset_epoch. |
| 429 | quota_exceeded | The key's daily budget is spent. Adds limit, used and reset_at. |
| 502 | miner_error | The miner answered with a failure. The reason is in detail. |
| 503 | no_miner_available | No miner is serving this task. |
| 503 | overloaded | The gateway is shedding load. |
| 504 | miner_timeout | No miner answered in time. |
overloaded and rate_limited come with a Retry-After header, so a retry after that delay is the right response. quota_exceeded deliberately has no Retry-After, because the budget returns at reset_at and retrying sooner is pointless.