External API v1 — User Guide
Audience: Backend engineers, automation authors, and partners integrating Dagen with CI/CD, n8n/Zapier-style tools, or custom apps.
Overview
External API v1 lives under /api/v1/*. It returns complete JSON responses (no SSE stream). The in-app AI Chat uses Firebase (or your deployment’s UI auth) and typically streams via SSE; the External API uses API keys in the X-API-Key header so servers can call agents and workflows without a browser.
Both paths share the same agent runtime, workflow engine, job / step logging, and billing pipeline—only auth and response shape differ.
Architecture (conceptual)
┌─────────────────────┐ ┌──────────────────────────┐
│ Internal (UI) APIs │ │ External API v1 │
│ e.g. side-chat, │ │ /api/v1/* │
│ workflow UI │ │ │
│ Auth: UI session │ │ Auth: X-API-Key │
│ Response: SSE │ │ Response: JSON body │
└──────────┬──────────┘ └────────────┬─────────────┘
│ │
└─────────────┬───────────────┘
▼
┌─────────────────────────────┐
│ Shared execution layer │
│ Agents, workflows, jobs, │
│ billing, workspace scope │
└─────────────────────────────┘
Authentication
Key format
Keys look like dg_ plus a long random suffix (URL-safe). Only a hash of the key is stored server-side; the plaintext is shown once at creation.
Validation (what the server checks)
- Presents
X-API-Key. - Hash lookup, active flag, not expired, correct scopes for the route.
- Rate limit — sliding window per key (default 60/min, configurable 1–600). With Redis, limits are accurate across workers; without, a per-process fallback applies.
- Usage counters — total requests, last-used timestamp.
- Request context is bound to the key’s workspace and owner for audit and billing.
Rate limit response
HTTP 429 Too Many Requests
{ "error": "Rate limit exceeded", "retry_after_seconds": 60 }
Scopes
| Scope | Endpoints |
|---|---|
agents |
GET /api/v1/agents, POST /api/v1/agent/chat |
workflows |
GET /api/v1/workflows, POST /api/v1/workflow/:id/run, GET /api/v1/workflow/runs/:run_id, POST /api/v1/workflow/runs/:run_id/cancel |
Keys may hold one or both scopes.
Agent endpoints
GET /api/v1/agents
Scope: agents
Returns agents[] with id, name, description, type (builtin | custom), plus workspace_id.
POST /api/v1/agent/chat
Scope: agents
Body
| Field | Required | Description |
|---|---|---|
agent_id |
Yes | From agents list |
message |
Yes | User text |
session_id |
No | Multi-turn continuity |
model_id |
No | Override configured default |
context |
No | Structured extra context for tools |
Response
| Field | Description |
|---|---|
message |
Full assistant text |
session_id |
Pass on next call for history |
agent_id |
Agent that answered |
duration_ms |
Server-side latency |
Behaviour: Runs agent.run synchronously to completion (same logical path as non-streaming UI). Creates Job + JobStep records for Job History. Inputs may include "source": "external_api" for filtering.
Workflow endpoints
GET /api/v1/workflows
Scope: workflows
Query: status optional — draft | active | paused | archived.
Returns id, name, description, status, version, timestamps, last_run_at, etc.
POST /api/v1/workflow/:id/run
Scope: workflows
| Field | Description |
|---|---|
input_data |
JSON inputs for the workflow |
wait |
true = block until done (subject to timeout) |
timeout |
Seconds to wait when wait is true (default 300, max 600) |
- Async (default): HTTP 202 +
run_id→ poll status. - Sync
wait: true: Blocks with adaptive polling until terminal state or timeout.
Runs are attributed to the API key owner; trigger metadata records source: external_api and api_key_id for audit.
GET /api/v1/workflow/runs/:run_id
Scope: workflows
Returns status (pending | running | success | failed | cancelled), input_data, output_data, error_message, duration_seconds, steps[] (node id, name, status, outputs, errors, per-step duration), timestamps.
POST /api/v1/workflow/runs/:run_id/cancel
Scope: workflows
Only pending or running runs; otherwise 400.
Errors
{ "error": "Descriptive message" }
| HTTP | When |
|---|---|
| 400 | Bad body, bad state |
| 401 | Missing/invalid key |
| 403 | Inactive key, expired, wrong scope |
| 404 | Unknown resource |
| 429 | Rate limit |
| 500 | Agent/workflow failure |
Agent failures still update the Job record for debugging.
Billing, history, and workspace isolation
- Billing: Chat calls go through the same usage metering as the UI; the key owner is charged.
- Job History: API sessions appear alongside UI jobs—useful for correlating failures.
- Workspaces: A key is pinned to one workspace; it cannot read another workspace’s agents or workflows.
A2A (Agent-to-Agent) protocol
Dagen implements A2A v0.2.0-style interoperability for ecosystem tools.
| Resource | Notes |
|---|---|
GET /.well-known/agent.json |
Agent Card — public discovery of capabilities and auth expectations. |
POST /a2a |
JSON-RPC with X-API-Key. |
Methods (typical)
| Method | Purpose |
|---|---|
message/send |
Send a message; get a completed Task with Artifacts |
tasks/get |
Poll task status (maps to jobs / workflow runs) |
tasks/cancel |
Cancel running work |
Parts model: messages use parts (TextPart, DataPart). Tasks move submitted → working → completed | failed | canceled. Internal job statuses map to A2A states (e.g. pending → submitted, running → working).
Capability matrix (high level)
| Capability | Status |
|---|---|
Synchronous message/send |
Supported |
| Task lifecycle + artifacts | Supported |
| Text/Data parts | Supported |
Context continuity (contextId) |
Supported |
| Agent Card | Supported |
Streaming message/stream |
Planned |
| Push notifications, file parts | Planned |
The in-app API Management → A2A Protocol tab shows live examples for your deployment.
GitHub PR review (separate from v1 keys)
Git Reviews use per-repo GitHub webhooks and HMAC verification—not the External API key. Flow: create config in /git-reviews → receive webhook URL + secret → GitHub sends PR events → backend verifies signature → agent reviews diff → comment on PR. See Git Reviews.
Related
- API Keys — Create, rotate, scopes
- Building Pipelines — Workflow designer
- AI Chat — Interactive streaming counterpart