Quickstart
Issue a key, create an app, connect it to a repository, and run it. Ten minutes, and no infrastructure of your own.
Reach the control plane
Two endpoints need no credential: /readyz tells you the plane is serving, and /version tells you which build answered. Check both before you debug anything else.
export NEURUN_URL=https://api.neurun.dev
curl -sS $NEURUN_URL/readyz
curl -sS $NEURUN_URL/version
# {"version":"0.1.0","commit":"9f3a41c","api_version":"v1",
# "schema_version":"12","built_at":"2026-01-14T09:12:03Z"}Create an account
Registration is the only way an account comes into being — there is no CLI to run on the host. It creates the account as an administrator, creates the project it names, and signs you in by setting the session cookie, so one request takes a fresh install to a usable dashboard.
curl -sS -X POST $NEURUN_URL/v1/auth/register \
-c session.txt \
-d '{"username":"ada",
"password":"a-long-password"}'
# 201 {"user":{...},"dashboard":{...}}Issue a key
A session is for a person at a browser; a program gets a key. Create one with the scopes the work actually needs — the secret is returned exactly once, only its SHA-256 digest is stored, and the plaintext is unrecoverable.
curl -sS -X POST $NEURUN_URL/v1/api-keys \
-b session.txt \
-d '{"name":"ci","scopes":["apps:write","deployments:write","executions:write"]}'
export NEURUN_KEY=neu_live_a41f.••• # shown once, never againA key carries scopes, not a project
Create an app
An app is the thing you deploy to, and it must exist first. Nothing auto-creates one: a deploy looks up the app_id and fails with app not found when it is missing. That is deliberate — auto-creation means a typo in a client silently produces a second app that looks fine and receives none of your traffic.
curl -sS -X POST $NEURUN_URL/v1/apps \
-H "authorization: Bearer $NEURUN_KEY" \
-d '{"project_id":"prj_4T1M0","name":"pricing-crawler"}'
# {"id":"app_7QK2M0X4","project_id":"prj_4T1M0",
# "name":"pricing-crawler", ...}Connect it to a repository
Source is never uploaded. Point the app at a repository the GitHub App is installed on, and every push to its production ref fetches that commit and builds it. Deploying a ref by hand takes the same path, so a manual deploy and a pushed one produce the same kind of record.
curl -sS -X PUT $NEURUN_URL/v1/apps/app_7QK2M0X4/repository \
-H "authorization: Bearer $NEURUN_KEY" \
-d '{"repository":"acme/pricing-crawler","production_ref":"main"}'
# then push to main — or deploy a ref yourself
curl -sS -X POST $NEURUN_URL/v1/github/deployments \
-H "authorization: Bearer $NEURUN_KEY" \
-d '{"app_id":"app_7QK2M0X4","ref":"main"}'
HTTP/1.1 201 Created
# {"id":"dep_01HXQ8F2K9","status":"ready",
# "build":{"id":"bld_9F3AC41","runtime":"python"}}Run it
Creating an execution returns 202 immediately and pins it to the latest ready build. Poll the execution until it goes terminal; only then are output, logs and failure settled.
POST /v1/deployments/
dep_01HXQ8F2K9/executions
{"input": {"url": "https://example.com"}}{
"id": "exe_01HXQ8F2M4",
"status": "queued",
"build_id": "bld_9F3AC41",
"input": {"url": "https://example.com"}
}The build_id is the point. You deployed source; the server tells you exactly which immutable build will answer, and keeps naming it long after you have rebuilt.