Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.duvo.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Duvo Public API enables programmatic access to run Assignments from your own applications, scripts, or automation pipelines. Instead of triggering runs through the Duvo web interface, you can integrate Assignments directly into your workflows.

Finding Your Assignment ID

Each Assignment has a unique ID you pass in every API request. The easiest way to find it is in the assignment builder: open your assignment, go to the Setup tab, scroll to the Triggers section, and expand the API Trigger card. It shows a ready-to-run curl example with your assignment’s ID already filled in, so you can copy and paste it straight into a terminal or script. You can also create an API key from the link in that card.

Key Concepts

Assignments: Assignments are configured through the Duvo web interface with a specific SOP, connections, and capabilities. The Public API allows you to start Jobs for them programmatically. To create and manage Assignments via API, see Creating Assignments via API. Builds: A Build is a versioned Setup snapshot for an Assignment. Every time an Assignment is published, a new Build is created. Runs always execute against an Assignment’s latest Build. You can also create Builds via the API to deploy Setup changes programmatically. Runs: A run represents a single execution of an Assignment. When you start a run, the Assignment begins working on its configured task. Runs are asynchronous—the API returns immediately with run information, and you poll for status updates. Sandboxes: Sandboxes are isolated file environments where you can upload files before starting a run. If your Assignment needs to process files (CSVs, documents, images, etc.), you first upload them to a sandbox, then reference that sandbox when starting the run. Human-in-the-Loop (HITL): Some Assignments may require human input during execution. When this happens, the run enters a “waiting” status. You can provide a webhook URL when starting a run to receive notifications when human input is needed, then respond via the API.

Base URL

All API endpoints are available at:
https://api.duvo.ai/v1

Rate Limiting

The API enforces rate limits per API key (300 requests per minute). Rate limit information is included in response headers:
HeaderDescription
x-ratelimit-limitMaximum requests allowed in the window
x-ratelimit-remainingRequests remaining in current window
x-ratelimit-resetUnix timestamp when the window resets
retry-afterSeconds to wait before retrying (when rate limited)
When rate limited, the API returns a 429 Too Many Requests response.

Authentication

All Public API requests require authentication using an API key. API keys are scoped to a team and inherit the permissions of the user who created them.

API Key Format

API keys follow the format dv_<random> (e.g., dv_abc123xyz789...). They are approximately 35 characters long.

Using Your API Key

Include your API key in the Authorization header as a Bearer token:
curl -X GET "https://api.duvo.ai/v1/health" \
  -H "Authorization: Bearer dv_your_api_key_here"

Creating API Keys in the UI

  1. Navigate to Team SettingsAPI Keys in the Duvo web interface
  2. Click Create API Key
  3. Enter a descriptive name for the key (e.g., “Production Pipeline”, “CI/CD Integration”)
  4. Click Create
  5. Copy the key immediately — it will only be shown once and cannot be retrieved later
⚠️ Important: Store your API key securely. Treat it like a password. If you lose it, you’ll need to create a new one.

Managing API Keys

From the API Keys settings page, you can:
  • View all keys for your team, including who created them and when they were last used
  • Delete keys that are no longer needed or may have been compromised
Only team Admins and Owners can create and manage API keys.

Key Security

  • Keys are hashed before storage — Duvo cannot retrieve your full key
  • Keys can be revoked at any time by deleting them
  • The last_used_at timestamp helps you identify unused keys
  • Optional expiration can be set when creating keys programmatically

Endpoints

For Assignment and Build CRUD endpoints, see Creating Assignments via API.

Runs

Start a Run

API: POST /v1/runs — see the API Reference for full details.

Get Run Status

API: GET /v1/runs/{run_id} — see the API Reference for full details.

Get Run Messages

API: GET /v1/runs/{run_id}/messages — see the API Reference for full details.

Post a Message to a Run

API: POST /v1/runs/{run_id}/messages — see the API Reference for full details.

Respond to Human Request

API: POST /v1/runs/{run_id}/human-requests/{request_id}/respond — see the API Reference for full details.

Stop a Run

API: POST /v1/runs/{run_id}/stop — see the API Reference for full details.

Sandboxes

Create a Sandbox

API: POST /v1/sandboxes — see the API Reference for full details.

Get Upload URLs for a Sandbox

API: POST /v1/sandboxes/{sandbox_id}/upload-urls — see the API Reference for full details.

Get Files in a Sandbox

API: GET /v1/sandboxes/{sandbox_id}/files — see the API Reference for full details.

Upload Files to a Sandbox

API: POST /v1/sandboxes/{sandbox_id}/files — see the API Reference for full details.

Error Handling

All errors follow a consistent format:
{
  "error": "Error type",
  "message": "Detailed error description"
}
Common HTTP Status Codes
CodeDescription
400Bad Request — Invalid parameters
401Unauthorized — Missing or invalid API key
403Forbidden — API key doesn’t have access to this resource
404Not Found — Resource doesn’t exist
413Payload Too Large — File exceeds size limit
429Too Many Requests — Rate limit exceeded
500Internal Server Error — Something went wrong on our end
502Bad Gateway — Upstream service unavailable

Webhooks

Human-in-the-Loop Webhook

When you provide a human_request_webhook_url when starting a run, Duvo will POST to that URL whenever the Assignment needs human input. Webhook Payload
{
  "event": "human_request_created",
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "request_id": "req_789xyz",
  "title": "Confirm data deletion",
  "description": "The agent wants to delete 150 records. Please confirm this action.",
  "created_at": "2024-01-15T10:32:00.000Z"
}
When you receive this webhook, use the Respond to Human Request endpoint to provide your response and resume the run.

Complete Example

Here’s a complete example of uploading files and starting a run:
#!/bin/bash
API_KEY="dv_your_api_key"
AGENT_ID="7c9e6679-7425-40de-944b-e07fc1f90ae7"
BASE_URL="https://api.duvo.ai/v1"

# 1. Create a sandbox
SANDBOX_RESPONSE=$(curl -s -X POST "$BASE_URL/sandboxes" \
  -H "Authorization: Bearer $API_KEY")
SANDBOX_ID=$(echo $SANDBOX_RESPONSE | jq -r '.sandbox_id')
echo "Created sandbox: $SANDBOX_ID"

# 2. Upload a file
curl -X POST "$BASE_URL/sandboxes/$SANDBOX_ID/files" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@./input-data.csv" \
  -F "path=/workspace/input-data.csv"

# 3. Start a run with the sandbox
RUN_RESPONSE=$(curl -s -X POST "$BASE_URL/runs" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"agent_id\": \"$AGENT_ID\",
    \"sandbox_id\": \"$SANDBOX_ID\"
  }")
RUN_ID=$(echo $RUN_RESPONSE | jq -r '.run.id')
echo "Started run: $RUN_ID"

# 4. Poll for completion
while true; do
  STATUS_RESPONSE=$(curl -s -X GET "$BASE_URL/runs/$RUN_ID" \
    -H "Authorization: Bearer $API_KEY")
  STATUS=$(echo $STATUS_RESPONSE | jq -r '.run.status')
  echo "Run status: $STATUS"

  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] || [ "$STATUS" = "stopped" ]; then
    break
  fi

  sleep 5
done

echo "Run finished with status: $STATUS"

# 5. Get the conversation messages
curl -s -X GET "$BASE_URL/runs/$RUN_ID/messages?limit=50" \
  -H "Authorization: Bearer $API_KEY" | jq '.messages'