AI GridDocs
Sign Up

Sandbox products

Your project's private flows — contracts, revisions, HTTP and MCP invocation.

Updated Sep 9, 2026

A sandbox product is a private executable flow owned by exactly one project: a named input/output contract plus a graph of typed nodes, authored in the console's studio without writing code. Its nodes call the products already assigned to that project through the same governed admission and charging path as direct consumption.

A sandbox product is not a published product: it never enters the organization or global catalogue, and (unless it is chat-compatible) never appears in /v1/models. Creating, saving or running one publishes nothing.

POST/v1/sandbox/{id}/invoke
POST/v1/sandbox/{id}/mcp

Contracts#

The contract is a JSON Schema subset: an object whose properties are typed string, number, boolean or object, plus a required list — no nesting, no combinators, no $ref. Image and audio references are object properties with format: "image" or "audio". A select field is a string property with an enum of 1 to 100 unique options; a value outside the list is refused with 422 input_type before any charge, and an empty string counts as not supplied. A select may carry format: "voice", "aspect_ratio", "resolution" or "duration"; the format is an annotation naming what the options are and changes nothing about how a value is validated.

Every read and write requires explicit project consumption authority (project.invoke — a Project Owner or Consumer grant). Owning-team membership and organization administration do not reach a sandbox product, and another project of the same organization receives 404, not 403.

Revisions and activation#

Saving always writes a new revision; a saved revision is never mutated, so an edit cannot change a run already under way. Saves may be marked draft to retain incomplete wiring, and carry a baseRevision for optimistic concurrency — a stale base is refused with 409 revision_conflict.

Activation is separate from saving: it re-validates the whole graph, builds an immutable package (graph, schemas, content digest, runner version, dependency manifest of assigned product ids) and deploys it through the runtime adapter. A failed activation changes nothing — the previously active revision stays active.

HTTP invocation#

bash
curl https://api.aigridapp.com/v1/sandbox/sbx-…/invoke \
  -H "Authorization: Bearer $AIGRID_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Accept: application/x-ndjson" \
  -d '{"input": {"question": "What does this error mean?"}}'
  • The project is the key's bound project; the sandbox product must belong to it, and a selector (X-AIGrid-Project and aliases) may only restate it (403 project_mismatch otherwise, 404 for another project's product).
  • Idempotency-Key is required here (8–128 characters, unlike chat where it is optional). Repeating a key replays the same run and its charges once.
  • The body is {"input": {…}, "revision": n?}. Externally, only the actively deployed revision runs — naming any other is 409 revision_not_active; omit revision to use the active one.
  • The answer is the execution record: status, typed output, node results, the child call ids and chargedMicro. A Failed execution is still returned, with the charges already incurred.

An image answers as an image. A plain bearer call that negotiates no content type — a quick curl — gets the picture itself when the run succeeded and the single output value is a stored image: the asset's own MIME type, Cache-Control: private, no-store, X-Content-Type-Options: nosniff and range support. Everything else still answers with the execution record — Accept: application/json, a streamed NDJSON run, a console execute, a failed run, or any output that is not exactly one image. The run has already settled, so there is no second charge either way.

Progress over NDJSON. Send Accept: application/x-ndjson to receive admitted, node and complete events as the graph executes — completed node records carry durationMs and, for provider calls, remoteMs. Refusals before admission remain normal HTTP error responses. A disconnected client never strands the run: it finishes server-side and settles.

MCP interface#

MCP is opt-in per sandbox product and disabled by default (enabled in the studio or via the console API). When enabled:

  • /v1/sandbox/{id}/mcp speaks the stateless Streamable HTTP transport; GET/DELETE answer 405 after authorization, as that transport requires.
  • It authenticates the same bearer keys and the same project authority.
  • It exposes one tool, invoke_product, whose input/output schema comes from the active immutable revision's contract.
  • Every tool call requires the Idempotency-Key header; a retry with the same key replays the same run and child charges.
  • Output includes structured values plus native image/audio content where the contract produces them.

MCP does not introduce another identity or wallet — it is the same execution path over a different protocol.

Charging#

There is no aggregate parent fee. Each paid node (a product.chat or media node) goes through the same admission, reservation, policy and settlement path as a direct call, produces its own usage record, and charges the project wallet. An execution's chargedMicro is exactly the sum of its child charges. Child calls are idempotent per execution and node, so a resumed or replayed run never charges a completed node twice. If funds run out mid-flow the execution fails and reports the charges already incurred.

Media nodes#

Administrators can publish image and speech products with a declared capability descriptor (kind, aspect ratios, voices, speed, reference-image support) and a fixed per-request price. Sandbox media nodes call them through the platform's provider connection using OpenRouter's image and speech wire shapes; generated bytes are retained as private assets of the project. Media-only products are invoked through sandbox nodes, not through chat completions — the same reservation, settlement and audit path applies per node.

Bounds#

Limit Value
Nodes / edges per flow 50 / 200
Paid product calls per flow 8
Contract fields 20
Value size per port 64 KB
Output size per execution 256 KB
Execution time 5 minutes

Node results persist after each node, so a restarted server resumes from completed work rather than recharging it.

Next#