Skip to main content

Call Your Agent from Your Product

You built an agent that does the job - in the app, from Claude, or with the SDK. This guide turns it into a backend feature of your own product using four plain HTTPS calls. Every step shows raw curl first and the Python equivalent next to it.

The whole integration is:

  1. Upload a file the run should work on (optional) - get back a public_url
  2. Start a run - a frozen compilation via run-instruction (the production default) or a live agent via run-loop
  3. Poll the execution every ~2 seconds until it reaches a terminal status
  4. Read agent_result
An agent run is not a request-response call

A run takes roughly tens of seconds - the agent plans, calls tools, and assembles a result. Fire and forget from your hot path: the POST that starts the run returns immediately with an execution id. Store that id and poll from a background job. Never make an end-user request wait synchronously on a run.

The contract at a glance

Base URL is https://backend.flymy.ai. Auth is the same X-API-KEY: fly-*** header on every call - get a key at app.flymy.ai/profile.

CallPurpose
POST /api/v1/agents/agent-file-chat-upload/Multipart upload (file, external_id) - returns {"public_url"}
POST /api/v1/agents/tasks/{agent_uuid}/run-loop/Start a run on a live agent with {"variables": {...}} - returns {"id"}
POST /api/v1/agents/compilations/{compilation_id}/run-instruction/Start a run of a frozen compilation with {"variables": {...}} - returns a new run
GET /api/v1/agents/executions/{id}/Current run state - poll until completed / failed, then read agent_result
POST /api/v1/agents/compilations/freeze-instruction/{execution_id}/Freeze a good run into a compilation you can run-instruction from then on

You address a live agent by its UUID - grab it from client.agents.list() in the Python SDK, from the list_agents gateway tool, or from the agent's chat URL in the app (app.flymy.ai/agents/chat/{agent_uuid}).

The running example below is an agent that turns a voice memo into a structured note - upload the audio, run, poll, render the note in your UI.

1. Upload input files (optional)

Skip this step if your run only needs text variables. When the run needs a file from your product - an audio memo, an image, a document - upload it first and pass the returned public_url to the run as a variable.

curl -X POST https://backend.flymy.ai/api/v1/agents/agent-file-chat-upload/ \
-H "X-API-KEY: $FLYMYAI_API_KEY" \
-F "file=@voice-memo.m4a" \
-F "external_id=user-4242"

external_id is an identifier you choose on your side (a user or session id works well). The response carries the field you need:

{"public_url": "https://..."}

2. Start the run

There are two ways to start a run, and they matter differently in production:

  • Frozen compilation (run-instruction) - replays a fixed instruction distilled from a run you approved. Deterministic, cheaper, faster. This is what you want behind a product feature. If you don't have a compilation id yet, see Freeze your agent below.
  • Live agent (run-loop) - the agent re-plans from its goal on every run. Right for interactive use and for producing the good run you will freeze.
# Production default: run a frozen compilation
curl -X POST https://backend.flymy.ai/api/v1/agents/compilations/$COMPILATION_ID/run-instruction/ \
-H "X-API-KEY: $FLYMYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"variables": {"audio_url": "'"$PUBLIC_URL"'"}}'

# Or: run a live agent by UUID
curl -X POST https://backend.flymy.ai/api/v1/agents/tasks/$AGENT_UUID/run-loop/ \
-H "X-API-KEY: $FLYMYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"variables": {"audio_url": "'"$PUBLIC_URL"'"}}'

Both calls return immediately - the run executes asynchronously on the server. The response gives you the execution id (a string slug):

{"id": "won-gsfr-mxp"}

variables are validated against the agent's input_schema and rendered into the goal for this run - see Inputs, Outputs & Variables.

3. Poll until it finishes, read agent_result

Poll GET /api/v1/agents/executions/{id}/ about every 2 seconds until status is terminal (completed, failed, or cancelled), then read agent_result.

EXECUTION_ID="won-gsfr-mxp"

while :; do
RUN=$(curl -s https://backend.flymy.ai/api/v1/agents/executions/$EXECUTION_ID/ \
-H "X-API-KEY: $FLYMYAI_API_KEY")
STATUS=$(echo "$RUN" | jq -r .status)
echo "status: $STATUS"
case "$STATUS" in completed|failed|cancelled) break ;; esac
sleep 2
done

echo "$RUN" | jq .agent_result

A completed execution looks like this (trimmed to the fields you need):

{
"id": "won-gsfr-mxp",
"status": "completed",
"agent_result": {
"title": "Standup notes",
"summary": "Shipped the importer, blocked on billing review...",
"action_items": ["Ping legal about the DPA", "Cut release v2.3"]
}
}

The shape of agent_result is whatever the agent's output_schema defines, so your product code can rely on the fields being there. On failed, the run carries a plain error string instead (surfaced as .error in the SDK) - see Runs for the full lifecycle.

Poll at ~2 seconds, not faster

Runs take tens of seconds; polling every 2 seconds finds the result within moments of it landing. Hammering the endpoint more often does not make the agent finish sooner.

4. Freeze your agent for production

A live agent re-plans on every run - great while you iterate, wasteful once the pipeline is settled. Freezing distills a run you approved into a fixed Markdown instruction that future runs replay: deterministic, cheaper, faster. ("Freeze" and "compile" are the same operation; the SDK surface is client.compilations.)

The flow:

  1. Run the agent live (in the app chat or via run-loop) until one run does exactly what you want.
  2. Freeze that execution:
curl -X POST https://backend.flymy.ai/api/v1/agents/compilations/freeze-instruction/$EXECUTION_ID/ \
-H "X-API-KEY: $FLYMYAI_API_KEY"
  1. The freeze call returns immediately and compilation starts in the background (status begins at pending). The SDK helper compile_from_run wraps the polling; see client.compilations for the lower-level building blocks.
  2. Point your production traffic at run-instruction with the new compilation id (step 2 above).

You can also freeze without touching REST at all: from any MCP client connected to the FlyMy MCPs gateway, the freeze_agent and run_frozen tools do the same thing conversationally.

A frozen endpoint never drifts

A frozen compilation replays a fixed instruction. A model update never changes a frozen endpoint - your product gets the same pipeline tomorrow that you approved today. When you want new behavior, you cut a new version deliberately: freeze a newer run, get a new compilation id, and switch your config when you are ready.

Production notes

Fire and forget from your hot path. The only synchronous call in your request handler is the POST that starts the run - it returns the execution id in milliseconds. Persist the id, return to your user, and let a background worker poll every ~2 seconds until the run lands. Render agent_result when it does.

Runs can pause for approval. If the agent's goal contains approval rules ("ask me before sending anything external"), a run can pause mid-flight and raise an approval request in the app at app.flymy.ai; it resumes after the owner approves. From your product's side this is just a longer-running execution - keep polling and do not treat a slow run as a failure. See Human-in-the-Loop Approvals.

Cost is per run, per use. There is no subscription - each run bills for what it actually used. The gateway tools get_execution_price and list_execution_prices return the real billed cost per run, not an estimate. As a reference point from real bills: a dictation-note pipeline like the example above lands at $0.031 per run.

Schedules instead of on-demand. If the same frozen run should fire on a schedule rather than per request, set a standard 5-field cron expression (plus an optional IANA timezone) on the compilation - compilations.update in the SDK or the schedule_agent gateway tool. The schedule fires per compilation, and each scheduled run appears as a normal execution you can poll like any other. See scheduling in the SDK reference.

Next steps