DEVELOPER API
Integration and contribution guide
Only endpoints that exist are documented here. Every response is JSON; data is wrapped in data, lists carry meta.nextCursor, and errors use a stable error.code.
Endpoints
| method | path | purpose |
|---|---|---|
| GET | /api/v1/health | service and database health |
| GET | /api/v1/network/status | deployment, indexer and research-activity status |
| GET | /api/v1/contracts | network configuration, deployment manifest and registry ABI |
| GET | /api/v1/capabilities | capability domains |
| GET | /api/v1/capabilities/{slug} | one capability with its suites and baselines |
| GET | /api/v1/baselines?capability= | baselines (summary) |
| GET | /api/v1/baselines/{id} | one baseline including its source |
| GET | /api/v1/suites/{id} | a test suite record (public dev seed, held-out commitment, limits) |
| GET | /api/v1/proposals?status=&capability=&contributor=&from=&to=&repro=&cursor=&limit= | proposals, newest first (from/to are YYYY-MM-DD on submission time; repro is REPRODUCED, PENDING, DIVERGED or NONE for the latest evaluation) |
| POST | /api/v1/proposals | submit a proposal (session required) |
| GET | /api/v1/proposals/{id} | one proposal with experiments, evaluations, lineage and contributions |
| POST | /api/v1/proposals/{id}/withdraw | withdraw your proposal (session required) |
| POST | /api/v1/proposals/{id}/replications | request another replication run (session required) |
| POST | /api/v1/proposals/{id}/anchor | report the on-chain anchor transaction (session required) |
| GET | /api/v1/experiments?proposal=&status= | experiments |
| GET | /api/v1/experiments/{id} | one experiment including its full harness result |
| GET | /api/v1/evaluations?proposal=&status= | evaluation records |
| GET | /api/v1/evaluations/{id} | one evaluation record with its challenges |
| GET | /api/v1/lineage?capability= | the lineage graph: nodes and edges |
| GET | /api/v1/lineage/{id} | a lineage record by id or child id |
| GET | /api/v1/challenges?evaluation= | challenges |
| POST | /api/v1/challenges | open a challenge (session required) |
| GET | /api/v1/challenges/{id} | one challenge |
| POST | /api/v1/challenges/{id}/anchor | report the challenger's on-chain openChallenge transaction (challenger session) |
| POST | /api/v1/challenges/{id}/resolve | resolve a challenge: uphold or dismiss (registry owner session; on-chain challenges need the resolve transaction hash) |
| POST | /api/v1/auth/nonce | issue a SIWE nonce |
| POST | /api/v1/auth/verify | verify a SIWE message and set the session cookie |
| GET | /api/v1/auth/session | current session |
| POST | /api/v1/auth/logout | clear the session |
The machine-readable index is at /api/v1.
Authentication (Sign-In with Ethereum)
Reads are public. Writes require a session established by signing a SIWE message. The message must use this site's domain, chain id 4663, a nonce issued by POST /api/v1/auth/nonce and an expiration within one hour. Signatures are verified server-side (EIP-1271 contract wallets included) and each nonce is single-use. The session is an HttpOnly cookie valid for seven days. Signing a message sends no transaction and moves no funds.
POST /api/v1/auth/nonce → { nonce, domain, chainId, expiresAt }
sign SIWE message (viem createSiweMessage) with your wallet
POST /api/v1/auth/verify { message, signature } → sets kuxer_session cookie
POST /api/v1/proposals (cookie) → 201 { proposal, experiment, created, queue }Submitting a proposal
POST /api/v1/proposals accepts the fields below. parents lists validated proposal ids to inherit from; the baseline is always added as the first parent. The source must be a JavaScript ES module exporting solve(instance, ctx) (see the candidate contract). Send an Idempotency-Key header to make retries safe; an identical resubmission returns the existing proposal with created: false.
{
"capabilityId": "cap_euclidean-tsp-v1",
"baselineId": "bl_nearest-neighbor-v1",
"parents": [],
"title": "Nearest neighbor with 2-opt refinement",
"summary": "Applies a deterministic 2-opt local search after nearest-neighbor construction.",
"method": "Standard 2-opt with first-improvement moves until no improving swap exists or 80% of the deadline is used.",
"source": "export function solve(instance, ctx) { /* ... */ }"
}The response includes the queued INITIAL experiment. Poll GET /api/v1/proposals/{id} to follow status changes; the experiment's full harness result is available at GET /api/v1/experiments/{id} once it completes.
Anchoring on-chain
When the registry is deployed, a contributor can commit their proposal from their own wallet by calling commitProposal(id, contentHash, parents) on the registry, where id and each parent are keccak256(utf8(recordId)) (returned as chainKey) and contentHash is the proposal's contentHash. All parents must already be committed. Then report the transaction with POST /api/v1/proposals/{id}/anchor; the server verifies the receipt and event before recording it. Evaluations of anchored proposals are committed by the operator's evaluator signer and confirmed by the indexer.
Pagination, caching and versioning
- List endpoints use keyset pagination: pass
limit(1–100, default 25) and themeta.nextCursorvalue ascursor. Cursors are opaque. - Public GET responses carry
Cache-Controlwith shorts-maxagevalues; mutable records are not cached. - The API is versioned by path. Breaking changes ship as
/api/v2; schema changes are reflected inschemaVersionon each record. Every response includes anx-api-versionheader.
Rate limits
| scope | limit |
|---|---|
| read | 240 requests per 60 s |
| auth:nonce | 30 requests per 60 s |
| auth:verify | 20 requests per 60 s |
| proposals:create | 10 requests per 3600 s |
| replication:request | 10 requests per 3600 s |
| challenges:create | 5 requests per 3600 s |
| challenges:anchor | 30 requests per 3600 s |
| challenges:resolve | 60 requests per 3600 s |
| proposals:anchor | 30 requests per 3600 s |
Exceeding a limit returns 429 rate_limited with details.retryAfterSeconds. Limits apply per wallet for writes and per IP for anonymous requests.
Errors and retries
{
"error": {
"code": "validation_error",
"message": "request failed validation",
"details": [
{
"path": "summary",
"message": "Too small: expected string to have >=10 characters"
}
]
}
}| status | code | meaning |
|---|---|---|
| 400 | bad_request · validation_error | malformed body, query or cursor; details lists field issues |
| 401 | unauthorized | no or invalid session; SIWE verification failed |
| 403 | forbidden | acting on another contributor's proposal; challenging your own record; resolving a challenge without the registry owner session |
| 404 | not_found | unknown record |
| 409 | conflict | idempotency key reused with a different body; open challenge exists |
| 422 | unprocessable | valid shape, invalid state (unknown baseline, unvalidated parent, wrong status) |
| 429 | rate_limited | retry after details.retryAfterSeconds |
| 503 | service_unavailable | database or registry not configured; safe to retry later |
Retry 429 and 503 with backoff and the same Idempotency-Key. Never retry 4xx validation failures without changing the request.