Skip to content
← All docs

niyra_execute — long-running tasks

Tell Niyra to actually do something. Spawn-on-timeout pattern keeps short tasks synchronous and long ones polled.

niyra_execute

The "do this for me" tool. Unlike niyra_ask, niyra_execute is allowed to invoke Niyra's full tool registry — email, calendar, web search, integrations, code execution, you name it.

When to use

  • "Email Sarah and ask if next Tuesday at 3pm works for the kickoff."
  • "Pull the Linear tickets tagged P0 and summarize them."
  • "Research recent funding rounds in Series B vertical SaaS and draft a brief."

If the request is just "what is X" — that's niyra_ask.

Endpoint

MethodPathAuthScope
POST/v1/public/executeBearer token (PAT or OAuth)niyra:execute

MCP equivalent: POST /mcp with method tools/call, name niyra_execute.

Request

{
  "instruction": "Email sarah@acme.com and propose Tuesday 3pm for the kickoff.",
  "conversation_id": "optional-uuid",
  "approval_mode": "auto",
  "channel_context": "from my CI pipeline"
}
FieldTypeRequiredNotes
instructionstringyesWhat you want Niyra to do. Max 8000 chars.
conversation_iduuidnoPin to a thread for context continuity.
approval_modeenumnoauto (default — Niyra decides), dry_run (plan only, no side effects), confirm (return a plan; second call with confirmed_task_id to execute)
channel_contextstringnoWhere this request came from — colors Niyra's tone.

Response — synchronous case

Returned when the work finishes inside the 60-second window:

{
  "result": "Sent. Sarah replied that Tuesday works — confirmed for 3pm.",
  "conversation_id": "8f3b…",
  "task_id": "task_xyz",
  "tools_used": ["gmail_send", "gmail_read"],
  "elapsed_ms": 8420,
  "terminal": true
}

Response — spawn-on-timeout case

When the work crosses 60 seconds, the same request returns:

{
  "result": null,
  "conversation_id": "8f3b…",
  "task_id": "task_xyz",
  "status": "running",
  "elapsed_ms": 60000,
  "terminal": false
}

Poll GET /v1/public/tasks/{task_id} until terminal: true. The task keeps running on Niyra's side regardless of whether you poll — losing the connection doesn't lose the work.

Code examples

curl

curl -X POST https://api.niyra.ai/v1/public/execute \
  -H "Authorization: Bearer pat_…" \
  -H "Content-Type: application/json" \
  -d '{
    "instruction": "Summarize the Linear tickets tagged P0 this week."
  }'

JavaScript with polling

async function niyraExecute(instruction, token) {
  const start = await fetch("https://api.niyra.ai/v1/public/execute", {
    method: "POST",
    headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
    body: JSON.stringify({ instruction }),
  }).then((r) => r.json());

  if (start.terminal) return start.result;

  // Poll every 3s, give up after 10 minutes.
  for (let i = 0; i < 200; i++) {
    await new Promise((r) => setTimeout(r, 3000));
    const tick = await fetch(
      `https://api.niyra.ai/v1/public/tasks/${start.task_id}`,
      { headers: { Authorization: `Bearer ${token}` } }
    ).then((r) => r.json());
    if (tick.terminal) return tick.result;
  }
  throw new Error("Task did not terminate within 10 minutes");
}

Approval modes

ModeWhat happens
autoNiyra plans and executes in one shot. Default.
dry_runReturns the plan Niyra would execute, with no side effects. Useful for previewing before committing.
confirmReturns a plan with a pending_task_id. Send a second execute call with confirmed_task_id: <id> to run it.

Errors

StatusCodeMeaning
400invalid_requestEmpty instruction, too long, or invalid approval_mode
401invalid_tokenToken revoked/expired/unknown
403insufficient_scopeToken lacks niyra:execute
403tool_disabledNiyra refused to run a tool the user has disabled in Settings → Skills
429rate_limit_exceededPer-token budget exhausted

Related

FAQ

What's the difference from niyra_ask?
niyra_ask answers questions. niyra_execute *does* things — sends emails, files tickets, schedules meetings, runs research. It's the tool that picks up other tools.
How does the timeout work?
60-second initial window. If the work finishes inside it, you get the result inline. If not, the same request returns a task_id and the work continues in the background — poll niyra_get_task.
For AI:.md.txt