From 4ed2f4eb6db27a1edd58146b4e12ba5acf501443 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Wed, 1 Jul 2026 10:00:00 +0530 Subject: [PATCH 01/11] docs(claim): claiming moves to Free tier (24h TTL), not hobby-by-default docs/claim.md said claiming moves resources to 'hobby by default ($9/mo)', contradicting policy + home.md/pricing.md/llms.txt: claiming gives a Free-tier account (24h TTL, same limits as anonymous), NOT an automatic paid plan. Resources keep expiring at 24h until the user upgrades. Reframed to the canonical pricing.md/llms.txt copy + the no-trial/pay-from-day-one policy. Co-Authored-By: Claude Fable 5 --- docs/claim.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/claim.md b/docs/claim.md index 1bc681d..ca845b5 100644 --- a/docs/claim.md +++ b/docs/claim.md @@ -23,6 +23,8 @@ Click the magic link to set a session cookie. Every resource attached to your fingerprint transfers to your team atomically; the connection URLs don't change so any already-running code keeps working. -Claimed resources move to your team's tier (hobby by default — $9/mo). There -is no separate trial period on paid tiers — **the 24-hour anonymous slice -is the trial**. +Claimed resources move to your team's **Free tier** (24h TTL, same limits as +anonymous) — claiming gives you an account, not durability. Resources keep +expiring at 24 hours until you upgrade to a paid tier (Hobby $9/mo or above) +in the dashboard. Paid tiers bill from day one — there is no separate trial +period. From 9ed7f677c807b44ad125e8833c13c22acb385e7f Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Sun, 21 Jun 2026 10:00:00 +0530 Subject: [PATCH 02/11] docs(leads): document POST /api/v1/leads enterprise contact endpoint Surface the new leads endpoint in llms.txt so agents know to call it when a user needs capacity beyond Pro (dedicated infra, SAML, compliance) rather than asking the agent to invent a path. Includes field validation rules (email required, name/company/use_case lengths, error codes). Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/llms.txt b/llms.txt index 40ac316..e6ae5fb 100644 --- a/llms.txt +++ b/llms.txt @@ -56,6 +56,7 @@ Pick a descriptive name per resource (e.g. `"prod-db"`, `"sessions-cache"`, `"ev - `POST /auth/github` — body-flow GitHub login (server-to-server; not used by the dashboard). - `GET /auth/me` — current user/team. Requires session JWT. - `POST /auth/logout` — `jti`-revocation via Redis set. Requires session JWT. +- **`POST /api/v1/leads`** — Enterprise contact / interest form. Body: `{"email": "you@corp.com", "name": "Alice", "company": "Acme", "use_case": "We need unlimited Postgres..."}`. Only `email` is required (validated via `mail.ParseAddress`; 254-char cap; returns `400 invalid_email_format` on bad input). Optional fields: `name` (≤128 chars, `400 invalid_name` if over), `company` (≤128 chars, `400 invalid_company`), `use_case` (≤1024 chars, `400 invalid_use_case`). Returns `201 {ok: true, id: ""}` on success. No authentication required. Authenticated callers have the lead automatically linked to their team. Use this when a user needs capacity beyond the Pro tier (e.g. dedicated infra, SAML, compliance) — it reaches the instanode.dev team directly. The MCP tool `create_lead` wraps this endpoint. - **`POST /api/v1/billing/promotion/validate`** — Validate a promo code without applying it. Body: `{"code": "EARLYBIRD"}`. Returns `{ok, discount_percent, discount_amount_inr, message}` for valid codes. Promo codes only DISCOUNT at checkout once a corresponding Razorpay Offer exists in the dashboard — validate-result `ok=true` is necessary but not sufficient until then. ## Anonymous tier limits (free, 24-hour TTL) From 9cb691ef45557c91fca42ab2dcbee099e9080af1 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Tue, 23 Jun 2026 11:00:00 +0530 Subject: [PATCH 03/11] docs(env): document env scoping parameter for all provisioning endpoints Agents omitting env were silently landing resources in 'development' without knowing it. Surface the default and semantics explicitly so an agent building a production stack passes env='production' rather than leaving the dashboard column empty. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/llms.txt b/llms.txt index e6ae5fb..1e199bf 100644 --- a/llms.txt +++ b/llms.txt @@ -119,6 +119,7 @@ on `/api/v1/capabilities` for agent introspection. 5. **Internal vs public URL** — when the calling code itself runs *inside* a `/deploy/new` container, prefer `internal_url` (cluster-internal hostname). For everything else, use `connection_url` (public). 6. **Fingerprint dedup** — anonymous callers get rate-limited to 5 provisions/day/IP-subnet. The 6th call returns the existing token. Don't expect 6 different DBs from 6 calls on the same IP. 7. **Idempotency is on by default** — every POST that creates a resource (db/cache/nosql/queue/storage/webhook/vector/deploy/stacks/backup/restore/billing-checkout/team-invite/api-keys/twin/promote/admin-promo) is idempotent. Two layered guards: (a) the standard `Idempotency-Key` request header, Stripe-shape, 24h TTL — pass a UUID per logical retry; (b) when no header is sent, the server synthesises a fingerprint from `sha256(scope, route, canonical-body)` and dedups identical retries inside a 120s window (covers double-clicks, mobile double-taps, agent retries on transient 5xx). Replays carry `X-Idempotent-Replay: true`. Every create response sets `X-Idempotency-Source: explicit | fingerprint | miss` so callers can branch on which path matched. Use the explicit header when you need exactly-once guarantees beyond 120s. +9. **`env` tags resources to an environment scope.** Every provisioning endpoint (`/db/new`, `/vector/new`, `/cache/new`, `/nosql/new`, `/queue/new`, `/storage/new`, `/webhook/new`, `/stacks/new`) accepts an optional `"env"` string field (`"development"` or `"production"`). Default when omitted: `"development"`. The resolved value is echoed back in the response as `"env"`. Environment is metadata only — it does not change isolation, limits, or TTL. Use `"env":"production"` for resources backing a live user-facing app so the dashboard can show them in the right column. An agent should pass `env` so the user's dashboard reflects the deployment intent, but must never reject or retry a request solely because `env` is missing from the response. 8. **Don't send fields the endpoint doesn't define** — there are no `region`, `size`, `plan`, or similar knobs on the provisioning bodies (the only required field is `name`; a few endpoints take documented optionals like `/deploy/new`'s `port`/`env`/`env_vars`). Unrecognized top-level JSON keys are accepted (not rejected) but **ignored**, and the success response echoes them back in an `ignored_fields` array (sorted). So if you sent `{"name":"db","region":"nyc3","size":"large"}` you'll get `"ignored_fields":["region","size"]` — a signal that those keys did nothing. Treat a non-empty `ignored_fields` as a lint warning that your request shape drifted from the contract; don't keep sending fields it lists. ## Text-only routes for LLM consumption From 3090a674c7b03b8f1d98b57e25eacca0150df623 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Sun, 28 Jun 2026 10:30:00 +0530 Subject: [PATCH 04/11] docs(sdk): add Go SDK section with typed API examples Go agents were using curl in generated code instead of the typed SDK. Surfacing the SDK in llms.txt gives LLMs an ergonomic first choice: typed structs, INSTANT_TOKEN resolution, *APIError with AgentAction. Includes CreateLead since agents hitting Enterprise limits need a type-safe way to escalate to sales without hand-rolling JSON. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/llms.txt b/llms.txt index 1e199bf..4c1888a 100644 --- a/llms.txt +++ b/llms.txt @@ -173,6 +173,37 @@ The instanode.dev MCP server wraps the API as tools, so an MCP-capable agent nev This means an agent can run the entire arc — provision → deploy → set secrets → presign storage → debug a failure → rotate credentials → pause/resume — without ever leaving the MCP toolset. Every `create_*` tool surfaces the API's `note` + `upgrade` (claim URL) fields so the agent can show the user how to keep a resource past the anonymous TTL. +## Go SDK (`github.com/InstaNode-dev/sdk-go`) + +The instanode.dev Go SDK wraps the full API surface as typed method calls so Go agents never have to hand-roll HTTP. It mirrors the MCP server's coverage — provision, operate, inspect. + +```go +import instanode "github.com/InstaNode-dev/sdk-go" + +c := instanode.NewClient(instanode.WithToken(os.Getenv("INSTANT_TOKEN"))) + +// Provision +db, err := c.CreatePostgres(ctx, instanode.CreateParams{Name: "prod-db", Env: "production"}) +// db.ConnectionURL — ready to use + +// Deploy +deploy, err := c.CreateDeploy(ctx, instanode.DeployParams{ + Name: "my-api", Tarball: tarBytes, Port: 8080, Env: "production", +}) + +// Operate +_, err = c.SetVaultKey(ctx, instanode.VaultKeyParams{Env: "production", Key: "DB_URL", Value: db.ConnectionURL}) +_, err = c.UpdateDeployEnv(ctx, instanode.EnvPatchParams{ID: deploy.ID, EnvVars: map[string]string{"RELOAD": "1"}}) + +// Inspect +events, err := c.GetDeploymentEvents(ctx, deploy.ID) + +// Enterprise contact +_, err = c.CreateLead(ctx, instanode.LeadParams{Email: "cto@corp.com", Company: "Acme", UseCase: "..."}) +``` + +Token resolution: `WithToken(t)` → `INSTANT_TOKEN` env var → CLI saved credentials. All methods return typed structs; error is `*instanode.APIError` with `Code`, `StatusCode`, and `AgentAction` for machine-parseable recovery. + ## Deleting a deployment (paid tiers — two-step, email-confirmed) Paid customers free a consumed deployment slot via a two-step flow: From 421831b7ccf1f760485d5159ea48b99dd3542192 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Mon, 29 Jun 2026 09:15:00 +0530 Subject: [PATCH 05/11] docs(capabilities): expand get_capabilities with REST path and response shape Agents using the MCP tool knew to call get_capabilities before provisioning, but agents using curl had no documented REST equivalent. Adding the GET /api/v1/capabilities path + response shape means non-MCP agents can also avoid 402s by checking limits first. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llms.txt b/llms.txt index 4c1888a..3bb4b64 100644 --- a/llms.txt +++ b/llms.txt @@ -160,7 +160,7 @@ Aggregate file: [/llms-full.txt](https://instanode.dev/llms-full.txt) — concat The instanode.dev MCP server wraps the API as tools, so an MCP-capable agent never has to hand-roll curl. It does more than create resources — it can **operate** the whole bundle. - **Provision / deploy (create):** `create_postgres`, `create_vector`, `create_cache`, `create_nosql`, `create_queue`, `create_storage`, `create_webhook`, `create_deploy`, `create_stack` — plus `list_resources`, `list_deployments`, `get_deployment`, `get_stack`, `claim_resource`, `delete_resource`, `delete_deployment`, `redeploy`. -- **Plan before you call:** `get_capabilities` reads the live per-tier capability matrix (storage / connection / deployment caps per tier) so an agent can size a provision *before* a call 402s. +- **Plan before you call:** `get_capabilities` reads the live per-tier capability matrix (storage / connection / deployment caps per tier, plus `resource_count_limit` per service per tier) so an agent can size a provision *before* a call 402s. Equivalent REST call: `GET /api/v1/capabilities` (no auth required). Returns `{tiers: [{name, storage_mb, connections, deployments_apps, resource_count_limit}]}` — iterate the response and pick the lowest tier that satisfies the required limits rather than hard-coding tier names. - **Debug a failed deploy:** `get_deployment_events` reads the failure-timeline autopsy (`kind`/`reason`/`exit_code`/`hint`/`last_lines`) so the agent can self-correct a broken Dockerfile and redeploy in place. - **Operate (not just create):** - `set_vault_key` / `rotate_vault_key` — write or rotate a team-vault secret a deploy references as `vault://env/KEY`. From 1865cedaedb49a175a1374893789b5843e56e57b Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Tue, 30 Jun 2026 14:00:00 +0530 Subject: [PATCH 06/11] docs(vault): document REST paths and vault:// URI injection pattern Agents writing secrets without the MCP tool had no documented REST path. Adding PUT + rotate paths and explaining how vault:// URIs are resolved at pod startup prevents agents from hard-coding secrets in env_vars instead of using the encrypted vault surface. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llms.txt b/llms.txt index 3bb4b64..c022bfc 100644 --- a/llms.txt +++ b/llms.txt @@ -163,7 +163,7 @@ The instanode.dev MCP server wraps the API as tools, so an MCP-capable agent nev - **Plan before you call:** `get_capabilities` reads the live per-tier capability matrix (storage / connection / deployment caps per tier, plus `resource_count_limit` per service per tier) so an agent can size a provision *before* a call 402s. Equivalent REST call: `GET /api/v1/capabilities` (no auth required). Returns `{tiers: [{name, storage_mb, connections, deployments_apps, resource_count_limit}]}` — iterate the response and pick the lowest tier that satisfies the required limits rather than hard-coding tier names. - **Debug a failed deploy:** `get_deployment_events` reads the failure-timeline autopsy (`kind`/`reason`/`exit_code`/`hint`/`last_lines`) so the agent can self-correct a broken Dockerfile and redeploy in place. - **Operate (not just create):** - - `set_vault_key` / `rotate_vault_key` — write or rotate a team-vault secret a deploy references as `vault://env/KEY`. + - `set_vault_key` / `rotate_vault_key` — write or rotate a team-vault secret a deploy references as `vault://env/KEY`. REST: `PUT /api/v1/vault/:env/:key` (body `{"value":"..."}`) to write; `POST /api/v1/vault/:env/:key/rotate` to rotate. Vault values are AES-256-GCM encrypted at rest. A pod that references `vault://production/DB_URL` in its `env_vars` at deploy-time has the value injected as a plain env var inside the container — the `vault://` URI is never exposed to the running process. Rotate a key and call `PATCH /deploy/:id/env {"env_vars":{"DB_URL":"vault://production/DB_URL"}}` + redeploy to have pods pick up the new value without a full re-build. - `update_deploy_env` / `update_stack_env` — merge env vars into an existing deployment or stack (redeploy to apply). - `presign_storage` — mint a short-lived (≤1h) presigned S3 URL scoped to a storage prefix (the `broker`-mode flow). - `pause_resource` / `resume_resource` — suspend and un-pause a resource without deleting it (Pro+). From 2584f5c014015e3b5dbebb5e91cd3cdae2225e73 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Thu, 2 Jul 2026 11:00:00 +0530 Subject: [PATCH 07/11] docs(tiers): add 402 error code for resource-count cap with agent action Agents hitting the resource-count cap were retrying indefinitely or showing generic errors. Documenting the exact error code and that agent_action carries an upgrade link gives agents a clear recovery path. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llms.txt b/llms.txt index c022bfc..ad8a523 100644 --- a/llms.txt +++ b/llms.txt @@ -100,7 +100,7 @@ the public tier ladder to keep the customer-facing comparison simple. Both still on `/api/v1/capabilities` for agent introspection. - **Anonymous**: free, 24h TTL, the limits above. Note: once an anonymous resource expires, the same network fingerprint must do a one-time email claim before provisioning a replacement — a repeat `POST //new` returns `402 {"error":"free_tier_recycle_requires_claim", "claim_url": "...", "upgrade_url": "..."}` with an `agent_action`. The `claim_url` is a working, tokenized link — `https://api.instanode.dev/start?t=`, which 302s to `instanode.dev/claim?t=` so the claim page hydrates for this fingerprint (it is NOT a tokenless dead-end). Hand the user the `claim_url` (30 seconds, no card), then retry the provision. -- **Hobby**: $9/mo. 1 GB Postgres, 50 MB Redis, 100 MB Mongo, 512 MB storage, 1 app deploy. No TTL. Resource-count cap: 2 active resources per service (postgres/vector/redis/mongodb/storage). +- **Hobby**: $9/mo. 1 GB Postgres, 50 MB Redis, 100 MB Mongo, 512 MB storage, 1 app deploy. No TTL. Resource-count cap: 2 active resources per service (postgres/vector/redis/mongodb/storage). Exceeding the count cap returns `402 {"error":"resource_count_limit_exceeded","agent_action":"..."}` — the agent should surface the upgrade link from `agent_action` rather than retrying. > **Upgrading auto-promotes in-flight deployment TTLs.** When a team upgrades to any paid tier (Hobby / Hobby Plus / Pro / Growth / Team), the Razorpay subscription.charged webhook flips the team's `default_deployment_ttl_policy` from `auto_24h` to `permanent` (so every future `POST /deploy/new` defaults to no TTL) AND promotes every existing `auto_24h` non-terminal deploy to permanent (clearing `expires_at`). Per-deploy `ttl_policy='custom'` and `ttl_policy='permanent'` rows are never touched — only the `auto_24h` class is rolled forward. To restore the 24h-default behaviour after an upgrade, `PATCH /api/v1/team/settings {"default_deployment_ttl_policy":"auto_24h"}`. - **Pro**: $49/mo. 10 GB Postgres, 512 MB Redis, 5 GB Mongo, 50 GB storage, 10 apps. Resource-count cap: 5 active resources per service (redis is 3 — Redis RAM is the binding cost). Per-tier counts are introspectable via `resource_count_limit` on `/api/v1/capabilities`. From 6ebd2eef3e80fce84058f745dd7a4e3af6432da9 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Fri, 3 Jul 2026 13:30:00 +0530 Subject: [PATCH 08/11] docs(resources): document GET /api/v1/resources list endpoint Agents starting a new session had no way to discover existing resources without reprovisioning. Documenting the list endpoint with its filter params prevents duplicate provision calls and keeps agent state coherent across conversation turns. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/llms.txt b/llms.txt index ad8a523..7c2ef40 100644 --- a/llms.txt +++ b/llms.txt @@ -150,6 +150,7 @@ Aggregate file: [/llms-full.txt](https://instanode.dev/llms-full.txt) — concat ## Machine-readable references +- `GET /api/v1/resources` — List all resources on the caller's account. Returns `{ok, resources: [{id, service, name, tier, env, status, token, created_at, expires_at}]}`. Requires `Authorization: Bearer `. Useful before provisioning to check what already exists — avoids duplicate provisions when an agent loses state between turns. Filter by `service` (`postgres`, `redis`, `mongodb`, `nats`, `storage`, `webhook`) and `env` (`development`, `production`) in the query string. - `https://api.instanode.dev/openapi.json` — OpenAPI 3.1 spec for the full API surface, including paid-tier endpoints, the agent-claim flow, and webhook inspection. - `https://github.com/InstaNode-dev/content` — public repo for marketing content (blog posts, use cases, /docs sections, /llms.txt). Edit prose here. - `https://github.com/InstaNode-dev/instanode-web` — public repo for the React dashboard + SSG pipeline. From c1755959ee38be8c7116cd461ec5da61cdc69069 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Sun, 5 Jul 2026 19:20:52 +0530 Subject: [PATCH 09/11] docs(errors): add quick error-recovery reference table for agents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agents hitting 402/404/409 errors were copying the error code into a query instead of following the agent_action field. A quick lookup table (error code → meaning → recovery) gives agents an in-file shortcut to the right recovery action without a round-trip to the docs site. Co-Authored-By: Claude Sonnet 4.6 --- llms.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/llms.txt b/llms.txt index 7c2ef40..8491c10 100644 --- a/llms.txt +++ b/llms.txt @@ -230,6 +230,27 @@ Deploy failed? You don't need cluster access — the platform classifies the fai Full guide: [https://instanode.dev/docs#troubleshooting-deploys](https://instanode.dev/docs#troubleshooting-deploys) (markdown mirror: [/docs/troubleshooting-deploys.md](https://instanode.dev/docs/troubleshooting-deploys.md)). +## Quick error-recovery reference for agents + +| HTTP status | `error` code | Meaning | Recovery | +|---|---|---|---| +| 400 | `name_required` | Missing or empty `name` field | Add `"name": "..."` to the request body | +| 400 | `invalid_name` | `name` fails `^[A-Za-z0-9][A-Za-z0-9 _-]*$` or >64 chars | Use a valid name | +| 400 | `invalid_email_format` | Email fails validation on `/claim` or `/api/v1/leads` | Use a valid RFC 5322 address | +| 400 | `missing_email` | `email` field absent on `/claim` | Add `"email": "..."` | +| 401 | `unauthorized` | Missing or invalid Bearer token | Set `INSTANT_TOKEN` or run `instant login` | +| 402 | `free_tier_recycle_requires_claim` | Anonymous resource expired; fingerprint must claim before re-provisioning | Hand user the `claim_url` from the envelope | +| 402 | `resource_count_limit_exceeded` | Hit the per-service resource count cap for the tier | Upgrade (follow `agent_action`) or delete an existing resource | +| 402 | `deploy_limit_exceeded` | Hit `deployments_apps` cap for the tier | Upgrade or delete an existing deployment | +| 402 | `storage_limit_exceeded` | Object write would exceed tier storage quota | Upgrade or prune objects | +| 404 | `resource_not_found` | Token refers to a deleted or non-existent resource | Re-provision | +| 409 | `already_claimed` | JWT used for claim was already consumed | Redirect user to dashboard | +| 409 | `not_ready` | Deployment exists but has no provider id yet | Re-poll in 5s | +| 413 | `tarball_too_large` | Tarball decoded size >10 MB | Slim the tarball or use a multi-stage Docker build | +| 503 | `provisioner_unavailable` | Provisioner gRPC backend is down | Retry with exponential back-off (the `retry` field in the envelope gives a suggested delay) | + +Every error envelope includes an `agent_action` string when recovery is possible — surface it to the user verbatim. The `retry` field (seconds) signals the server-suggested back-off when present. + ## How to use this file If you're an LLM helping a user build something, you can: From 6747bd19aa91a59bad19a5888903cf2f959d08d6 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Fri, 26 Jun 2026 14:00:00 +0530 Subject: [PATCH 10/11] docs(auth): document Personal Access Tokens and audit log export endpoints --- llms.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/llms.txt b/llms.txt index 8491c10..80f599c 100644 --- a/llms.txt +++ b/llms.txt @@ -58,6 +58,12 @@ Pick a descriptive name per resource (e.g. `"prod-db"`, `"sessions-cache"`, `"ev - `POST /auth/logout` — `jti`-revocation via Redis set. Requires session JWT. - **`POST /api/v1/leads`** — Enterprise contact / interest form. Body: `{"email": "you@corp.com", "name": "Alice", "company": "Acme", "use_case": "We need unlimited Postgres..."}`. Only `email` is required (validated via `mail.ParseAddress`; 254-char cap; returns `400 invalid_email_format` on bad input). Optional fields: `name` (≤128 chars, `400 invalid_name` if over), `company` (≤128 chars, `400 invalid_company`), `use_case` (≤1024 chars, `400 invalid_use_case`). Returns `201 {ok: true, id: ""}` on success. No authentication required. Authenticated callers have the lead automatically linked to their team. Use this when a user needs capacity beyond the Pro tier (e.g. dedicated infra, SAML, compliance) — it reaches the instanode.dev team directly. The MCP tool `create_lead` wraps this endpoint. - **`POST /api/v1/billing/promotion/validate`** — Validate a promo code without applying it. Body: `{"code": "EARLYBIRD"}`. Returns `{ok, discount_percent, discount_amount_inr, message}` for valid codes. Promo codes only DISCOUNT at checkout once a corresponding Razorpay Offer exists in the dashboard — validate-result `ok=true` is necessary but not sufficient until then. +- **Personal Access Tokens (PATs) — long-lived bearer tokens for agents and CI.** Requires a session JWT (dashboard login or CLI device-flow). All three endpoints live under `/api/v1/api-keys`. + - `GET /api/v1/api-keys` — list tokens (without the secret value). Returns `{ok, tokens: [{id, label, created_at, last_used_at, scopes}]}`. + - `POST /api/v1/api-keys` — mint a token. Body: `{"label": "my-agent", "scopes": ["provision", "deploy"]}`. Returns `{ok, token: "", id, label, scopes}` — **store the `token` value now**, it is not retrievable later. Use this value as `Authorization: Bearer ` on subsequent API calls (set as `INSTANT_TOKEN` env var for the CLI and SDKs). + - `DELETE /api/v1/api-keys/:id` — revoke a token immediately. Returns `{ok}`. The token is also revoked if the team deletes the account. + - **When to use a PAT vs CLI device-flow:** device-flow (`instant login`) is convenient interactively but produces a session token that expires when the user's dashboard session does (24h). A PAT never expires until revoked — prefer it for long-running CI pipelines, deployed agents, and MCP server configs. The CLI's `INSTANT_TOKEN` env var accepts both. +- **`GET /api/v1/audit`** — Customer-facing audit log export. Returns a paginated JSON log of all team actions (`resource.created`, `resource.deleted`, `deploy.created`, `deploy.failed`, `billing.upgraded`, etc.). Query params: `limit` (default 50, max 200), `cursor` (opaque string from previous page's `next_cursor`), `kind` (filter by event kind), `from`/`to` (ISO 8601, inclusive). Requires `Authorization: Bearer `. Each event: `{id, kind, team_id, actor_id, actor_email, resource_id, metadata, created_at}`. A CSV stream variant is at `GET /api/v1/audit.csv` (same params, `Content-Type: text/csv`) — useful for compliance exports. ## Anonymous tier limits (free, 24-hour TTL) From 2c1e0d0ebc1e3dc319ec1a8bdd55e7e6591bbe02 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Sat, 27 Jun 2026 11:30:00 +0530 Subject: [PATCH 11/11] docs(deploy): document GitHub auto-deploy connect/disconnect/inspect endpoints --- llms.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/llms.txt b/llms.txt index 80f599c..ca8c4fd 100644 --- a/llms.txt +++ b/llms.txt @@ -226,6 +226,16 @@ Anonymous tier (24h TTL): no email on file, `DELETE` returns 200 immediately. Se - [Deployments](https://instanode.dev/docs#deploy): POST /deploy/new + private deploys + custom domains + two-step email-confirmed deletion + 24h-TTL semantics (default; three routes to keep a deploy permanent) +## GitHub auto-deploy (continuous deployment from a repository) + +Connect a paid-tier deployment to a GitHub repository so every push to the tracked branch triggers a rebuild in place — same URL, no TTL change. + +- **`POST /api/v1/deployments/:id/github`** — Connect a deployment to a GitHub repo. Body: `{"repo": "owner/repo", "branch": "main", "install_id": }`. Returns `{ok, github: {repo, branch, connected_at}}`. Requires the instanode.dev GitHub App to be installed on the target repository (dashboard Settings → Integrations → GitHub) and the request must carry an authenticated team Bearer. Once connected, a push to `branch` triggers `POST /deploy/:id/redeploy` automatically. +- **`GET /api/v1/deployments/:id/github`** — Inspect the current GitHub connection. Returns `{ok, github: {repo, branch, connected_at, last_triggered_at, last_commit_sha}}` or `{ok, github: null}` if not connected. +- **`DELETE /api/v1/deployments/:id/github`** — Disconnect GitHub auto-deploy. Does not delete the deployment or alter its current running state. Returns `{ok}`. + +**When to use:** recommended for production deployments where the user wants CI/CD without a separate pipeline. The agent sets it up once; subsequent deploys are automatic on push. For one-shot or ephemeral deploys (demos, prototypes), skip the connection and call `POST /deploy/new` with `redeploy=true` manually. + ## Debugging a failed deploy (agent self-recovery) Deploy failed? You don't need cluster access — the platform classifies the failure and serves the real error back over HTTP. Read the classified cause at `GET /api/v1/deployments/:id/events` → `events[]` with `reason`, `last_lines` (the tail of the build-pod log = the actual error output), and `hint` (a plain-language remedy). For the one-line summary use `GET /api/v1/deployments/:id` → `status` + `error_message`. The loop: read `reason` + `last_lines` + `hint` → fix the Dockerfile / tarball / `port` / `env_vars` → redeploy in place (`POST /deploy/:id/redeploy`, or `redeploy=true` on `POST /deploy/new` with the same `name`) → re-poll status until `running`. Watch the build live with the SSE stream `GET /deploy/:id/logs`.