Direct HTTP access to inference shell.
Base URL
1https://api.inference.shPath prefix
There is none. Routes live at the root of the API host:
1curl https://api.inference.sh/tasks/task_abc123 -H "Authorization: Bearer inf_your_key"Authentication
All requests require an API key in the Authorization header:
1Authorization: Bearer inf_your_api_keyContent Type
1Content-Type: application/jsonResponse format
Every JSON response is an envelope: the resource under data, and messages for any notices the
server attached (level, code, message, optional meta). Errors are
RFC 9457 application/problem+json. Streams (SSE, NDJSON)
carry bare DTOs per event. The official SDKs unwrap data and surface messages through a callback.
Success example (task from POST /run):
1{2 "data": {3 "id": "task_abc123",4 "status": 10,5 "output": { "image": { "uri": "https://..." } }6 },7 "messages": []8}Error example (401):
1{2 "type": "https://api.inference.sh/errors/unauthorized",3 "title": "Unauthorized",4 "status": 401,5 "detail": "Invalid or missing API key"6}Older examples on other pages show the resource without the data wrapper; read it from data.
1curl https://api.inference.sh/tasks/task_abc123 \2 -H "Authorization: Bearer inf_your_key"Error Responses
Errors use Content-Type: application/problem+json with the type, title, status, and detail fields shown above. The type URI ends with the error code (for example .../errors/not_found).
Some errors include an optional meta extension member with structured context — for example entitlement errors (limit_exceeded, feature_not_available) attach resource, limit, current, upgrade_available, and optional addon plan fields. See Entitlements API — Error metadata.
Error Codes
| Code | HTTP | Description |
|---|---|---|
unauthorized | 401 | Invalid or missing API key |
forbidden | 403 | Insufficient permissions |
blocked_by_usage_policy | 403 | Resource is outside the workspace usage policy reach (apps, agents, MCPs, knowledge, flows). Checked before prepaid balance on paid runs — not a credits problem. |
not_found | 404 | Resource not found |
invalid_request | 400 | Malformed request |
rate_limited | 429 | Too many requests |
entitlement_unavailable | 500 | The entitlement lookup failed, so plan limits could not be verified. Retriable. |
internal_error | 500 | Server error |
Pre-authentication access controls
Some requests are rejected before authentication. These responses do not use the problem+json format above:
| Condition | HTTP | Response |
|---|---|---|
| IP blocked for abuse | 403 | { "message": "Access denied. This attempt has been logged. If you believe this is a mistake, please disconnect any VPN or proxy and try again, or contact [email protected]." } |
| Region blocked (sanctions) | 451 | service not available in your region (plain text) |
Both checks apply to almost every route. Some health and status endpoints stay reachable. They are separate from the permission 403 errors (forbidden, feature_not_available) returned after authentication.
Regional blocking uses the request's country and, for some countries, its subdivision. Blocked countries are Cuba, Iran, North Korea, Russia, and Syria. Within Ukraine, Crimea, Sevastopol, Donetsk, and Luhansk are blocked. VPN or proxy exit nodes in a blocked region get the same response.
CORS (browser clients)
Browser fetch from JavaScript needs CORS headers on the response. The API answers in two modes, chosen from the request's Origin header:
| Origin | Access-Control-Allow-Origin | Credentials |
|---|---|---|
The deployment's own app (for example https://app.inference.sh) and any extra hosts configured for that deployment | The matching origin | Allowed (Access-Control-Allow-Credentials: true) |
| Any other origin, whatever the request's auth | Reflects the request origin | Not allowed: cookies are never honoured cross-site, so send an API key in Authorization |
Both modes allow methods GET, POST, PUT, DELETE, OPTIONS, and HEAD, request headers Accept, Authorization, Content-Type, X-CSRF-Token, X-Team-ID, X-Client-Source, and X-API-Version, and expose the response headers Link and Retry-After (see Rate limits below).
Refusals stay readable. CORS runs before middleware that can end the request early: invalid or revoked bearer tokens, suspended accounts, denied impersonation, regional blocks, and IP redlist hits. Those answers carry CORS headers for every origin, so browser code sees the real HTTP status and body instead of an opaque network error.
Signup email restrictions
New accounts cannot use temporary or disposable email domains. The check runs when a new user record would be created, so every sign-up path enforces it:
| Auth path | When the check runs | Error for new signups |
|---|---|---|
Magic link (POST /auth/magic-link/send) | Before the email is sent | disposable_email (400) |
| OAuth sign-in | After the provider redirects back | disposable_email (400) |
| SAML SSO | On first login for a new email | user_creation_failed (500). Use a permanent address and retry. |
Existing accounts are not affected. An account registered on such a domain before the restriction can still sign in.
Stored form: Email addresses on user accounts and pending team invites are stored trimmed and lowercased. Sign-in and account lookup match case-insensitively, so [email protected] and [email protected] resolve to the same account when only one exists. API responses return the stored address.
For Gmail and Googlemail, team invites and membership checks also treat addresses that deliver to the same mailbox as one address (dots in the local part and + tags after the local part are ignored for that comparison). Magic link sign-in uses the same mailbox rules when plus-alias blocking is enabled.
Plus addressing (+ aliases) on magic link: New sign-ups can currently use + in the local part (for example [email protected]). The API may enable stricter checks later to block aliases that would open a separate account (trial-credit abuse). When that enforcement is on, POST /auth/magic-link/send returns invalid_email (400) for a new address whose provider treats + as a distinct mailbox. Gmail and Googlemail are always allowed: those providers fold + tags into one mailbox, and sign-in lands on the canonical account. An address that already has an account is never blocked by the alias rule. OAuth and SAML do not apply the magic-link alias rule.
Billing and plan limits
These billing and plan errors can block API calls:
| Kind | Typical codes | What to check |
|---|---|---|
| Plan limits | limit_exceeded (402), feature_not_available (403) | Subscription tier caps — API keys, storage, concurrent tasks, feature flags |
| Entitlement lookup failure | entitlement_unavailable (500) | Transient server error while reading plan limits. Retry. Not a tier cap. |
| Usage policy | blocked_by_usage_policy (403) | Outside-resource reach and allow/block lists — see Usage policy. On paid runs the API judges policy before balance, so a blocked app never returns payment_required. |
| Prepaid balance | payment_required (402) | Credits for task and agent runs the usage policy already allows |
| Payment method | payment_method_required (402) | A run certain to cost $0 needs a saved payment method when the balance would refuse it; meta.billing_page names the page that adds one. See Billing: free runs. |
Inspect current usage programmatically with GET /entitlements/usage. List entitlement rows (limits and sources) with GET /entitlements. See Entitlements API for response formats and error metadata.
Web app modals
In the inference shell app, entitlement errors with upgrade_available: true open an upgrade modal instead of only surfacing a toast:
| API error | Modal |
|---|---|
limit_exceeded or feature_not_available (tier cap) | Upgrade modal — lists self-serve plans above your current tier |
feature_not_available with addon_plan_id | Add-on purchase modal — shows addon name, price, and subscribe - $X/mo CTA that routes to the add-ons page |
payment_required (402 without upgrade_available) | Top-up modal — add prepaid credits |
For payment_required, credits always go to whoever pays for the selected workspace (the team itself, or the organization workspace for an org member team). If you manage organization billing while switched into a member team, checkout runs against the organization balance and returns to that workspace's billing settings. If the organization pays and you cannot manage its billing, the modal shows the org notice instead of checkout — the same rule as inline add credits controls elsewhere in the app.
The upgrade modal shows the API detail message (or which resource requires a higher plan). For limit_exceeded, it also shows current usage / plan cap (for example 3 / 5) when the cap is greater than zero. A 0 cap means the feature is disabled on your tier — the modal omits a usage line instead of showing 0 / 0.
Each listed plan shows monthly price, included credits, and key limits. The recommended badge marks the cheapest plan that resolves the blocked resource (unlimited, a higher numeric cap, or an enabled boolean feature). Select a plan or View all plans to open settings → workspace → subscription.
When the error includes addon_plan_id, the modal shows a single add-on card with a subscribe - $X/mo button that routes to settings → workspace → add-ons, the same purchase flow as the add-ons page (Stripe Checkout via POST /subscription/addon). Most add-ons do not require a base subscription; some set required_plan_ids on the plan.
Direct links: Pricing (browse plans) · settings → workspace → billing (credits) · settings → workspace → subscription (manage plan) · settings → workspace → add-ons (purchase add-ons)
Description length limits
Create and update endpoints enforce a maximum length on resource description fields. Limits count Unicode characters (runes), not bytes.
| Constant | Max length | Applies to |
|---|---|---|
DescriptionLimitListing | 200 | Apps, agent template versions, flows, workspace MCP servers, and knowledge entries whose type is not skill |
DescriptionLimitSkill | 1024 | Skills (type: skill on knowledge, and skill create/update APIs) — matches the Agent Skills frontmatter limit |
When a new description exceeds the limit, the API returns validation_error (400) with detail such as description must be at most N characters, got M. If an update leaves the description unchanged, the limit is not re-checked — existing text longer than the cap can stay until you edit the field.
Agent-facing reads: Discovery and catalog surfaces clip descriptions to 200 characters for the model: whitespace collapses to a single space and overflow ends with .... This includes /suggest result lines and catalog tools such as search_tools / list_tools. Put longer guidance in the resource body (app README, skill instructions, knowledge content, system prompt).
Client-side validation: JavaScript (@inferencesh/sdk ≥ v0.20.0) exports DescriptionLimitListing and DescriptionLimitSkill; Python (inferencesh ≥ v0.19.0) exports DescriptionLimit.LISTING and DescriptionLimit.SKILL on the DescriptionLimit enum in inferencesh.types.
Web app: On app.inference.sh, description fields for apps, agents, flows, skills, workspace MCP servers, and knowledge entries show a counter (n/limit) under the input and stop accepting characters at the same limits as the API. Knowledge uses the skill limit when type is skill or unset, and the listing limit for other types (same rule as knowledge create/update). Text saved before limits existed may still be longer than the cap; the counter turns red until you shorten it, and you can save other fields without editing the description.
Rate Limits
| Endpoint | Limit |
|---|---|
| Run task | 100/minute |
| Get task | 1000/minute |
| Upload file | 50/minute |
Response headers:
1X-RateLimit-Remaining: 952X-RateLimit-Reset: 16400000003Retry-After: 60Some endpoints (for example magic link send when throttled by IP) return HTTP 429 with a Retry-After header (whole seconds). Browser clients can read it — the API exposes Retry-After in CORS Access-Control-Expose-Headers.
OpenAPI
Download the generated route catalog:
1GET https://api.inference.sh/openapi.jsonOpenAPI 3.1 document listing public paths, methods, and schemas. Useful for client generation and discovering routes not yet covered in these guides. No authentication required.
Cursor pagination
Most list endpoints (GET /tasks, GET /skills, POST /apps/list, GET /chats/:id/messages, and others) use the same cursor-list shape. Send parameters as query strings on GET or in a JSON body on POST …/list.
| Field | Type | Description |
|---|---|---|
limit | integer | Page size (default varies by endpoint — often 10 or 50). Pass -1 to return all matching items in one response without pagination. |
cursor | string | Opaque cursor from next_cursor or prev_cursor (ignored when limit=-1) |
direction | string | forward (default) or backward (ignored when limit=-1) |
sort | array | Sort orders, for example [{ "field": "created_at", "dir": "desc" }] |
filters | array | Filter expressions (field, operator, value) |
search | object | Full-text search (term, fields, …) where supported |
include_others | boolean | Include other users' items in the response, where the endpoint supports it |
include_private | boolean | Workspace owners and admins only. Include every row the selected workspace owns, including members' private resources. Ignored for other roles. Each use is audited. See Workspace admin visibility. |
Workspace admin visibility
By default, list endpoints hide a member's private resources from everyone except the creator. Workspace owners and admins can widen a listing by passing include_private: true (include_private=true in the query string on GET, a JSON body field on POST …/list).
When set, the response includes every row owned by the workspace in the request context: your own private items, other members' private items, and team-visible items. The flag has no effect for the member role, which always gets the standard listing.
Use this when cleaning up a workspace after someone leaves, for example to transfer or delete their private apps, flows, or knowledge. Each include_private list request is audited as team_admin.list_private.
Workspace owners and admins can also read or write an individual member's private resource when the normal permission check would deny access, for example GET /apps/{id} on a departed member's private app. The bypass does not cover running the resource. Each access is audited as team_admin.permission_bypass. Org admins get the same bypass for resources in workspaces attached to their org. Person-owned identity data (exports, sessions, and similar) is never reachable this way.
Response shape
| Field | Type | Description |
|---|---|---|
items | array | Resources for this page (or all matches when limit=-1) |
next_cursor | string | Cursor for the next page |
prev_cursor | string | Cursor for the previous page |
has_next | boolean | More results after this page |
has_previous | boolean | Results before this page |
items_per_page | number | Items in this response |
total_items | number | Total matching items |
Responses may include RFC 8288 Link headers (rel="next", rel="prev") with the same cursors.
Full dumps (limit=-1)
Pass limit=-1 on any cursor-paginated list endpoint to skip pagination and return matching rows in one response (capped at 10,000 rows). Sort and filters still apply; cursor and direction are ignored. has_next is false — treat items as the complete result set when the match count is under the cap.
Use this for exports, migrations, or debugging on smaller datasets. Prefer normal cursor pagination for UI scroll-back and tables that may exceed 10,000 rows.
1curl "https://api.inference.sh/tasks?limit=-1&filters=%5B%7B%22field%22%3A%22status%22%2C%22operator%22%3A%22eq%22%2C%22value%22%3A10%7D%5D" \2 -H "Authorization: Bearer inf_your_key"Endpoints
- Tasks — Run apps, status, logs, timings, telemetry, cancellation, webhooks, cost
- Remotes — Register machines that connect as outbound daemons
- Exec runs — Dispatch commands to remotes and stream output
- Engines — Private engine list, drain, update, stop
- Files — Upload files
- Agents — Agent chat API
- Publications — Publish agents for embedding (
POST /publications) - Embed — Anonymous chat API for published agents
- Triggers — Cron and webhook automation (run agents, apps, flows)
- Skills — Manage and access skills
- Knowledge — Manage knowledge entries
- Artifacts — Publish versioned HTML and Markdown pages to a shareable URL
- Pages — Read CMS pages (docs, blog, landing pages)
- Search — Search apps, skills, knowledge, and pages
- Entitlements — Plan limits, usage, and feature flags
- Streaming — SSE endpoints
- Billing · Subscription — Credits and plan management
- Magic link sign-in · Device authorization: web app and CLI login