NOUKAI

Slug Execution API

Execute flows via their slug URL — sync and async modes.

Base URL: https://api.noukai.xyz/api/v1/seq

Sync Execution

POST /seq/{org}/{project}/{flow}/execute

Blocks until the flow completes and returns the result.

Path Parameters

ParameterDescription
orgOrganization slug
projectProject slug
flowFlow slug

Request Body

{
  "message": "string (required)",
  "parameters": {},
  "attachments": [],
  "block_overrides": {}
}
FieldTypeRequiredDescription
messagestringYesPrimary input text
parametersobjectNoAdditional key-value parameters passed to blocks
attachmentsarrayNoMedia attachments (images). See Attachments below.
block_overridesobjectNoPer-step field overrides (advanced)

The key "attachments" is reserved inside the parameters object. Placing it there returns 400 PARAMETER_NAME_RESERVED. Use the top-level attachments field instead.

Attachments

Pass media into your flow alongside message. Noukai never stores attachment bytes — clients host the file on any HTTPS-reachable URL (their CDN, S3 bucket, Supabase storage, etc.) and pass the URL through.

{
  "message": "Describe what's in this image.",
  "attachments": [
    {
      "kind": "url",
      "url": "https://customer-cdn.example.com/uploads/photo.png",
      "mime_type": "image/png",
      "filename": "photo.png"
    }
  ]
}

Attachment object

FieldTypeRequiredDescription
kindstringYesDiscriminator. Must be "url" in v1.
urlstringYesHTTPS URL where the file is hosted. Must be publicly reachable by OpenRouter.
mime_typestringYesMIME type. Must be in the supported list below.
filenamestringNoDisplay name (≤ 255 chars, no /, \, or ..). Derived from URL path if omitted.

Supported MIME types

MIME typeDescription
image/jpegJPEG images
image/pngPNG images
image/webpWebP images
image/gifGIF images (most models read first frame only)

Limits

LimitValue
Max attachments per request10
Max URL length2048 chars
Max filename length255 chars
URL schemehttps:// only

The block's model must support the attachment's MIME type. If you attach an image but the LLM block uses a non-vision model, the request is rejected with 400 MODEL_MIME_INCOMPATIBLE before execution starts. Use a vision-capable model (e.g. google/gemini-2.0-flash-001, anthropic/claude-sonnet-4-6, openai/gpt-4o) on any block that should see the attachment.

Response (200)

{
  "status": "completed",
  "result": { "..." },
  "flowId": "uuid",
  "blockCount": 3
}
FieldTypeDescription
statusstring"completed", "failed", or "tool_calls_required" (see Tool Calls)
resultanyFlow output (shape defined by output schema)
flowIdstringUUID of the executed flow
blockCountintegerNumber of blocks in the flow

Tool Calls

Let the model call functions in the caller's process, then resume the flow with the tool results. The pattern mirrors the OpenAI Chat Completions tool-call loop: server holds no state between pauses — the caller carries the conversation and echoes it back.

Tool calls are sync-only. /jobs (async) returns 405 TOOLS_REQUIRE_SYNC_EXECUTE if tools is present. SSE-based pause/resume over the queue path is not implemented in v1.

Prerequisites

The target block must be configured with processor_config.tools_enabled: true in the published flow version. If no block in the flow opts in, /execute with tools returns 422 TOOLS_NOT_ENABLED.

Request — fresh call

{
  "message": "Find the weather in Paris and summarize.",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a city.",
        "parameters": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    }
  ],
  "toolChoice": "auto"
}
FieldTypeRequiredDescription
toolsarrayNoTool definitions made available to the model. Max 64 per request.
toolChoicestring | objectNo"auto" | "none" | "required" | {"type":"function","function":{"name":"x"}}

Tool definition

FieldTypeConstraints
typestringMust be "function".
function.namestring1–64 chars, ^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$. Unique within a request.
function.descriptionstring≤ 4096 chars.
function.parametersobjectJSON Schema. Serialized JSON must be ≤ 16 KB.

Paused response (200, status tool_calls_required)

When the model emits tool calls, the flow pauses and the response is:

{
  "status": "tool_calls_required",
  "executionId": "uuid",
  "pausedAtStep": "step-uuid",
  "iterationsUsed": 1,
  "toolCallMessages": [
    { "role": "user", "content": "Find the weather in Paris and summarize." },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc",
          "type": "function",
          "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" }
        }
      ]
    }
  ],
  "toolCalls": [
    { "id": "call_abc", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } }
  ],
  "accumulatedOutputs": {},
  "flowId": "uuid",
  "blockCount": 3
}
FieldTypeDescription
executionIdstringEcho back on the resume call. Stable across pauses.
pausedAtStepstringstep_id of the block that paused. Echo back.
iterationsUsedintegerCumulative tool-call round-trips for this block. Echo back.
toolCallMessagesarrayFull conversation so far. Append role:"tool" results and echo back.
toolCallsarrayConvenience: last assistant message's tool_calls. Same IDs the resume call must answer.
accumulatedOutputsobjectOutputs of blocks completed before the pause. Echo back.

Resume request

Execute the tool calls in your process, then POST back to the same /execute URL:

{
  "executionId": "uuid",
  "pausedAtStep": "step-uuid",
  "iterationsUsed": 1,
  "toolCallMessages": [
    { "role": "user", "content": "Find the weather in Paris and summarize." },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        { "id": "call_abc", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } }
      ]
    },
    { "role": "tool", "tool_call_id": "call_abc", "content": "{\"temp_c\":14,\"sky\":\"cloudy\"}" }
  ],
  "accumulatedOutputs": {},
  "tools": [ /* same tools array as before */ ]
}

Rules on resume:

  • executionId, pausedAtStep, toolCallMessages are all required together.
  • Every id in the prior assistant tool_calls must have a matching role:"tool" message with that tool_call_id. Missing or extra IDs return 400 TOOL_RESULTS_MISMATCH.
  • tools should be re-sent unchanged so the model can call them again on the next turn.
  • Omit message on resume — it is ignored.

The flow may pause again (multi-step tool use) or return status: "completed". Loop until you see completed.

Tool-call limits

LimitValue
Max tools per request64
Max parameters schema size16 KB
Max tool result content per message256 KB
Max toolCallMessages payload1 MB
Default max iterations per block25 (override via block processor_config.max_tool_iterations)

Tool-call error codes

StatusCodeMeaning
400TOOLS_INVALIDBad shape, duplicate name, oversized parameters, or oversized tool result content.
400TOOL_NAME_INVALIDFunction name fails the ^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$ pattern.
400PAUSED_STEP_INVALIDpausedAtStep is not a tools_enabled block in this flow. Body lists valid_steps.
400EXECUTION_ID_INVALIDexecutionId does not match the paused FlowRun.
400TOOL_RESULTS_MISMATCHTool-result IDs don't match the prior assistant tool_calls. Body lists expected and received.
400INVALID_RESUMEResume request is missing one of executionId, pausedAtStep, toolCallMessages.
405TOOLS_REQUIRE_SYNC_EXECUTEtools sent to /jobs (async). Use /execute.
409TOOL_ITERATION_LIMITCumulative iterations reached the block's max_tool_iterations cap. Body includes step_id, iterations_used, cap, and the full messages.
413MESSAGES_TOO_LARGEtoolCallMessages payload exceeds 1 MB.
422TOOLS_NOT_ENABLEDThe flow has no block with tools_enabled: true.
422TOOLS_IN_NON_SEQUENTIAL_STEPThe tools-enabled block is inside a parallel or loop step (not supported in v1).

Async Execution

POST /seq/{org}/{project}/{flow}/jobs

Returns immediately with an execution ID for polling.

The tools field is rejected on this path with 405 TOOLS_REQUIRE_SYNC_EXECUTE. Use /execute for tool calls.

Response (202)

{
  "executionId": "uuid",
  "status": "started",
  "flowId": "uuid",
  "blockCount": 3
}

Poll for Results

GET /seq/{org}/{project}/{flow}/jobs/{executionId}

Returns the current execution state. Poll until status is completed or failed.

Step-Through Execution

For human-in-the-loop UIs, debugging, or "edit step N's output and continue" flows, use the step-through endpoint:

POST /seq/{org}/{project}/{flow}/step

It runs one step per call, streams SSE, and lets the client carry the cursor between calls. See Step-Through Execution API.

Versioned Endpoints

Call a specific version instead of production:

POST /seq/{org}/{project}/{flow}/v{version}/execute
POST /seq/{org}/{project}/{flow}/v{version}/jobs
POST /seq/{org}/{project}/{flow}/v{version}/step

Authentication

Authorization: Bearer nk_live_...

Both API keys and JWT tokens are accepted.

Error Responses

StatusDescription
401Invalid or missing auth token
402Insufficient credits
404Flow not found (bad slug or not published)
422Request validation error
429Rate limited
500Internal execution error

Attachment-specific errors

All return 400 with a structured detail body: {"code": "...", "message": "..."}.

CodeMeaning
PARAMETER_NAME_RESERVEDCaller put "attachments" inside parameters. Move it to the top-level attachments field.
ATTACHMENT_LIMIT_EXCEEDEDMore than 10 attachments in one request.
ATTACHMENT_INVALID_SCHEMEURL is not HTTPS, or is a data: URI.
ATTACHMENT_BLOCKED_HOSTHostname resolves to a private/loopback/link-local IP (SSRF guard).
ATTACHMENT_URL_TOO_LONGURL exceeds 2048 chars.
ATTACHMENT_UNSUPPORTED_MIMEmime_type is not in the supported list.
ATTACHMENT_INVALID_FILENAMEFilename too long, or contains /, \, or ...
ATTACHMENT_UNSUPPORTED_KINDkind other than "url".
MODEL_MIME_INCOMPATIBLEA block's model does not support the attached MIME type. Includes step_id, model, and unsupported_mime for diagnosis.
CAPABILITY_REGISTRY_UNAVAILABLE(503) Model capability registry is temporarily unavailable. Retry.

cURL Example

curl -X POST https://api.noukai.xyz/api/v1/seq/acme-corp/support-bot/classify-intent/execute \
  -H "Authorization: Bearer $NOUKAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "I need help resetting my password", "parameters": {}}'

With attachments

curl -X POST https://api.noukai.xyz/api/v1/seq/acme-corp/support-bot/describe-image/execute \
  -H "Authorization: Bearer $NOUKAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "What is in this screenshot?",
    "attachments": [
      {
        "kind": "url",
        "url": "https://customer-cdn.example.com/uploads/screenshot.png",
        "mime_type": "image/png",
        "filename": "screenshot.png"
      }
    ]
  }'

With tool calls

First call — fresh:

curl -X POST https://api.noukai.xyz/api/v1/seq/acme-corp/support-bot/agent/execute \
  -H "Authorization: Bearer $NOUKAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Weather in Paris?",
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a city.",
        "parameters": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    }],
    "toolChoice": "auto"
  }'

If the response is status: "tool_calls_required", execute the calls locally, then resume:

curl -X POST https://api.noukai.xyz/api/v1/seq/acme-corp/support-bot/agent/execute \
  -H "Authorization: Bearer $NOUKAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "executionId": "11111111-2222-3333-4444-555555555555",
    "pausedAtStep": "step-uuid",
    "iterationsUsed": 1,
    "toolCallMessages": [
      { "role": "user", "content": "Weather in Paris?" },
      { "role": "assistant", "content": null, "tool_calls": [
        { "id": "call_abc", "type": "function",
          "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" } }
      ]},
      { "role": "tool", "tool_call_id": "call_abc",
        "content": "{\"temp_c\":14,\"sky\":\"cloudy\"}" }
    ],
    "tools": [ /* same tools array */ ]
  }'