DaytonaDocs

Invoking Functions

Call a function synchronously, spawn it asynchronously, or fan out with map.

Once a function is deployed, you invoke it on demand. Daytona resolves the function's current version, routes your payload to a warm instance (starting one if needed), and records the invocation. There are three ways to invoke, differing only in how you wait for the result: a synchronous invoke that holds the connection until the handler responds, an async spawn that returns an id to poll, and a map fan-out that submits many payloads at once. All three forward the payload verbatim as the handler's POST / body.

Synchronous invoke

A synchronous invoke sends the payload and blocks until the handler responds or the function's timeout_s elapses, then returns the handler's response body. This is the simplest shape and the right default for interactive callers and request/response tools.

Python
from rlp import Daytona
 
daytona = Daytona()
 
result = daytona.fn.invoke("greet", {"name": "Ada"})
print(result)  # {"greeting": "hello Ada"}
TypeScript
import { Daytona } from '@rlp/sdk'
 
const daytona = new Daytona()
 
const result = await daytona.fn.invoke<{ greeting: string }>('greet', { name: 'Ada' })
cURL
curl -X POST https://api.rl.trydaytona.com/fns/greet/invoke \
  -H "Authorization: Bearer $RLP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Ada" }'

The synchronous response carries a few headers about the invocation: x-rlp-invocation-id (the invocation's id), x-rlp-fn-status (the handler's own HTTP status), and x-rlp-cold (1 if this invocation paid a cold start, 0 if it reused a warm instance).

Note: If no instance is available and Daytona can't place one within its queue budget (about 30 seconds), the invoke returns 429 with a Retry-After: 5 header. Treat this as backpressure and retry.

Async spawn

An async spawn returns immediately with an invocation id and a pending status, then runs the invocation in the background. Use it for long-running work you don't want to hold a connection for, or when you want to kick off work and check back later. You retrieve the outcome by polling GET /invocations/:id until it reaches a terminal status.

Python
job = daytona.fn.spawn("greet", {"name": "Ada"})
inv = daytona.fn.get_invocation(job["invocation_id"])
while not inv["done"]:
    inv = daytona.fn.get_invocation(job["invocation_id"])
print(inv["status"], inv["result"])
TypeScript
const { invocation_id } = await daytona.fn.spawn('greet', { name: 'Ada' })
let inv = await daytona.fn.getInvocation(invocation_id)
while (!inv.done) inv = await daytona.fn.getInvocation(invocation_id)
console.log(inv.status, inv.result)

An invocation's status moves through pendingrunning → a terminal state: succeeded, failed, timeout, or shed (shed means it couldn't be placed within the queue budget). The done field is true once terminal.

Note: For a spawned invocation, the result is retrievable through polling only when it is at most 256 KiB and JSON-parseable. Larger async results are not stored for retrieval in this version — return a reference (for example, an object-store key) instead, or use a synchronous invoke, which streams the body back live.

Map fan-out

map submits a batch of payloads in a single call and runs them as parallel invocations — one per payload. It returns the invocation ids up front so you can poll each result independently. This is the fan-out primitive for batch jobs, agent swarms, and parallel rollouts.

Python
batch = daytona.fn.map("greet", [{"name": "Ada"}, {"name": "Alan"}, {"name": "Grace"}])
for inv_id in batch["invocation_ids"]:
    inv = daytona.fn.get_invocation(inv_id)
    # poll each until inv["done"]
TypeScript
const { invocation_ids, count } = await daytona.fn.map('greet', [
  { name: 'Ada' },
  { name: 'Alan' },
  { name: 'Grace' },
])
cURL
curl -X POST https://api.rl.trydaytona.com/fns/greet/map \
  -H "Authorization: Bearer $RLP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "payloads": [ {"name":"Ada"}, {"name":"Alan"}, {"name":"Grace"} ] }'

A single map call accepts up to 1000 payloads; for larger batches, issue multiple calls. Each payload becomes its own invocation you poll with get_invocation, exactly like a spawn.

Payload limits

The invocation payload — the body you send to invoke, spawn, or each entry in a map — is capped at about 6 MiB. Keep payloads to references and small structured data; move large inputs and outputs through object storage and pass keys.

For the full request and response shapes, headers, and error codes, see the Functions API reference.

On this page