# Conversations
Source: https://datagen.dev/api-reference/agent-api/conversations
Resume, fork, list, share, and delete agent conversations
Conversation state lives on the server. You send one new user message per call and
identify the thread with `metadata.conversation_id`; the agent resumes its full
prior context — including files it wrote and what it learned — without you
replaying any history.
Examples use DataGen Cloud (`https://api.datagen.dev`). Self-hosted installs
swap in their own host, e.g. `http://10.0.0.42:3001` — see
[Base URL](/api-reference/agent-api/overview#base-url).
***
## Resuming
Call `/v1/messages` with no `conversation_id`. Read the
**`X-Conversation-Id`** response header — or supply your own id up front and
skip this step entirely.
```bash theme={null}
curl -N -X POST "https://api.datagen.dev/api/agents/data-agent/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5",
"stream": true,
"metadata": {"conversation_id": "support-ticket-4821"},
"messages": [{"role": "user", "content": "Now draft a reply to the customer."}]
}'
```
**Bring your own id.** An id that doesn't exist yet is created with exactly the
string you sent — it doesn't have to be a UUID. Derive it from your ticket
number, Slack thread, or user id and you never have to store a mapping table.
**Don't send the next turn the instant the stream ends.** A turn's stream closes
a few seconds before the server finishes recording which session the
conversation now points at. A message sent inside that window resumes a
conversation with no session recorded yet, and the agent answers with no memory
of the turn that just happened — no error, just amnesia.
A person typing the next message never notices. An automated client does, every
time. Before resuming a conversation you just ran a turn on, poll
`GET /conversations/{id}` until `claude_session_id` is non-null:
```bash theme={null}
until curl -s "$BASE/api/agents/$AGENT/conversations/$ID" -H "X-Api-Key: $KEY" \
| jq -e '.conversation.claude_session_id' >/dev/null; do sleep 0.25; done
```
Bound the wait and proceed anyway if it expires — a turn that produced no output
legitimately has no session id.
### How an id resolves
| `conversation_id` | Result |
| ----------------------------------------- | ---------------------------------------------------- |
| Omitted | New conversation; id returned in `X-Conversation-Id` |
| Unknown id | Created with that id, verbatim |
| Yours, on this agent | Resumes |
| Belongs to a different agent or workspace | `404 Conversation not found` |
| Someone else's, not shared | `404` — existence is never leaked |
| Someone else's, shared with the workspace | `403` — readable, not writable. Fork it. |
### Durability
Transcripts are stored durably, so a conversation resumes days or weeks later. The
agent's sandbox is kept warm for a while after each turn and then reclaimed;
resuming after that costs a slower first turn but loses no context.
If a turn ends without producing any output while resuming, the resume pointer
is cleared so the next turn starts a clean session instead of silently returning
nothing forever. Retrying a "silent" conversation is the right move.
***
## Forking
Branch a conversation to explore an alternative without disturbing the original.
```bash theme={null}
curl -X POST \
"https://api.datagen.dev/api/agents/data-agent/conversations/{parent-id}/fork" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"at_turn": 2}'
```
```json theme={null}
{
"conversation_id": "ff3feac1-7da5-48ac-91ca-0064ec9eaa96",
"parent_conversation_id": "8bb802a6-a001-48d2-8b70-d9c01536c6bc",
"forked_at_turn": 2,
"claude_session_id": "6210add3-d666-4474-a6f8-45ee74d536a4"
}
```
| Body field | Default | Notes |
| ---------------------- | -------------- | ------------------------------------------------------------------- |
| `at_turn` | all turns | Copy history up to this turn. Clamped to the conversation's length. |
| `conversation_id` | auto-generated | Mint the child with your own id. `409` if it's taken. |
| `model` / `automation` | inherited | Defaults recorded on the child for its future turns. |
The child is owned by you and private by default. Its first turn answers from the
parent's context, then continues on its own branch — the parent is untouched.
***
## Managing conversations
All routes are under `/api/agents/{agent}/conversations` and use the same
authentication. You can see conversations that are yours, shared with the
workspace, or channel-owned (Slack, email).
| Method | Path | Purpose |
| -------- | ------------------------------ | ------------------------------------------------------------------------- |
| `GET` | `/conversations` | List, newest activity first |
| `GET` | `/conversations/{id}` | Metadata for one conversation |
| `GET` | `/conversations/{id}/messages` | Full transcript |
| `POST` | `/conversations/{id}` | Share toggle — body **must** be `{"shared": true}` or `{"shared": false}` |
| `POST` | `/conversations/{id}/fork` | Branch (above) |
| `DELETE` | `/conversations/{id}` | Delete. `204 No Content` |
List query parameters: `channel` (`INTERACTIVE`, `NOTEBOOK`, `SLACK`, `EMAIL`),
`channel_id`, `notebook_path`, `automation=`, `since=`, and
`limit` (1–200, default 50).
```json theme={null}
{
"conversations": [
{
"id": "support-ticket-4821",
"title": "Summarize yesterday's failed runs",
"channel": "INTERACTIVE",
"shared": false,
"is_owner": true,
"claude_session_id": "5a3e26ed-…",
"parent_conversation_id": null,
"forked_at_turn_index": null,
"created_at": "2026-07-31T16:09:28.503Z",
"updated_at": "2026-07-31T16:09:44.930Z",
"turn_count": 1
}
]
}
```
`title` is derived from the first prompt when the conversation is created and
never re-stamped, so it always names the original question.
### Transcript
`GET /conversations/{id}/messages` returns the conversation metadata, an
Anthropic-shaped `messages[]` array, and a raw `events[]` array for callers that
want the underlying agent event stream.
```json theme={null}
{
"conversation": { "…": "…" },
"messages": [
{
"role": "user",
"content": [{"type": "text", "text": "Summarize yesterday's failed runs"}],
"author_user_id": "14d6cade-…",
"author_name": "alex@example.com"
},
{ "role": "assistant", "content": [{"type": "text", "text": "Three runs failed…"}] }
],
"events": []
}
```
Long conversations are compacted automatically by the agent runtime. A compaction
appears as a `user` message flagged `is_compact_summary: true` — render it as a
"context compacted" notice rather than a user turn. `GET
/conversations/{id}/last-compaction` returns `{compacted, summary}` so a client
can tell an empty turn apart from a compaction step.
### Sharing and ownership
Conversations are private to their creator until shared. Sharing grants **read**
access to the workspace — never write: a member who opens a shared conversation
can read it and fork it, but sending a turn into it returns `403`. Only the owner
can toggle sharing or delete, with no admin override.
# Errors & Limits
Source: https://datagen.dev/api-reference/agent-api/errors
Status codes, error shapes, timeouts, and concurrency guidance for the Agent API
## Error shape
Errors before the stream opens are JSON, in Anthropic's shape:
```json theme={null}
{ "error": { "type": "not_found_error", "message": "Agent not found in this workspace" } }
```
Errors *after* the stream opens arrive as an SSE event on an already-`200`
response:
```
event: error
data: {"type":"error","error":{"type":"api_error","message":"…"}}
```
A `200` status only means the turn started. Always handle `error` events, and
treat a stream that ends without `message_stop` as a failed turn.
***
## Status codes
| Status | `error.type` | Cause | Fix |
| ------ | ----------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| `400` | `invalid_request_error` | Missing body, empty `messages`, or no user-role text in `messages` | Send a non-empty `messages` array with at least one `role: "user"` entry |
| `401` | `authentication_error` | Missing, unknown, or malformed key | Check the `X-Api-Key` header |
| `401` | — | `{"message": "API key has been revoked"}` | Create a new key |
| `401` | credential error | The agent has no usable LLM credential | Add the agent's model credential in the workspace |
| `403` | `permission_error` | Viewer role, or writing to a shared conversation you don't own | Use an Operator+ key; fork the conversation |
| `404` | `not_found_error` | `Agent not found in this workspace` | Check the agent slug **and** that the key belongs to the agent's workspace |
| `404` | `not_found_error` | `Conversation not found` | The id belongs to another agent, workspace, or user |
| `404` | HTML page | Wrong HTTP verb (`GET` on `/v1/messages`) | Routes are method-specific — use the documented verb |
| `409` | `conflict_error` | Fork target id already taken | Omit `conversation_id` on fork, or pick a new one |
| `413` | — | Request body over 15 MiB | Reduce attachment size (10 MiB decoded cap) |
| `501` | `not_implemented` | `metadata.delivery: "async"` | Use webhooks or schedules for background runs |
Agent lookup is scoped to the calling key's workspace, and a miss is reported
the same way whether the agent doesn't exist or lives somewhere you can't see —
so no caller can probe for agent names in other workspaces. If you're sure the
name is right, the key is almost always the problem.
***
## Limits and timing
| | |
| ---------------------- | -------------------------------------------------- |
| **Per-turn ceiling** | 10 minutes of agent execution |
| **Typical short turn** | \~10–20 s, dominated by sandbox and agent startup |
| **Attachments** | 10 files, 10 MiB decoded total, per turn |
| **Request body** | 15 MiB |
| **Rate limit** | None on this endpoint — bound concurrency yourself |
A long-running turn that is producing output or doing tool work stays alive; the
runtime only cancels a turn that has genuinely lost its network or exceeded the
ceiling. A turn cancelled that way keeps its resume pointer, so sending
`"continue"` on the same conversation picks up where it stopped.
### Client configuration
* **Set generous timeouts.** Default HTTP client timeouts (30 s) will cut off
normal agent work. Allow at least 10 minutes and read the stream incrementally.
* **Disable buffering proxies.** Any intermediary that buffers responses breaks
streaming. The endpoint sends `Cache-Control: no-cache, no-transform`.
* **Retry on the conversation, not the request.** Because a resumed turn appends
to durable history, a blind retry of a turn that partially succeeded can double
up work. Prefer sending a fresh instruction on the same `conversation_id`.
* **Wait for the resume pointer between back-to-back turns.** Sending the next
message the moment a stream ends can resume a conversation before its session
is recorded, and the agent loses the previous turn's context silently. See
[Resuming](/api-reference/agent-api/conversations#resuming).
### Concurrency
Each conversation runs in one sandbox. Two simultaneous turns on the same
`conversation_id` share it and race on the transcript.
Serialize turns **within** a conversation; parallelize **across** conversations.
A queue keyed by `conversation_id` is the simplest correct client design.
***
## Observability
Every turn records an execution on the agent — status, duration, and result — with
API-key traffic tagged separately from web-UI traffic, so you can filter your
integration's runs on the agent's activity page. Failed turns keep their error
message there, which is usually faster than reconstructing it from the stream.
# Send a Message
Source: https://datagen.dev/api-reference/agent-api/messages
POST /api/agents/{agent}/v1/messages — request body, streaming response, and SDK usage
```
POST {base-url}/api/agents/{agent-name}/v1/messages
```
Runs one agent turn and streams the result back as Anthropic-style
server-sent events.
Examples below use DataGen Cloud (`https://api.datagen.dev`). Self-hosted
installs replace that host with their own server —
`http://10.0.0.42:3001/api/agents/invoice-agent/v1/messages` — and
everything else is identical. See
[Base URL](/api-reference/agent-api/overview#base-url).
***
## Request body
```json theme={null}
{
"model": "claude-haiku-4-5",
"stream": true,
"system": "Extra instructions for this turn.",
"messages": [
{ "role": "user", "content": "Summarize yesterday's failed runs." }
],
"metadata": {
"conversation_id": "support-ticket-4821",
"stream_tool_calls": true
}
}
```
| Field | Type | Required | Notes |
| ---------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `messages` | array | **yes** | Non-empty. Only the newest `role: "user"` text is used. `content` may be a string or an array of `{"type":"text","text":"…"}` blocks (joined with blank lines). Non-text blocks are not read — use `metadata.attachments` for files. |
| `stream` | boolean | no | Send `true`. See the streaming warning on the [overview](/api-reference/agent-api/overview). |
| `model` | string | no | One of the ids from `/v1/models`. Falls back to the automation's model, then the agent's default. |
| `system` | string | no | **Appended to** the agent's own instructions — it never replaces them. |
| `metadata` | object | no | DataGen extensions, below. |
Other Anthropic fields (`max_tokens`, `temperature`, `tools`, …) are accepted and
ignored.
### `metadata`
| Field | Default | Effect |
| ------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `conversation_id` | auto-generated | Resume target. Any string — use your own ticket, thread, or order id. See [Conversations](/api-reference/agent-api/conversations). |
| `stream_tool_calls` | `false` | Surface `tool_use` and `tool_result` blocks in the stream. Leave off for generic Anthropic clients that only expect text. |
| `attachments` | `[]` | Per-turn files, base64. Up to **10 files / 10 MiB decoded**. Written to `.uploads/` in the agent's working directory and announced to the agent. |
| `read_only` | `true` for API-key calls | Repo-backed agents: the repo is readable, but the turn never commits or pushes. Send `false` to let the agent write back — see [Writing to a connected repository](#writing-to-a-connected-repository). |
| `isolated` | `false` | Run in a throwaway sandbox with no repo clone and no workspace files. |
| `automation` | — | Name of an active automation on this agent. Its stored prompt and model become the defaults for this turn; anything you send in the body wins. An unknown name is ignored. |
| `delivery` | `"sync"` | Only `"sync"` is supported. `"async"` returns `501` — use webhooks or schedules for background runs. |
`metadata.builder` runs the turn against the agent builder's working tree
(storage-backed agents only, requires Admin or Builder) and `metadata.test`
marks a new conversation as a hidden test run. Both back the DataGen web UI;
they are not intended for external integrations.
### Writing to a connected repository
**API-key calls are read-only by default.** For an agent backed by a connected
repository, the agent clones and reads the repo but never writes back, unless you
explicitly ask it to.
To let a turn commit its work:
```json theme={null}
"metadata": { "read_only": false }
```
With `read_only: false`, a turn that changes any file ends with `git add -A`, a
commit authored by `datagen-agent`, and a **push to the repository's default
branch** — not to a scratch branch. Send it only for integrations whose whole
purpose is to modify the repository, and consider pointing the agent at a repo
whose default branch is protected.
Storage-backed agents have no repository and never push. Their working files are
restored fresh for each turn and are not written back; the durable output of a
turn is whatever the agent writes to its outputs directory, which is published to
the workspace store.
### Attachments
```json theme={null}
"metadata": {
"attachments": [
{ "name": "leads.csv", "mediaType": "text/csv", "dataBase64": "bmFtZSxkb21haW4K…" }
]
}
```
Base64 only — no `data:` prefix. Filenames are sanitized to a safe basename and
de-duplicated. Malformed entries and anything past the caps are dropped silently,
so validate client-side if a missing file would be a silent failure for you.
Attachments are never committed to a connected repo.
***
## Response
`200 OK`, `Content-Type: text/event-stream`, plus an **`X-Conversation-Id`**
response header — capture it when you didn't supply your own id.
```
event: message_start
data: {"type":"message_start","message":{"id":"msg_…","model":"claude-haiku-4-5","usage":{…}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"…"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"Here's the summary…"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{…}}
event: message_stop
data: {"type":"message_stop"}
```
**Block types.** `text`, `thinking` (with a following `signature_delta`), and —
when `stream_tool_calls` is on — `tool_use` (with `input_json_delta`) and
`tool_result` (carrying `tool_use_id`, `content`, `is_error`). The `tool_result`
block is a DataGen extension; generic Anthropic clients ignore it.
**Granularity.** Blocks arrive whole, not token by token: each is
`content_block_start` + one full `content_block_delta` + `content_block_stop`.
`index` is a running counter for the turn.
**Termination.** The stream ends at `message_stop` — there is no `data: [DONE]`
sentinel.
**Usage.** `message_delta.usage` carries `input_tokens`, `output_tokens`,
`cache_read_input_tokens`, `cache_creation_input_tokens`, and the DataGen-specific
`total_cost_usd` for the turn.
A failure after the stream opens arrives as an SSE `error` event on an
already-`200` response:
`event: error data: {"error":{"type":"api_error","message":"…"}}`.
Check for `error` events, not just the HTTP status.
***
## Examples
```bash cURL theme={null}
curl -N -X POST "https://api.datagen.dev/api/agents/data-agent/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-D - \
-d '{
"model": "claude-haiku-4-5",
"stream": true,
"metadata": {"conversation_id": "support-ticket-4821"},
"messages": [{"role": "user", "content": "Summarize yesterday'\''s failed runs."}]
}'
```
```python Python theme={null}
from anthropic import Anthropic
client = Anthropic(
api_key=DATAGEN_API_KEY,
# no trailing /v1 — the SDK appends it
base_url="https://api.datagen.dev/api/agents/data-agent",
)
with client.messages.stream(
model="claude-haiku-4-5",
max_tokens=1024, # required by the SDK, ignored by DataGen
messages=[{"role": "user", "content": "Summarize yesterday's failed runs."}],
extra_body={"metadata": {"conversation_id": "support-ticket-4821"}},
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print(stream.get_final_message().usage)
```
```typescript TypeScript theme={null}
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.DATAGEN_API_KEY!,
baseURL: "https://api.datagen.dev/api/agents/data-agent",
});
const stream = client.messages.stream({
model: "claude-haiku-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Summarize yesterday's failed runs." }],
// @ts-expect-error DataGen extension
metadata: { conversation_id: "support-ticket-4821", stream_tool_calls: true },
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}
```
`extra_body` (Python) and the cast on `metadata` (TypeScript) exist because the
SDKs type `metadata` as Anthropic's `{user_id}` object. The field is passed
through to DataGen untouched.
### Reading the stream without an SDK
```bash theme={null}
curl -sN … | while IFS= read -r line; do
case "$line" in
'data: '*) printf '%s' "$(printf '%s' "${line#data: }" |
jq -r 'select(.delta.type=="text_delta").delta.text // empty')" ;;
esac
done
```
***
## Model-routed variant
If you'd rather select the agent by model string than by URL path:
```
POST https://api.datagen.dev/api/agents/v1/messages
```
with `"model": "datagen-agent--data-agent"` (or a bare agent slug). Useful when a
client only lets you configure one base URL and switches agents through its model
picker. Everything else is identical.
# Agent API Overview
Source: https://datagen.dev/api-reference/agent-api/overview
Talk to any deployed DataGen agent over an Anthropic-compatible streaming endpoint
Every DataGen agent exposes an Anthropic Messages-compatible endpoint. Point the
official Anthropic SDK — or plain `curl` — at your agent and it answers as a
streaming chat completion.
```
POST {base-url}/api/agents/{agent-name}/v1/messages
GET {base-url}/api/agents/{agent-name}/v1/models
```
`{base-url}` is `https://api.datagen.dev` on DataGen Cloud, or
`http://:3001` if you self-host — see [Base URL](#base-url).
What runs behind it is a full agent session, not a bare model call: your agent's
files and repo, its skills, its MCP tools, and its secrets are all live inside a
sandbox for the duration of the turn.
`{agent-name}` is the agent's slug as shown on its detail page. Repo-backed
agents use `owner-repo` (lowercase, `/` replaced by `-`), e.g.
`datagendev-executive-assistant`. Storage-backed agents use the name you gave
them, e.g. `data-agent`.
***
## Base URL
Every example in this section uses the DataGen Cloud host. **If you self-host,
swap that host for your own server — the paths are identical.**
| Deployment | Base URL |
| -------------------- | ------------------------- |
| DataGen Cloud | `https://api.datagen.dev` |
| Self-hosted | `http://:3001` |
| Self-hosted with TLS | `https://` |
So the same endpoint, on each:
```bash theme={null}
# DataGen Cloud
https://api.datagen.dev/api/agents/invoice-agent/v1/messages
# Self-hosted — your server's IP or hostname, port 3001
http://10.0.0.42:3001/api/agents/invoice-agent/v1/messages
# Self-hosted with TLS — same domain as the web UI, no port
https://datagen.example.com/api/agents/invoice-agent/v1/messages
```
**Port 3001 is the API server, not the web UI.** Your team opens DataGen on
port **3000**; integrations call **3001**. Both are on the same machine. If your
operator changed `WASP_BACKEND_PORT` in `.env`, use that port instead — it is
whatever `WASP_SERVER_URL` in your `.env` points at.
With the TLS deployment profile, a reverse proxy serves the web UI and the API on
one domain and forwards `/api/*` to the API server, so port 3001 is closed to the
network and your base URL is simply your DataGen domain with no port.
Make the base URL a config value in your integration, not a literal. Moving
between cloud and self-hosted, or putting TLS in front of an existing install,
then changes one environment variable instead of every call site.
***
## Your first call
In DataGen, open **Workspace Settings → API Keys** and create a key. Create
it in the **same workspace as the agent** you want to call — the key can
only reach that workspace's agents.
```bash theme={null}
curl -N -X POST "https://api.datagen.dev/api/agents/data-agent/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5",
"stream": true,
"messages": [{"role": "user", "content": "What data sources can you reach?"}]
}'
```
The response carries an `X-Conversation-Id` header. Send it back as
`metadata.conversation_id` on the next call and the agent picks up exactly
where it left off. See [Conversations](/api-reference/agent-api/conversations).
### Two turns, end to end
The whole contract in one copy-pasteable script — ask something, then follow up in
the same conversation:
```bash cURL theme={null}
BASE=https://api.datagen.dev
AGENT=data-agent
turn() { # turn "" [conversation-id]
curl -sN -D /tmp/h -X POST "$BASE/api/agents/$AGENT/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" -H "Content-Type: application/json" \
-d "$(jq -n --arg m "$1" --arg c "${2:-}" '{
stream: true,
messages: [{role: "user", content: $m}],
metadata: (if $c == "" then {} else {conversation_id: $c} end)
}')" |
# Print the assistant text as it arrives.
sed -n 's/^data: //p' | jq -rj 'select(.delta.type == "text_delta") | .delta.text'
}
turn "List the tables you can reach."
CONV=$(grep -i '^x-conversation-id' /tmp/h | tr -d '\r' | awk '{print $2}')
turn "Now show me the row count of the first one." "$CONV"
```
```python Python theme={null}
import json, requests # or use the Anthropic SDK — see Send a Message
BASE, AGENT = "https://api.datagen.dev", "data-agent"
HEADERS = {"X-Api-Key": DATAGEN_API_KEY, "Content-Type": "application/json"}
def turn(message, conversation_id=None):
metadata = {}
if conversation_id:
metadata["conversation_id"] = conversation_id
with requests.post(
f"{BASE}/api/agents/{AGENT}/v1/messages",
headers=HEADERS, stream=True, timeout=(10, 660),
json={"stream": True,
"messages": [{"role": "user", "content": message}],
"metadata": metadata},
) as r:
r.raise_for_status()
for line in r.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
evt = json.loads(line[6:])
if evt.get("delta", {}).get("type") == "text_delta":
print(evt["delta"]["text"], end="", flush=True)
return r.headers["X-Conversation-Id"]
conv = turn("List the tables you can reach.")
turn("Now show me the row count of the first one.", conv)
```
Three things in that script carry the whole contract: `stream: true` on every
request, **one** user message per call (history comes from the conversation, not
the array), and the conversation id read from the response header and sent back.
Sending turns back to back from a script — as above — can outrun the server's
bookkeeping and lose the previous turn's context. Add a short wait between
automated turns; see
[Resuming](/api-reference/agent-api/conversations#resuming).
***
## Three differences from the Anthropic API
The wire format matches Anthropic's, so existing clients connect without changes.
The *semantics* differ in three ways that matter.
**Only the last user message is sent to the agent.** The server reads the newest
`role: "user"` text from `messages[]` and discards the rest. Conversation history
lives on the server — pass `metadata.conversation_id`, don't replay the array.
A three-message array whose first message states a fact and whose last asks about
it will get "I don't know."
**Always stream.** `stream: false` still returns `text/event-stream`. The
official SDKs' non-streaming call (`messages.create()` / `client.messages.create`)
does not raise on the mismatch — it returns a `Message` object filled with
misparsed text. Use `messages.stream()` and its equivalents.
**Sampling parameters are ignored.** The server reads `messages`, `stream`,
`model`, `system`, and `metadata`. `max_tokens`, `temperature`, `top_p`,
`stop_sequences`, `tools`, and `tool_choice` are accepted and dropped —
`max_tokens` is not required. The agent uses its own configured tools; you
cannot inject client-side tool definitions.
And one that has nothing to do with Anthropic's API: an agent can write.
**API-key calls are read-only by default.** An agent backed by a connected
repository reads it but never commits or pushes, unless you send
`metadata.read_only: false` — in which case a turn that changes files pushes a
commit to the repository's default branch. See
[Writing to a connected repository](/api-reference/agent-api/messages#writing-to-a-connected-repository).
***
## Authentication
One header, on every request:
```
X-Api-Key:
```
Create a key in the DataGen app under **Workspace Settings → API Keys**
(`/workspace/settings?tab=apikeys`) — the same page on a self-hosted install.
**The key decides the workspace.** Keys are created inside a workspace and belong
to it, so a key reaches only that workspace's agents — an agent in another
workspace returns `404`, even if you can see it in the web UI. To call an agent
in a team workspace, create the key while that workspace is selected. There is no
header for choosing a workspace per-request.
**The key decides what you may do.** Running a turn requires an **Admin**,
**Builder**, or **Operator** key; a **Viewer** key can read conversations but gets
`403` when it tries to send a message.
A missing or unrecognized key returns `401`; a revoked key returns
`401 {"message": "API key has been revoked"}`.
***
## Models
```bash theme={null}
curl "https://api.datagen.dev/api/agents/data-agent/v1/models" \
-H "X-Api-Key: $DATAGEN_API_KEY"
```
Returns the model ids the agent can run on, with the agent's configured default
first:
```json theme={null}
{
"data": [
{"type": "model", "id": "claude-opus-4-7", "display_name": "Claude Opus 4.7"},
{"type": "model", "id": "claude-sonnet-4-6", "display_name": "Claude Sonnet 4.6"},
{"type": "model", "id": "claude-haiku-4-5", "display_name": "Claude Haiku 4.5"}
],
"has_more": false
}
```
Same auth and error semantics as `/v1/messages`, which makes it a cheap way to
check that an agent name and key work together before sending a real turn.
When you omit `model`, resolution falls back to the automation's model (if you
passed `metadata.automation`), then the agent's default model.
***
## Where to go next
Full request body, SSE event stream, and SDK examples.
Resume, fork, list, share, and delete conversations.
Status codes, timeouts, and concurrency guidance.
# 對話
Source: https://datagen.dev/api-reference/agent-api/zh/conversations
接續、分支、列出、分享與刪除 Agent 對話
對話狀態存在伺服器端。你每次只送出一則新的使用者訊息,並用
`metadata.conversation_id` 指定是哪一段對話;Agent 會還原完整的先前脈絡 —
包含它寫過的檔案與學到的內容 — 你不需要重播任何歷史紀錄。
範例使用 DataGen Cloud(`https://api.datagen.dev`)。自架安裝請換成自己的主機,
例如 `http://10.0.0.42:3001` — 詳見
[Base URL](/api-reference/agent-api/zh/overview#base-url)。
***
## 接續對話
呼叫 `/v1/messages` 時不帶 `conversation_id`。從回應的 **`X-Conversation-Id`**
header 取得 id — 或是一開始就自訂 id,這樣就可以省略這個步驟。
```bash theme={null}
curl -N -X POST "https://api.datagen.dev/api/agents/data-agent/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5",
"stream": true,
"metadata": {"conversation_id": "support-ticket-4821"},
"messages": [{"role": "user", "content": "現在幫我草擬回覆給客戶。"}]
}'
```
**可以自帶 id。** 尚不存在的 id 會以你送出的字串原樣建立 — 不必是 UUID。直接用你
的工單編號、Slack 討論串或使用者 id,就不需要另外維護一張對照表。
**不要在串流結束的瞬間立刻送出下一回合。** 串流關閉的時間,會早於伺服器完成
「這段對話目前對應哪個工作階段」的紀錄數秒。在這個空窗期送出的訊息,會在尚未有
工作階段紀錄的情況下接續對話,於是 Agent 會完全不記得剛才那一回合 —
不會報錯,只是失憶。
人工打字的節奏不會遇到這個問題,但自動化程式每次都會。在接續一段你剛執行過的
對話之前,請輪詢 `GET /conversations/{id}` 直到 `claude_session_id` 不為 null:
```bash theme={null}
until curl -s "$BASE/api/agents/$AGENT/conversations/$ID" -H "X-Api-Key: $KEY" \
| jq -e '.conversation.claude_session_id' >/dev/null; do sleep 0.25; done
```
請設定等待上限,逾時後照常繼續 — 沒有產生任何輸出的回合,本來就不會有工作階段 id。
### id 的解析規則
| `conversation_id` | 結果 |
| ---------------------- | --------------------------------- |
| 未提供 | 建立新對話;id 由 `X-Conversation-Id` 回傳 |
| 不存在的 id | 以該 id 原樣建立 |
| 你自己的、屬於這個 Agent | 接續 |
| 屬於其他 Agent 或 workspace | `404 Conversation not found` |
| 別人的、未分享 | `404` — 不會洩漏其存在 |
| 別人的、已分享至 workspace | `403` — 可讀不可寫。請改用分支。 |
### 持久性
對話紀錄會持久保存,因此數天或數週後仍可接續。Agent 的沙箱在每一回合後會保持
一段時間的熱狀態,之後才回收;超過之後再接續,第一回合會比較慢,但不會遺失任何脈絡。
如果某個接續中的回合完全沒有產生輸出,接續指標會被清除,下一回合會以全新的工作階段
開始,而不是永遠靜默地回傳空白。遇到「沒有回應」的對話時,重試是正確的做法。
***
## 分支(fork)
在不影響原對話的情況下,分支出去探索另一種可能。
```bash theme={null}
curl -X POST \
"https://api.datagen.dev/api/agents/data-agent/conversations/{parent-id}/fork" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"at_turn": 2}'
```
```json theme={null}
{
"conversation_id": "ff3feac1-7da5-48ac-91ca-0064ec9eaa96",
"parent_conversation_id": "8bb802a6-a001-48d2-8b70-d9c01536c6bc",
"forked_at_turn": 2,
"claude_session_id": "6210add3-d666-4474-a6f8-45ee74d536a4"
}
```
| 內容欄位 | 預設值 | 說明 |
| ---------------------- | ----- | ---------------------------- |
| `at_turn` | 全部回合 | 複製到第幾回合為止。超出範圍會自動夾在對話長度內。 |
| `conversation_id` | 自動產生 | 用你自己的 id 建立子對話。已存在則回傳 `409`。 |
| `model` / `automation` | 沿用父對話 | 記錄在子對話上,供其後續回合使用。 |
子對話由你擁有,預設為私有。它的第一回合會延續父對話的脈絡,之後便走自己的分支 —
父對話不受影響。
***
## 管理對話
以下路由都在 `/api/agents/{agent}/conversations` 之下,使用相同的驗證方式。你可以看到
自己的對話、分享給 workspace 的對話,以及頻道所擁有的對話(Slack、Email)。
| 方法 | 路徑 | 用途 |
| -------- | ------------------------------ | ----------------------------------------------------------- |
| `GET` | `/conversations` | 列出,依最近活動排序 |
| `GET` | `/conversations/{id}` | 單一對話的中繼資料 |
| `GET` | `/conversations/{id}/messages` | 完整對話紀錄 |
| `POST` | `/conversations/{id}` | 切換分享狀態 — 內容**必須**是 `{"shared": true}` 或 `{"shared": false}` |
| `POST` | `/conversations/{id}/fork` | 分支(見上) |
| `DELETE` | `/conversations/{id}` | 刪除,回傳 `204 No Content` |
列表查詢參數:`channel`(`INTERACTIVE`、`NOTEBOOK`、`SLACK`、`EMAIL`)、
`channel_id`、`notebook_path`、`automation=<名稱>`、`since=`,以及
`limit`(1–200,預設 50)。
```json theme={null}
{
"conversations": [
{
"id": "support-ticket-4821",
"title": "整理昨天失敗的執行紀錄",
"channel": "INTERACTIVE",
"shared": false,
"is_owner": true,
"claude_session_id": "5a3e26ed-…",
"parent_conversation_id": null,
"forked_at_turn_index": null,
"created_at": "2026-07-31T16:09:28.503Z",
"updated_at": "2026-07-31T16:09:44.930Z",
"turn_count": 1
}
]
}
```
`title` 在對話建立時由第一個提示產生,之後不會再更新,因此它永遠代表最初的問題。
### 對話紀錄
`GET /conversations/{id}/messages` 會回傳對話中繼資料、Anthropic 格式的 `messages[]`
陣列,以及供進階用途使用的原始 `events[]` 事件串流。
```json theme={null}
{
"conversation": { "…": "…" },
"messages": [
{
"role": "user",
"content": [{"type": "text", "text": "整理昨天失敗的執行紀錄"}],
"author_user_id": "14d6cade-…",
"author_name": "alex@example.com"
},
{ "role": "assistant", "content": [{"type": "text", "text": "有三次執行失敗…"}] }
],
"events": []
}
```
較長的對話會由 Agent 執行環境自動壓縮(compaction)。壓縮會以標記
`is_compact_summary: true` 的 `user` 訊息呈現 — 請把它渲染成「脈絡已壓縮」的提示,
而不是一則使用者訊息。`GET /conversations/{id}/last-compaction` 會回傳
`{compacted, summary}`,讓用戶端能分辨「空回合」與「壓縮步驟」。
### 分享與擁有權
對話在分享之前僅限建立者可見。分享會給予 workspace 成員**讀取**權限,永遠不包含寫入:
成員可以開啟並分支一段分享的對話,但送出訊息會得到 `403`。只有擁有者能切換分享狀態或
刪除對話,管理員也無法越權。
# 錯誤與限制
Source: https://datagen.dev/api-reference/agent-api/zh/errors
Agent API 的狀態碼、錯誤格式、逾時與併發建議
## 錯誤格式
串流開始之前發生的錯誤是 JSON,格式與 Anthropic 相同:
```json theme={null}
{ "error": { "type": "not_found_error", "message": "Agent not found in this workspace" } }
```
串流開始**之後**的錯誤,會以 SSE 事件出現在一個已經回傳 `200` 的回應中:
```
event: error
data: {"type":"error","error":{"type":"api_error","message":"…"}}
```
`200` 只代表這一回合已經開始。請務必處理 `error` 事件,並把「沒有以
`message_stop` 結束的串流」視為失敗的回合。
***
## 狀態碼
| 狀態 | `error.type` | 原因 | 處理方式 |
| ----- | ----------------------- | ----------------------------------------- | ------------------------------------------ |
| `400` | `invalid_request_error` | 缺少內容、`messages` 為空,或其中沒有 user 角色的文字 | 送出非空的 `messages`,且至少包含一則 `role: "user"` |
| `401` | `authentication_error` | 金鑰遺失、無法辨識或格式錯誤 | 檢查 `X-Api-Key` header |
| `401` | — | `{"message": "API key has been revoked"}` | 建立新的金鑰 |
| `401` | 憑證錯誤 | 該 Agent 沒有可用的 LLM 憑證 | 在 workspace 中補上 Agent 的模型憑證 |
| `403` | `permission_error` | Viewer 角色,或寫入他人分享的對話 | 改用 Operator 以上的金鑰;或分支該對話 |
| `404` | `not_found_error` | `Agent not found in this workspace` | 確認 Agent 名稱**以及**金鑰是否屬於該 Agent 的 workspace |
| `404` | `not_found_error` | `Conversation not found` | 該 id 屬於其他 Agent、workspace 或使用者 |
| `404` | HTML 頁面 | HTTP 方法錯誤(例如對 `/v1/messages` 發 `GET`) | 路由綁定特定方法,請使用文件標示的方法 |
| `409` | `conflict_error` | 分支目標 id 已存在 | 分支時省略 `conversation_id`,或換一個 |
| `413` | — | 請求內容超過 15 MiB | 縮小附件(解碼後上限 10 MiB) |
| `501` | `not_implemented` | `metadata.delivery: "async"` | 背景執行請改用 webhook 或排程 |
Agent 的查詢會限縮在呼叫金鑰所屬的 workspace 內,而且無論是「Agent 不存在」或
「存在但你看不到」,回報方式都相同 — 這樣就沒有人能藉此探測其他 workspace 的
Agent 名稱。如果你確定名稱正確,問題幾乎都出在金鑰上。
***
## 限制與時間
| | |
| ---------- | -------------------------- |
| **單一回合上限** | 10 分鐘的 Agent 執行時間 |
| **一般短回合** | 約 10–20 秒,主要花在沙箱與 Agent 啟動 |
| **附件** | 每回合 10 個檔案、解碼後共 10 MiB |
| **請求內容** | 15 MiB |
| **速率限制** | 此端點沒有 — 請自行控制併發 |
長時間執行但仍在輸出或使用工具的回合會繼續進行;執行環境只會中止真正失去網路連線、
或超過上限的回合。被這樣中止的回合仍保有接續指標,因此在同一段對話送出「繼續」即可
從中斷處接續。
### 用戶端設定
* **逾時要設寬鬆。** 預設的 HTTP 用戶端逾時(30 秒)會切斷正常的 Agent 工作。請至少
給 10 分鐘,並以串流方式逐步讀取。
* **關閉會緩衝的代理。** 任何會緩衝回應的中介層都會破壞串流。此端點會送出
`Cache-Control: no-cache, no-transform`。
* **重試要以對話為單位,而不是以請求為單位。** 由於接續的回合會附加到持久的歷史紀錄,
盲目重試一個部分成功的回合可能造成重複工作。較好的做法是在同一個
`conversation_id` 上送出新的指示。
* **連續回合之間要等待接續指標。** 在串流剛結束就送出下一則訊息,可能在工作階段尚未
記錄前就接續對話,導致 Agent 靜默地失去上一回合的脈絡。詳見
[接續對話](/api-reference/agent-api/zh/conversations#接續對話)。
### 併發
每一段對話在單一沙箱中執行。對同一個 `conversation_id` 同時送出兩個回合,會共用該沙箱
並在對話紀錄上互相競爭。
同一段對話內請**依序**送出;要平行處理請**跨對話**。用 `conversation_id` 當 key 的
佇列,是最簡單且正確的用戶端設計。
***
## 可觀測性
每一個回合都會在該 Agent 上留下一筆執行紀錄 — 狀態、耗時與結果 — 並且會區分 API key
流量與網頁介面流量,因此你可以在 Agent 的活動頁面上篩選出自己整合的執行。失敗的回合
會保留錯誤訊息,通常比從串流回推更快找到原因。
# 送出訊息
Source: https://datagen.dev/api-reference/agent-api/zh/messages
POST /api/agents/{agent}/v1/messages — 請求內容、串流回應與 SDK 用法
```
POST {base-url}/api/agents/{agent-name}/v1/messages
```
執行一個 Agent 回合,並以 Anthropic 風格的 server-sent events(SSE)串流回傳結果。
以下範例使用 DataGen Cloud(`https://api.datagen.dev`)。自架安裝請把主機換成自己的
伺服器 — 例如
`http://10.0.0.42:3001/api/agents/invoice-agent/v1/messages` — 其餘完全相同。
詳見 [Base URL](/api-reference/agent-api/zh/overview#base-url)。
***
## 請求內容
```json theme={null}
{
"model": "claude-haiku-4-5",
"stream": true,
"system": "這一回合的額外指示。",
"messages": [
{ "role": "user", "content": "整理昨天失敗的執行紀錄。" }
],
"metadata": {
"conversation_id": "support-ticket-4821",
"stream_tool_calls": true
}
}
```
| 欄位 | 型別 | 必填 | 說明 |
| ---------- | ------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `messages` | array | **是** | 不可為空。只有最新的 `role: "user"` 文字會被使用。`content` 可以是字串,或 `{"type":"text","text":"…"}` 區塊陣列(以空行串接)。非文字區塊不會被讀取 — 檔案請改用 `metadata.attachments`。 |
| `stream` | boolean | 否 | 請填 `true`。原因見[總覽](/api-reference/agent-api/zh/overview)的串流警告。 |
| `model` | string | 否 | `/v1/models` 回傳的 id 之一。未指定時依序回退到 automation 的模型、Agent 的預設模型。 |
| `system` | string | 否 | 會**附加**在 Agent 自身的指示之後,不會取代它。 |
| `metadata` | object | 否 | DataGen 的擴充欄位,見下方。 |
其他 Anthropic 欄位(`max_tokens`、`temperature`、`tools` 等)會被接受但忽略。
### `metadata`
| 欄位 | 預設值 | 作用 |
| ------------------- | -------------------- | ----------------------------------------------------------------------------------------------------- |
| `conversation_id` | 自動產生 | 接續的目標對話。可以是任意字串 — 例如你自己的工單編號、討論串 id。詳見[對話](/api-reference/agent-api/zh/conversations)。 |
| `stream_tool_calls` | `false` | 在串流中顯示 `tool_use` 與 `tool_result` 區塊。若用戶端是一般 Anthropic 客戶端(只預期文字),請保持關閉。 |
| `attachments` | `[]` | 這一回合的附件檔案,base64 編碼。最多 **10 個檔案 / 解碼後 10 MiB**。會寫入 Agent 工作目錄下的 `.uploads/`,並在提示中告知 Agent。 |
| `read_only` | 使用 API key 時為 `true` | 以 repo 為來源的 Agent:可讀取 repo,但不會 commit 或 push。傳 `false` 才允許寫回,詳見[寫入連結的 repository](#寫入連結的-repository)。 |
| `isolated` | `false` | 在一次性的沙箱中執行,不 clone repo、不掛載 workspace 檔案。 |
| `automation` | — | 這個 Agent 上某個啟用中的 automation 名稱。它儲存的提示與模型會成為這一回合的預設值;請求本文中的設定優先。名稱不存在則忽略。 |
| `delivery` | `"sync"` | 目前只支援 `"sync"`。`"async"` 會回傳 `501` — 背景執行請使用 webhook 或排程。 |
`metadata.builder` 會在 Agent builder 的工作樹中執行(僅限以儲存空間為來源的
Agent,需要 Admin 或 Builder 權限);`metadata.test` 會把新對話標記為隱藏的測試
執行。兩者是 DataGen 網頁介面在使用的,並非提供給外部整合。
### 寫入連結的 repository
**使用 API key 呼叫時預設為唯讀。** 以 repo 為來源的 Agent 會 clone 並讀取 repo,
但除非你明確要求,否則不會寫回。
若要讓某一回合可以提交它的成果:
```json theme={null}
"metadata": { "read_only": false }
```
當 `read_only: false` 時,只要該回合變更了任何檔案,結束前就會執行 `git add -A`、
以 `datagen-agent` 身分 commit,並 **push 到 repository 的預設分支** — 不是暫存
分支。請只在整合的目的就是修改 repository 時才送出這個設定,並考慮讓 Agent 指向
預設分支受保護的 repo。
以儲存空間為來源的 Agent 沒有 repository,也不會 push。它們的工作檔案在每一回合開始
時重新還原、結束後不會寫回;一個回合的持久產出,是 Agent 寫入 outputs 目錄的內容,
這些會發佈到 workspace 的儲存空間。
### 附件
```json theme={null}
"metadata": {
"attachments": [
{ "name": "leads.csv", "mediaType": "text/csv", "dataBase64": "bmFtZSxkb21haW4K…" }
]
}
```
只接受 base64,不要加 `data:` 前綴。檔名會被正規化為安全的檔名並自動去重複。格式錯誤
的項目、以及超出上限的部分會被靜默捨棄,因此若「缺少檔案」對你而言屬於重大問題,請在
用戶端先行驗證。附件永遠不會被提交到連結的 repository。
***
## 回應
`200 OK`、`Content-Type: text/event-stream`,並帶有 **`X-Conversation-Id`** 回應
header — 若你沒有自訂 id,請記得把它保存下來。
```
event: message_start
data: {"type":"message_start","message":{"id":"msg_…","model":"claude-haiku-4-5","usage":{…}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"…"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"以下是摘要…"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{…}}
event: message_stop
data: {"type":"message_stop"}
```
**區塊型別。** `text`、`thinking`(其後會跟著 `signature_delta`),以及在開啟
`stream_tool_calls` 時的 `tool_use`(伴隨 `input_json_delta`)與 `tool_result`
(帶有 `tool_use_id`、`content`、`is_error`)。`tool_result` 區塊是 DataGen 的擴充,
一般 Anthropic 客戶端會忽略它。
**顆粒度。** 區塊是整塊送達,而非逐 token:每個區塊是
`content_block_start` + 一次完整的 `content_block_delta` + `content_block_stop`。
`index` 是這一回合的遞增計數。
**結束方式。** 串流在 `message_stop` 結束 — 沒有 `data: [DONE]` 結尾標記。
**用量。** `message_delta.usage` 包含 `input_tokens`、`output_tokens`、
`cache_read_input_tokens`、`cache_creation_input_tokens`,以及 DataGen 專屬的
`total_cost_usd`(該回合的美元成本)。
串流開始之後才發生的失敗,會以 SSE `error` 事件出現在一個已經回傳 `200` 的回應中:
`event: error data: {"error":{"type":"api_error","message":"…"}}`。
請檢查 `error` 事件,不要只看 HTTP 狀態碼。
***
## 範例
```bash cURL theme={null}
curl -N -X POST "https://api.datagen.dev/api/agents/data-agent/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-D - \
-d '{
"model": "claude-haiku-4-5",
"stream": true,
"metadata": {"conversation_id": "support-ticket-4821"},
"messages": [{"role": "user", "content": "整理昨天失敗的執行紀錄。"}]
}'
```
```python Python theme={null}
from anthropic import Anthropic
client = Anthropic(
api_key=DATAGEN_API_KEY,
# 結尾不要加 /v1 — SDK 會自動補上
base_url="https://api.datagen.dev/api/agents/data-agent",
)
with client.messages.stream(
model="claude-haiku-4-5",
max_tokens=1024, # SDK 必填,DataGen 會忽略
messages=[{"role": "user", "content": "整理昨天失敗的執行紀錄。"}],
extra_body={"metadata": {"conversation_id": "support-ticket-4821"}},
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print(stream.get_final_message().usage)
```
```typescript TypeScript theme={null}
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.DATAGEN_API_KEY!,
baseURL: "https://api.datagen.dev/api/agents/data-agent",
});
const stream = client.messages.stream({
model: "claude-haiku-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: "整理昨天失敗的執行紀錄。" }],
// @ts-expect-error DataGen 擴充欄位
metadata: { conversation_id: "support-ticket-4821", stream_tool_calls: true },
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}
```
之所以需要 `extra_body`(Python)與型別轉換(TypeScript),是因為 SDK 把
`metadata` 定義成 Anthropic 的 `{user_id}` 物件。這個欄位會原封不動傳給 DataGen。
### 不使用 SDK 讀取串流
```bash theme={null}
curl -sN … | while IFS= read -r line; do
case "$line" in
'data: '*) printf '%s' "$(printf '%s' "${line#data: }" |
jq -r 'select(.delta.type=="text_delta").delta.text // empty')" ;;
esac
done
```
***
## 以模型字串指定 Agent
如果你偏好用模型字串而不是 URL 路徑來選擇 Agent:
```
POST https://api.datagen.dev/api/agents/v1/messages
```
並帶上 `"model": "datagen-agent--data-agent"`(或直接用 Agent 名稱)。當用戶端只能
設定一個 base URL、而透過模型選單切換 Agent 時特別有用。其餘行為完全相同。
# Agent API 總覽
Source: https://datagen.dev/api-reference/agent-api/zh/overview
透過相容 Anthropic 的串流端點呼叫任何已部署的 DataGen Agent
每一個 DataGen Agent 都提供一個相容 Anthropic Messages API 的端點。把官方
Anthropic SDK(或單純用 `curl`)指向你的 Agent,它就會以串流方式回應。
```
POST {base-url}/api/agents/{agent-name}/v1/messages
GET {base-url}/api/agents/{agent-name}/v1/models
```
`{base-url}` 在 DataGen Cloud 是 `https://api.datagen.dev`;自架(self-hosted)
則是 `http://<你的伺服器 IP>:3001` — 詳見下方 [Base URL](#base-url)。
背後執行的是完整的 Agent 工作階段,而不是單純呼叫模型:Agent 的檔案與 repo、
skills、MCP 工具與密鑰,在這一回合期間全部都在沙箱中可用。
`{agent-name}` 是 Agent 詳細頁面上顯示的名稱。以 repo 為來源的 Agent 使用
`owner-repo`(全小寫,`/` 換成 `-`),例如
`datagendev-executive-assistant`;以儲存空間為來源的 Agent 則使用你自己命名的
名稱,例如 `data-agent`。
***
## Base URL
本節所有範例都使用 DataGen Cloud 的網址。**若你是自架,只要把主機換成自己的
伺服器即可,路徑完全相同。**
| 部署方式 | Base URL |
| ------------- | ------------------------- |
| DataGen Cloud | `https://api.datagen.dev` |
| 自架 | `http://<伺服器 IP>:3001` |
| 自架 + TLS | `https://<你的網域>` |
同一個端點在三種部署下的樣子:
```bash theme={null}
# DataGen Cloud
https://api.datagen.dev/api/agents/invoice-agent/v1/messages
# 自架 — 你的伺服器 IP 或主機名稱,連接埠 3001
http://10.0.0.42:3001/api/agents/invoice-agent/v1/messages
# 自架 + TLS — 與網頁介面同一個網域,不需要連接埠
https://datagen.example.com/api/agents/invoice-agent/v1/messages
```
**連接埠 3001 是 API 伺服器,不是網頁介面。** 你的團隊用 **3000** 開啟
DataGen;整合程式呼叫的是 **3001**。兩者在同一台機器上。如果管理者在 `.env`
中改過 `WASP_BACKEND_PORT`,請改用該連接埠 — 也就是 `.env` 裡
`WASP_SERVER_URL` 指向的位址。
若採用 TLS 部署模式,反向代理會在同一個網域上同時提供網頁介面與 API,並把
`/api/*` 轉送到 API 伺服器;此時 3001 不對外開放,base URL 就是你的 DataGen
網域,不需要加連接埠。
請把 base URL 做成設定值,不要寫死在程式碼裡。日後在雲端與自架之間搬移、或替
既有安裝加上 TLS 時,只需要改一個環境變數,而不是每一個呼叫點。
***
## 第一次呼叫
在 DataGen 中開啟 **Workspace Settings → API Keys** 建立金鑰。請在**要呼叫的
Agent 所屬的同一個 workspace** 中建立 — 金鑰只能存取該 workspace 的 Agent。
```bash theme={null}
curl -N -X POST "https://api.datagen.dev/api/agents/data-agent/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5",
"stream": true,
"messages": [{"role": "user", "content": "你能存取哪些資料來源?"}]
}'
```
回應會帶有 `X-Conversation-Id` header。下一次呼叫時把它放進
`metadata.conversation_id`,Agent 就會從上次結束的地方接續。詳見
[對話](/api-reference/agent-api/zh/conversations)。
### 兩回合的完整範例
一段可直接複製執行的腳本,涵蓋整個使用流程 — 先提問,再在同一段對話中追問:
```bash cURL theme={null}
BASE=https://api.datagen.dev
AGENT=data-agent
turn() { # turn "<訊息>" [conversation-id]
curl -sN -D /tmp/h -X POST "$BASE/api/agents/$AGENT/v1/messages" \
-H "X-Api-Key: $DATAGEN_API_KEY" -H "Content-Type: application/json" \
-d "$(jq -n --arg m "$1" --arg c "${2:-}" '{
stream: true,
messages: [{role: "user", content: $m}],
metadata: (if $c == "" then {} else {conversation_id: $c} end)
}')" |
# 逐步印出 Agent 的回覆文字。
sed -n 's/^data: //p' | jq -rj 'select(.delta.type == "text_delta") | .delta.text'
}
turn "列出你可以存取的資料表。"
CONV=$(grep -i '^x-conversation-id' /tmp/h | tr -d '\r' | awk '{print $2}')
turn "第一個資料表有幾筆資料?" "$CONV"
```
```python Python theme={null}
import json, requests # 也可以改用 Anthropic SDK,見「送出訊息」頁
BASE, AGENT = "https://api.datagen.dev", "data-agent"
HEADERS = {"X-Api-Key": DATAGEN_API_KEY, "Content-Type": "application/json"}
def turn(message, conversation_id=None):
metadata = {}
if conversation_id:
metadata["conversation_id"] = conversation_id
with requests.post(
f"{BASE}/api/agents/{AGENT}/v1/messages",
headers=HEADERS, stream=True, timeout=(10, 660),
json={"stream": True,
"messages": [{"role": "user", "content": message}],
"metadata": metadata},
) as r:
r.raise_for_status()
for line in r.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
evt = json.loads(line[6:])
if evt.get("delta", {}).get("type") == "text_delta":
print(evt["delta"]["text"], end="", flush=True)
return r.headers["X-Conversation-Id"]
conv = turn("列出你可以存取的資料表。")
turn("第一個資料表有幾筆資料?", conv)
```
這段腳本中有三個關鍵:每次請求都要 `stream: true`、每次只送 **一則** 使用者訊息
(歷史紀錄來自對話本身,而不是陣列),以及從回應 header 讀出 conversation id 再
帶回去。
像上面這樣由程式連續送出多個回合,可能會快過伺服器的紀錄寫入,導致遺失上一回合
的脈絡。自動化情境請在兩回合之間稍作等待,詳見
[接續對話](/api-reference/agent-api/zh/conversations#接續對話)。
***
## 與 Anthropic API 的三個差異
線路格式與 Anthropic 相同,因此既有的用戶端不必修改即可連線。真正不同的是
**語意**,有三點特別重要。
**只有最後一則使用者訊息會送給 Agent。** 伺服器只讀取 `messages[]` 中最新的
`role: "user"` 文字,其餘一律捨棄。對話歷史存在伺服器端 — 請傳
`metadata.conversation_id`,不要重播整個陣列。若陣列的第一則訊息陳述了某項事實、
最後一則詢問該事實,你只會得到「我不知道」。
**一律使用串流。** 即使 `stream: false`,回應仍然是 `text/event-stream`。官方
SDK 的非串流呼叫(`messages.create()`)並不會因為格式不符而拋出錯誤 — 它會回
傳一個由誤解析文字填充的 `Message` 物件。請使用 `messages.stream()` 或對應的
串流 API。
**取樣參數會被忽略。** 伺服器只讀取 `messages`、`stream`、`model`、`system`
與 `metadata`。`max_tokens`、`temperature`、`top_p`、`stop_sequences`、`tools`
與 `tool_choice` 會被接受但直接捨棄 — `max_tokens` 並非必填。Agent 使用的是它
自己設定的工具,你無法從用戶端注入工具定義。
還有一點與 Anthropic API 無關:Agent 是可以寫入的。
**使用 API key 呼叫時預設為唯讀。** 以 repo 為來源的 Agent 會讀取 repo,但不會
commit 或 push,除非你送出 `metadata.read_only: false` — 屆時只要該回合變更了
檔案,就會把 commit 推送到 repo 的預設分支。詳見
[寫入連結的 repository](/api-reference/agent-api/zh/messages#寫入連結的-repository)。
***
## 驗證
每一次請求都只需要一個 header:
```
X-Api-Key: <你的 api key>
```
請在 DataGen 應用程式的 **Workspace Settings → API Keys**
(`/workspace/settings?tab=apikeys`)建立金鑰;自架安裝也是同一個頁面。
**金鑰決定 workspace。** 金鑰是在 workspace 內建立、並屬於該 workspace,因此只能
存取該 workspace 的 Agent — 呼叫其他 workspace 的 Agent 會得到 `404`,即使你在網
頁介面上看得到它。若要呼叫團隊 workspace 的 Agent,請在選取該 workspace 的狀態下
建立金鑰。沒有任何 header 可以在單次請求中切換 workspace。
**金鑰決定權限。** 執行一個回合需要 **Admin**、**Builder** 或 **Operator** 金鑰;
**Viewer** 金鑰可以讀取對話,但送出訊息時會得到 `403`。
金鑰遺失或無法辨識會回傳 `401`;已撤銷的金鑰回傳
`401 {"message": "API key has been revoked"}`。
***
## 模型
```bash theme={null}
curl "https://api.datagen.dev/api/agents/data-agent/v1/models" \
-H "X-Api-Key: $DATAGEN_API_KEY"
```
回傳這個 Agent 可使用的模型 id,並把 Agent 設定的預設模型排在第一位:
```json theme={null}
{
"data": [
{"type": "model", "id": "claude-opus-4-7", "display_name": "Claude Opus 4.7"},
{"type": "model", "id": "claude-sonnet-4-6", "display_name": "Claude Sonnet 4.6"},
{"type": "model", "id": "claude-haiku-4-5", "display_name": "Claude Haiku 4.5"}
],
"has_more": false
}
```
驗證與錯誤語意和 `/v1/messages` 完全相同,因此在正式送出請求前,這是一個成本很低
的方式,用來確認 Agent 名稱與金鑰是否搭配正確。
若省略 `model`,解析順序為:automation 指定的模型(當你傳了
`metadata.automation`)→ Agent 的預設模型。
***
## 接下來
完整的請求內容、SSE 事件串流與 SDK 範例。
接續、分支、列出、分享與刪除對話。
狀態碼、逾時與併發建議。
# Add MCP Servers
Source: https://datagen.dev/guide/add-mcp-servers
Connect external services like Gmail, Linear, and Slack to your agents
MCP servers give your agents access to external services -- Gmail, Linear, Slack, HubSpot, and more. Connect them once through DataGen, and they work both locally in Claude Code and in deployed agents.
## Prerequisites: DataGen MCP Must Be Connected
Before adding any external MCP servers, make sure the DataGen MCP server itself is connected to your Claude Code.
If you ran `/datagen:setup` earlier, this is already configured. To verify:
```bash theme={null}
claude mcp list
```
Look for `datagen` in the output. If it's not there, add it manually:
```bash theme={null}
claude mcp add datagen --transport http https://mcp.datagen.dev/mcp -e DATAGEN_API_KEY
```
This requires `DATAGEN_API_KEY` to be set in your environment. If you haven't authenticated yet, run `datagen login` or `/datagen:setup` first.
***
## Add via Claude Code
Run the guided skill in Claude Code:
```
/datagen:add-mcps
```
This walks you through:
Select from common services (Gmail, Slack, Linear, GitHub, HubSpot, etc.) or provide a custom MCP server URL.
The plugin checks DataGen's built-in server templates first. If a match is found, it installs automatically with OAuth.
For OAuth-based servers, a browser window opens for authentication. The plugin monitors the flow and confirms when complete.
Once connected, the plugin shows all new tools available from the service (e.g., `mcp_Linear_list_issues`, `mcp_Gmail_gmail_send_email`).
You can also add a server directly by asking Claude:
```
"Add Linear MCP to DataGen: https://mcp.linear.app/sse"
```
Claude will call `addRemoteMcpServer`, handle the OAuth flow, and confirm the connection.
***
## Add via the Web UI
### Browse the MCP Registry
Navigate to **MCP Servers** in the DataGen sidebar and click the **MCP Registry** tab.
Click **Connect** on any server to start the OAuth flow.
### Add a Custom MCP Server
For servers not in the registry, click **Add Connector**.
Fill in:
* **Server Name** -- Display name (e.g., "Linear")
* **Type** -- Transport method: Streamable HTTP, SSE, or STDIO
* **URL** -- The MCP server endpoint
* **Environment Variables** -- Optional variables the server needs
### View Connected Servers
The **Connected** tab shows all your active MCP servers.
***
## How MCP Works with Agents
When you connect an MCP server through DataGen, the tools become available in two places:
1. **Locally** -- Use tools directly in Claude Code conversations
2. **Deployed agents** -- Your agents and custom tools can call the same MCP tools in production
Connect once, use everywhere. No separate auth setup for each agent.
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient()
# Same MCP tools work locally and in deployed agents
issues = client.execute_tool("mcp_Linear_list_issues", {
"status": "in_progress",
"limit": 10
})
```
***
## Commonly Used MCPs
### Official Remote MCP Servers
* **Notion** -- `https://mcp.notion.com/mcp` -- Workspace, content management, databases
* **Linear** -- `https://mcp.linear.app/sse` -- Issue tracking, project management
* **Neon** -- `https://mcp.neon.tech` -- Cloud Postgres database management
### MCP Providers
**URL**: [composio.dev](https://mcp.composio.dev/)
Use **HTTP** transport. Popular servers:
* **Gmail** -- `https://mcp.composio.dev/gmail`
* **Outlook** -- `https://mcp.composio.dev/outlook`
* **Dropbox** -- `https://mcp.composio.dev/dropbox`
**URL**: [klavis.ai](https://www.klavis.ai/)
Production-ready with hosted authentication:
* **Gmail** -- `https://www.klavis.ai/mcp-server-connections/gmail`
* **GitHub** -- `https://www.klavis.ai/mcp-server-connections/github`
* **Slack** -- `https://www.klavis.ai/mcp-server-connections/slack`
* **Jira** -- `https://www.klavis.ai/mcp-server-connections/jira`
* **Google Drive** -- `https://www.klavis.ai/mcp-server-connections/google-drive`
**URL**: [smithery.ai](https://smithery.ai/)
6,800+ MCP servers. Both local and hosted options.
### Community & Custom MCPs
* **Open Source** -- [github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers)
* **Custom** -- Use the MCP SDK to build integrations for proprietary systems
***
## Managing Connections
### Reconnect Expired Tokens
Some OAuth tokens expire. To reconnect:
1. Check status with `checkRemoteMcpOauthStatus`
2. Re-authenticate with `ReAuthRemoteMcpServer`
### Update a Server
Use `updateRemoteMcpServer` to change the URL or credentials for a connected server.
***
## Troubleshooting
1. Clear browser cookies for the OAuth provider
2. Try an incognito/private window
3. Check if your organization blocks OAuth for the service
4. Re-run the OAuth flow
1. Wait 1-2 minutes for synchronization
2. Use `searchTools` to discover newly available tools
3. Verify `checkRemoteMcpOauthStatus` shows "completed"
4. Restart Claude Desktop if needed
1. Verify you granted all required permissions during OAuth
2. Some services need admin approval for certain scopes
3. Re-run the OAuth flow with broader permissions
# Agent Templates
Source: https://datagen.dev/guide/agent-templates
Browse and install pre-built agent templates from the DataGen template repository
Get started faster with pre-built agent templates. Each template includes the agent definition, context files, helper scripts, and everything you need to run a working agent.
In Claude Code, run `/datagen:fetch-agent` to browse and install templates with guided setup.
## Browse Templates
Run the command without arguments to see all available templates:
```
/datagen:fetch-agent
```
This fetches the catalog from the [DataGen agent templates repository](https://github.com/datagendev/datagen-agent-templates) and displays available agents with their descriptions, required tools, and MCP connections.
***
## Install a Template
Specify a template ID to install it:
```
/datagen:fetch-agent linkedin-engagement
```
The installer will:
Fetches the template's manifest and downloads all files to:
* `.claude/agents/.md` -- the agent definition
* `.datagen//` -- context, scripts, memory, and workspace files
Identifies required MCP connections, secrets, and Python packages. Reports what's ready and what's missing.
Installs any required Python packages listed in the template manifest.
Shows what the agent does, how to invoke it, and any remaining setup.
***
## After Installation
### Connect Required MCPs
Templates may require external MCP servers (Gmail, Linear, Slack, etc.). Connect them before running:
```
/datagen:add-mcps
```
Or connect via the [web UI](/guide/add-mcp-servers).
### Configure Secrets
Some templates need API keys or credentials. Add them at [DataGen Secrets](https://datagen.dev/account?tab=secrets).
### Run the Agent
```
@template-id run the full pipeline
```
After installing a template, run `claude -r` to reload Claude Code and pick up the new agent.
***
## Customizing Templates
Installed templates are fully editable:
* **Context files** -- Update `.datagen//context/` with your domain knowledge
* **Scripts** -- Modify `.datagen//scripts/` to change data processing logic
* **Agent definition** -- Edit `.claude/agents/.md` to adjust reasoning and workflow
* **Memory** -- Upgrade the memory structure if you need more state management
***
## Reusable Skills
Skills are smaller, reusable capabilities that any agent can use:
```
/datagen:fetch-skill
```
Skills install to `.claude/skills//` and can be composed into any agent. Unlike templates (which are complete agents), skills are building blocks -- e.g., a product analysis skill, a lead scoring skill, or a data validation skill.
# Alternative Setup Methods
Source: https://datagen.dev/guide/alternative-setup
Set up DataGen with CLI, Direct Connect, Claude Desktop, or Cursor
**Using Claude Code?** The fastest path is the [DataGen Plugin](/guide/quickstart) -- it handles authentication, MCP configuration, CLI, and SDK setup automatically.
## Method 1: Direct Connect (Claude Pro/Max)
Connect directly from Claude's web interface without installing anything.
* Go to [claude.ai](https://claude.ai) and sign in
* Click your profile icon then **Settings**
* Navigate to **Connectors** in the sidebar
* Scroll to the bottom and click **"Add custom connector"**
* Enter the MCP Name: `DataGen`
* Enter the MCP server URL: `https://mcp.datagen.dev/mcp`
* Click **"Add"** to complete the connection
DataGen tools are now available in Claude web, mobile, and desktop.
Works on Claude web interface, mobile apps, and Claude Desktop for Pro, Max, Team, and Enterprise subscribers.
***
## Method 2: DataGen CLI
Works with Claude Code, Claude Desktop, and other MCP clients.
```bash theme={null}
curl -fsSL https://cli.datagen.dev/install.sh | sh
```
```bash theme={null}
datagen login
```
This opens a browser for OAuth and saves your API key to your shell profile.
```bash theme={null}
datagen mcp
```
Follow the prompts to configure Claude Code, Claude Desktop, or other clients.
Don't have an API key? [Sign up at datagen.dev](https://datagen.dev) to get one.
***
## Method 3: Manual Configuration (Claude Desktop)
* Install and Launch [Claude Desktop](https://claude.ai/download)
* Click the Settings icon -> **Developer** -> **Edit Config**
Copy and paste this into your Claude Desktop config:
```json theme={null}
{
"mcpServers": {
"datagen": {
"command": "npx",
"args": [
"mcp-remote",
"https://mcp.datagen.dev/mcp"
]
}
}
}
```
Close and reopen Claude Desktop to load the new MCP connection.
Requires Node.js/npm installed on your system for the `npx` command.
***
## Method 4: Claude Code CLI
```bash theme={null}
claude mcp add --transport http datagen https://mcp.datagen.dev/mcp
claude mcp list
```
## Method 5: Cursor IDE
1. Open Cursor and go to MCP settings
2. Choose **Type**: "Command"
3. In the **Command** field, enter:
```
npx mcp-remote https://mcp.datagen.dev/mcp
```
***
## Verify Your Connection
Test your connection in any Claude interface:
Ask Claude: **"List all available DataGen tools"**
You should see tools like `executeCode`, `searchTools`, `addRemoteMcpServer`, and `createCustomTool`.
***
## Troubleshooting
1. Verify your JSON configuration is valid (use a JSON validator)
2. Ensure you restarted Claude Desktop after adding the config
3. Check that `npx` is installed and accessible in your terminal
4. Try running `datagen mcp` again to reconfigure
1. Check your internet connection
2. Verify the URL: `https://mcp.datagen.dev/mcp`
3. If behind a corporate firewall, contact your IT team about MCP access
1. Verify your API key is correct: `datagen login`
2. Some tools require OAuth authentication -- use `addRemoteMcpServer` to connect external services
1. Ensure you have curl installed: `which curl`
2. Try running with sudo: `sudo sh -c "$(curl -fsSL https://cli.datagen.dev/install.sh)"`
3. Manual install: Download from [GitHub releases](https://github.com/datagendev/datagen-cli/releases)
***
## Support
* **Community**: [Discord](https://discord.gg/6nfr4hh38r)
* **Email**: [support@datagen.dev](mailto:support@datagen.dev)
* **1:1 Onboarding**: [Book a session](https://cal.com/yusheng/datagen-on-board-1-1)
# Run Agents Autonomously
Source: https://datagen.dev/guide/autonomous
Trigger agents from external events with webhooks, or run them on a schedule
Once deployed, agents don't need you to press "Run." They can react to external events via webhooks or run on a recurring schedule -- fully hands-free.
***
## Webhooks: Trigger from External Events
Every deployed agent gets a unique webhook URL. Any system that can make an HTTP POST request can trigger your agent.
### Getting Your Webhook URL
Your webhook URL is available in:
* **Web UI** -- On the agent's detail page, click the copy icon next to the webhook URL
* **CLI** -- `datagen agents show `
* **Plugin** -- Displayed after running `/datagen:deploy-agent`
### Triggering with cURL
```bash theme={null}
curl -X POST "https://api.datagen.dev/agent/YOUR_AGENT_ID" \
-H "Content-Type: application/json" \
-d '{
"task": "Process new data",
"source": "github",
"data": { "pr_number": 42 }
}'
```
The JSON body is passed to your agent as context for the run.
### Payload Format
The webhook accepts any valid JSON. Your agent receives the full payload and can reference it during execution.
**Simple trigger (no data):**
```bash theme={null}
curl -X POST "https://api.datagen.dev/agent/YOUR_AGENT_ID"
```
**With structured data:**
```json theme={null}
{
"task": "Enrich these leads",
"leads": [
{"name": "Acme Corp", "domain": "acme.com"},
{"name": "Globex", "domain": "globex.com"}
]
}
```
### Integration Examples
Use your webhook URL with any system that supports HTTP webhooks:
* **n8n / Make / Zapier** -- HTTP action in automation workflows
* **GitHub** -- Trigger on push, PR, or issue events
* **HeyReach** -- Real-time LinkedIn campaign monitoring
* **Fireflies** -- Auto-generate follow-ups after meetings
* **Custom apps** -- Any system that can make HTTP POST requests
When triggered via webhook, results are also sent to any configured [channels](/guide/channels-overview) (Slack, email).
***
## Schedules: Run on a Recurring Basis
Schedules let you run agents automatically -- hourly, daily, weekly, or with custom cron expressions. No manual intervention needed.
### Set Up via the Web UI
Click **Schedule** on your deployed agent.
* **Hourly** -- Run every hour
* **Daily** -- Run once per day at a specific time
* **Weekly** -- Run on specific days of the week
* **Custom** -- Define a custom cron expression
Choose your timezone to ensure the agent runs at the expected times.
Provide JSON payload passed to your agent on each run.
```json theme={null}
{
"target_branch": "main",
"dry_run": false
}
```
Click **Save** to activate the schedule.
### Set Up via the CLI
```bash theme={null}
# Daily at 9 AM Eastern
datagen agents schedule \
--cron "0 9 * * *" \
--timezone "America/New_York"
# Every Monday at 2 PM UTC
datagen agents schedule \
--cron "0 14 * * 1"
```
### Schedule Types
| Type | Example | Cron Expression |
| ------------ | ---------------------- | --------------- |
| **Hourly** | Every hour on the hour | `0 * * * *` |
| **Daily** | Every day at 9 AM | `0 9 * * *` |
| **Weekly** | Every Monday at 2 PM | `0 14 * * 1` |
| **Weekdays** | Monday-Friday at 8 AM | `0 8 * * 1-5` |
| **Custom** | Every 6 hours | `0 */6 * * *` |
### Managing Schedules
```bash theme={null}
# List schedules
datagen agents schedule
# Pause a schedule
datagen agents schedule --pause
# Resume a schedule
datagen agents schedule --resume
# Delete a schedule
datagen agents schedule --delete
```
You can also pause, resume, and delete schedules from the web UI.
# Per-Agent Channel Config
Source: https://datagen.dev/guide/channels-agent
Customize Email and Slack settings for each agent
After setting up channels globally, you can customize settings for each individual agent. Per-agent settings override the global defaults.
***
## Email Per Agent
Configure email recipients and permissions from the agent's Channel settings:
* **Sender address** -- Each agent gets a unique email address (e.g., `agent-name@agents.datagen.dev`)
* **Owner** -- Can trigger the agent by email and receives notifications
* **Viewer** -- Receives notifications only
* **Email allowlist** -- Restrict which email addresses can interact with this agent
* **Success/Failure notifications** -- Choose whether to send emails on successful runs, failed runs, or both
***
## Slack Per Agent
Pick which Slack channels this specific agent posts to and who can trigger it:
* **Agent channels** -- Select which Slack channels this agent can post to
* **Enable inbound** -- Allow Slack replies in those channels to trigger the agent
* **Allowed Slack members** -- Control who can trigger the agent (Owner) and who receives notifications only (Viewer)
* **Custom emoji** -- Set a bot emoji for this agent's messages
Click **Save Slack Settings** after making changes.
***
## Settings Hierarchy
Per-agent settings override global defaults. If a per-agent setting is not configured, the global default applies.
| Setting | Global (Account) | Per-Agent |
| ---------------------- | ---------------------- | ------------------ |
| **Email enabled** | Default for all agents | Override per agent |
| **Slack enabled** | Default for all agents | Override per agent |
| **Notify on success** | Default behavior | Override per agent |
| **Notify on failure** | Default behavior | Override per agent |
| **Reply-to-resume** | Default behavior | Override per agent |
| **Slack destinations** | Available channels | Selected per agent |
| **Email allowlist** | -- | Per agent |
***
## Channel Setup During Deployment
When deploying an agent through the web UI, you can configure channels as part of the setup:
1. **Select channels** -- Toggle Email and/or Slack
2. **Configure Slack** -- Select channels for this agent
3. **Review** -- Confirm notification preferences before deploying
You can always update channel settings after deployment from the agent's configuration page.
# Global Channel Config
Source: https://datagen.dev/guide/channels-overview
Set up Email and Slack channels at the account level
Channels let you interact with your deployed agents through everyday communication tools. When an agent finishes running, it sends results to your configured channels. You can also trigger agents by replying -- creating a two-way conversation loop.
Start by configuring channels globally, then customize per agent.
## Supported Channels
Each agent gets a unique email address. Send an email to trigger it, receive results in your inbox, and reply to continue the conversation.
Connect your Slack workspace. Agents post results to channels, and you can trigger them with `@DataGen` mentions or thread replies.
Discord, WhatsApp, Telegram, SMS, and LINE are planned for future releases.
***
## Email (Global)
Email is enabled by default for all deployed agents. Toggle it on or off from the Channel page.
### How It Works
1. Each agent gets a unique email address (e.g., `agent-name@agents.datagen.dev`)
2. Send an email to that address to trigger the agent
3. The agent runs, then replies to your email thread with results
4. Reply again to continue the conversation
***
## Slack (Global)
### Connect Your Workspace
Go to the **Channel** page in DataGen and click the Slack toggle to connect.
Sign in to your Slack workspace and grant permissions. DataGen requests access to read channels, post messages, and receive mentions.
Click **Add Slack channels** to select which channels are available for your agents.
### Using Slack with Agents
Once connected:
* **Mention `@DataGen`** in a channel to trigger the default agent for that channel
* **Reply in a thread** to continue a conversation with the agent that posted
* **Results appear as threaded messages**, keeping your channels organized
### Bring Your Own Bot (BYOB)
If you want to use your own custom Slack app instead of DataGen's default bot, you can configure a custom Slack app with your own branding and permissions.
***
## Next Step
Customize channel settings for each individual agent
# Create Your First Agent
Source: https://datagen.dev/guide/create-agent
Build a Claude Code agent, skill, or command and prepare it for deployment
## What Are Claude Code Agents?
Claude Code agents are markdown files (`.md`) that define autonomous AI workflows. They live in your repository and can be deployed to run on schedules or webhooks.
There are three types:
| Type | Location | Purpose |
| ----------- | ------------------- | ----------------------------------------------------------------------- |
| **Agent** | `.claude/agents/` | Autonomous workflows that can use tools, create PRs, send notifications |
| **Skill** | `.claude/skills/` | Reusable capabilities that can be invoked by agents or users |
| **Command** | `.claude/commands/` | Quick actions triggered by slash commands |
## Create an Agent
Run `/agents` in Claude Code to create a new agent, or create the file manually at `.claude/agents/{agent-name}.md`:
```markdown theme={null}
---
name: Weekly Report Generator
description: Generates a weekly summary of GitHub activity and posts to Slack
tools:
- mcp_GitHub_list_pull_requests
- mcp_Slack_chat_postMessage
---
You are a weekly report generator. Every time you run:
1. Fetch all merged PRs from the past 7 days using the GitHub tool
2. Summarize the changes by category (features, fixes, docs)
3. Post the summary to the #engineering Slack channel
Format the report with clear sections and bullet points.
Keep the tone professional but concise.
```
The **frontmatter** (between `---`) defines metadata. The **body** is the prompt that tells the agent what to do.
## Create a Skill
Skills are directories with a `SKILL.md` file and optional supporting files. Create `.claude/skills/enrich-lead/SKILL.md`:
```markdown theme={null}
---
name: Enrich Lead
description: Enriches a company lead with LinkedIn and web data
tools:
- mcp_LinkedIn_get_company_profile
- mcp_Perplexity_search
---
Given a company name and domain, enrich the lead with:
1. Company size, industry, and funding from LinkedIn
2. Recent news and product launches from web search
3. Key decision makers and their titles
Return structured JSON with all findings.
```
You can add supporting files alongside `SKILL.md` (scripts, reference data, etc.):
```
.claude/skills/enrich-lead/
SKILL.md # Skill definition
criteria.md # Enrichment criteria
scripts/
validate.py # Helper script
```
## Create a Command
Commands are quick actions. Create `.claude/commands/check-pr.md`:
```markdown theme={null}
---
name: Check PR
description: Reviews the latest open PR and posts feedback
---
Find the most recent open pull request, review the code changes,
and post constructive feedback as a PR comment.
```
## Guided Build (Optional)
For a more structured approach, run the guided workflow in Claude Code:
```
/datagen:build-agent
```
This walks you through defining your agent's purpose, connecting tools, and writing the agent file.
## Next Step
Push your agent to DataGen cloud and set up webhooks or schedules
# Create Custom Tool
Source: https://datagen.dev/guide/custom-tools
Build custom tools from Python code and deploy as APIs
Custom Tools are deterministic Python workflows that assist your agents with fast, reliable operations. Instead of letting the agent figure out multi-step logic each time, you package it as a custom tool -- predictable, testable, and reusable.
Once deployed, custom tools become REST API endpoints and MCP tools -- callable from agents, Claude conversations, external systems, or scheduled jobs.
Custom Tools are separate from [agents](/guide/create-agent). Agents are autonomous and use reasoning. Custom Tools are deterministic -- same input, same output, every time.
**Using Claude Code?** Run `/datagen:create-custom-tool` for a guided workflow that handles schema design, implementation, testing, and deployment.
## Create via Claude Code
Ask Claude to build and deploy your tool:
```
"Create a custom tool that enriches company leads using LinkedIn and Perplexity"
```
Or use the guided workflow:
```
/datagen:create-custom-tool
```
This walks you through:
1. **Plan** -- Define the tool's purpose and input/output schema
2. **Implement** -- Write the Python logic using the DataGen SDK
3. **Test** -- Run in a sandbox with `executeCode`
4. **Deploy** -- Deploy as a reusable API endpoint
## Writing the Code
Use the DataGen SDK to call MCP tools as Python functions:
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient()
# Call MCP tools
issues = client.execute_tool("mcp_Linear_list_issues", {
"filter": {"state": {"name": {"eq": "In Progress"}}}
})
# Process data
active_count = len(issues)
result = f"Found {active_count} active issues"
```
### Input Schema
Define what parameters your tool accepts using JSON Schema:
```json theme={null}
{
"type": "object",
"properties": {
"campaign_id": {
"type": "string",
"description": "The campaign ID to analyze"
},
"days": {
"type": "integer",
"description": "Number of days to look back",
"default": 30
}
},
"required": ["campaign_id"]
}
```
### Output Variables
List the variables your code produces. These become the tool's return values:
```python theme={null}
# Your code assigns these variables
result = {"total_leads": 150, "conversion_rate": 0.12}
summary = "Campaign performed above average"
# Output variables: ["result", "summary"]
```
### Dependencies
| Type | Description | Example |
| --------------- | ---------------------------- | --------------------- |
| **MCP Servers** | Which MCP servers to connect | `["Linear", "Gmail"]` |
| **Secrets** | Environment variables needed | `["OPENAI_API_KEY"]` |
| **Imports** | Python packages to import | `["pandas", "httpx"]` |
***
## Testing
### Test with executeCode
Before deploying, test your code interactively:
```
"Run this code to test my campaign analysis logic"
```
Claude calls `executeCode` to run your code in a sandbox and return results immediately.
### Test a Deployed Tool
After deployment, test with `submitCustomToolRun`:
```
"Run my analyze_campaign tool with campaign_id='abc123'"
```
***
## Deploying
Ask Claude to deploy using natural language:
```
"Deploy this as a custom tool called 'analyze_campaign'"
```
Or with more detail:
```
"Deploy this tool with campaign_id and date_range parameters, schedule daily at 9 AM"
```
Claude calls `createCustomTool` with your code, schema, and configuration.
### Using Your Deployed Tool
Once deployed, your tool is available as:
* **MCP tool** -- Callable from Claude conversations via `submitCustomToolRun`
* **REST API** -- HTTP endpoint for external integrations
* **Scheduled job** -- Run automatically via [schedules](/guide/autonomous#schedules-run-on-a-recurring-basis)
***
## Managing Custom Tools
### Find Your Tools
```
"Search for my campaign tools"
```
Claude calls `searchCustomTools` to list your deployed tools.
### Update a Tool
```
"Update my analyze_campaign tool to also return top performing messages"
```
Claude calls `updateCustomTool` to modify the code, schema, or dependencies.
### Check Run Status
```
"Check the status of my last campaign analysis run"
```
Claude calls `checkRunStatus` to show the current state and output.
### CLI Management
```bash theme={null}
# List all custom tools
datagen tools list
# Show tool details
datagen tools show
# Run a tool
datagen tools run --input '{"campaign_id": "abc123"}'
```
***
## Example: Lead Enrichment Tool
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient()
# Input: list of company domains
domains = input_domains # From input schema
enriched = []
for domain in domains:
# Web research
research = client.execute_tool("mcp_Perplexity_search", {
"query": f"What does {domain} company do? Who are the founders?"
})
# LinkedIn data
company = client.execute_tool("mcp_LinkedIn_get_company", {
"domain": domain
})
enriched.append({
"domain": domain,
"description": research.get("answer"),
"employee_count": company.get("employeeCount"),
"industry": company.get("industry")
})
# Output variables
result = enriched
total_enriched = len(enriched)
```
**Input Schema:**
```json theme={null}
{
"type": "object",
"properties": {
"input_domains": {
"type": "array",
"items": {"type": "string"},
"description": "List of company domains to enrich"
}
},
"required": ["input_domains"]
}
```
**Dependencies:** MCP Servers: `["Perplexity", "LinkedIn"]` | Output Variables: `["result", "total_enriched"]`
***
## Best Practices
Each tool should do one thing well. Create separate tools for different tasks rather than one massive tool.
```python theme={null}
try:
result = client.execute_tool("mcp_Linear_create_issue", {...})
except DatagenToolError as e:
error_message = f"Failed to create issue: {e}"
```
Name tools clearly: `enrich_company_data` not `tool1`. Good descriptions help Claude understand when to use your tool.
Always test with `executeCode` first. Deployed tools are harder to debug.
# Deploy Your Agent
Source: https://datagen.dev/guide/deploy-agent
Deploy agents, skills, and commands from Claude Code or the web UI
Deploying an agent turns it into a cloud service that runs on webhooks, schedules, or manual triggers. Once deployed, your agent can create PRs, send notifications, and process data automatically.
**Using Claude Code?** Run `/datagen:deploy-agent` for a guided deployment workflow.
## Push to GitHub
Your agent needs to be in a GitHub repository before deploying.
```bash theme={null}
git add .claude/
git commit -m "Add agent definition"
git push origin main
```
If you don't have a remote yet:
```bash theme={null}
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/your-username/your-repo.git
git push -u origin main
```
***
## Deploy from Claude Code
Run the deploy command inside Claude Code:
```
/datagen:deploy-agent
```
The plugin will:
1. Scan your agent's dependencies (scripts, tools, secrets)
2. Connect your GitHub repo via the DataGen GitHub App
3. Push required secrets to DataGen
4. Create a webhook endpoint
5. Optionally set up cron schedules
After deployment, you get a webhook URL to trigger your agent externally.
***
## Deploy from the Web UI
### Step 1: Connect Your GitHub Repository
Navigate to the **Agents** page in DataGen.
Click **Connect Repository** to start the setup.
Click **Install GitHub App** and authorize DataGen to access your repositories.
Choose the GitHub account/organization and select the repositories you want to connect.
### Step 2: Deploy an Agent
DataGen automatically discovers agents, skills, and commands from your repository's `.claude/` directory.
Click on the agent you want to deploy from the list.
Select which secrets your agent needs. You need either an Anthropic API key or a Claude Code subscription token.
**Option A: Anthropic API Key** -- Add `ANTHROPIC_API_KEY` in [DataGen Secrets](https://datagen.dev/account?tab=secrets).
**Option B: Claude Code Subscription (Recommended)** -- Run `claude setup-token` in your terminal, then add the token as `CLAUDE_CODE_OAUTH_TOKEN` in DataGen Secrets.
* **Create Pull Request** -- Enable if you want the agent to submit changes as PRs
* **Entry Prompt** -- Set a system-level instruction for every execution
Click **Deploy Agent** to create your deployment.
After deployment, copy the webhook URL for external integrations.
***
## After Deployment
Once deployed, your agent:
* Has a unique **webhook URL** for triggering via HTTP POST
* Appears in the **Agents** dashboard with run statistics
* Can be configured with [schedules](/guide/schedules), [channels](/guide/channels-overview), and additional secrets
## Troubleshooting
Make sure your agent file is at `.claude/agents/your-agent.md` and has been pushed to the main branch.
Ensure you've configured the required secrets (Anthropic API key or Claude Code OAuth token) and selected them during deployment.
Verify you have admin access to the repository. Try disconnecting and reconnecting the repo.
## Next Step
View execution logs, tool calls, and agent output
# Introduction
Source: https://datagen.dev/guide/introduction
Deploy Claude Code agents, connect tools, and automate workflows
## What is DataGen?
DataGen is a **command center** to operationalize your Claude Code. Build agents locally, deploy them to the cloud, add MCP integrations or create custom tools to extend their capabilities, and trigger them via webhooks or schedules. Your agents can send results through Slack, email, or create pull requests automatically.
## What You Can Do
Deploy Claude Code agents to run on webhooks or schedules. Auto-create PRs, send notifications, and process data.
Communicate with agents through Slack, email, and webhooks. Trigger runs and receive results.
Connect 50+ MCP servers -- Gmail, Linear, HubSpot, and more. Build custom tools with Python.
## How It Works
Create agents, skills, or commands as `.md` files in your repository.
Push to DataGen cloud via the plugin or web UI.
Run on a recurring schedule, via webhook from external systems, or manually.
Agents deliver results through your configured channels -- Slack messages, email threads, or pull requests.
## Get Started
Get 50+ MCP tools, 9 slash commands, and one-command deployment -- install in under 60 seconds.
Not using Claude Code? See [Alternative Setup](/guide/alternative-setup) for Claude Desktop, Cursor, and Direct Connect options.
# Monitor Agent Runs
Source: https://datagen.dev/guide/monitoring
View execution logs, tool calls, and agent output
After deploying an agent, you can monitor every execution from the DataGen dashboard or CLI.
## Execution History
Click on any deployed agent to see its execution history. Each run shows:
* **Start time** -- When the execution began
* **Duration** -- How long the run took
* **Status** -- Current state of the execution
* **Trigger** -- What initiated the run (schedule, manual, webhook)
You can filter by status and sort by date.
## Status Types
| Status | Description |
| ------------- | ---------------------------- |
| **Queued** | Run is waiting to start |
| **Running** | Agent is currently executing |
| **Completed** | Run finished successfully |
| **Failed** | Run encountered an error |
| **Cancelled** | Run was manually stopped |
## Execution Details
Click on any execution to see the full details:
* **Event stream** -- Step-by-step log of what the agent did (system events, assistant messages, tool calls, results)
* **Log entries** -- Timestamped messages with levels (DEBUG, INFO, WARN, ERROR)
* **Payload** -- The input payload that triggered the run
* **Result** -- The agent's final output
## Tool Visibility
Each execution log shows which MCP tools your agent called during the run. For every tool call, you can see:
* **Tool name** -- Which MCP tool was invoked (e.g., `mcp_Gmail_gmail_send_email`)
* **Input parameters** -- The exact parameters passed to the tool
* **Output** -- The tool's response data
* **Timing** -- When the tool was called during execution
This helps you debug agent behavior, verify data flow, and understand which integrations your agent is using.
## Viewing Pull Requests
If your agent creates pull requests, a direct link to the PR appears in the execution details.
## Run Now
Test your agent at any time with the **Run Now** button.
Optionally provide a JSON payload for the test run:
```json theme={null}
{
"task": "Review latest PRs",
"notify": true
}
```
## Monitoring with the CLI
```bash theme={null}
# View execution history
datagen agents logs
# View output of the latest run
datagen agents output
# Stop a running execution
datagen agents run --stop
```
## Next Step
Set up Slack, email, and webhook notifications for your agents
# Quick Start
Source: https://datagen.dev/guide/quickstart
Install the DataGen plugin and run your first skill in under 2 minutes
## Prerequisites
* [Claude Code](https://docs.anthropic.com/en/docs/claude-code) v1.0.33+
* A [DataGen account](https://datagen.dev)
## Install the Plugin
```bash theme={null}
claude plugin marketplace add datagendev/datagen-plugin
claude plugin install datagen --scope project
```
```
/plugin marketplace add datagendev/datagen-plugin
/plugin install datagen --scope project
```
Type /plugin in the Claude Code prompt to access plugin commands.
## Run Setup
Inside Claude Code, run:
```
/datagen:setup
```
This triggers the following actions:
A browser window opens for OAuth authentication with DataGen.
Your API key is saved to your shell profile (`~/.zshrc` or equivalent).
The plugin connects to `https://mcp.datagen.dev/mcp` automatically.
The DataGen CLI is installed. Optionally install the Python or TypeScript SDK.
After setup, all 50+ MCP tools are available in your Claude Code session. Try asking Claude: **"List all available DataGen tools"**.
## What You Get
The plugin adds **9 slash commands** to Claude Code:
| Command | Description |
| ----------------------------- | ------------------------------------------------------ |
| `/datagen:setup` | Authenticate and configure MCP tools |
| `/datagen:add-mcps` | Connect external services (Gmail, Slack, Linear, etc.) |
| `/datagen:build-agent` | Build a new agent with a guided workflow |
| `/datagen:deploy-agent` | Deploy an agent as a webhook or scheduled automation |
| `/datagen:manage-agents` | List, monitor, and manage deployed agents |
| `/datagen:fetch-agent` | Browse and install pre-built agent templates |
| `/datagen:fetch-skill` | Browse and install reusable skills |
| `/datagen:create-custom-tool` | Create a custom tool with your own logic |
| `/datagen:code-mode` | Write local Python/TypeScript scripts using the SDK |
Plus **50+ MCP tools** for Gmail, Slack, Linear, GitHub, HubSpot, LinkedIn, Notion, and more.
## Next Steps
Write an agent and deploy it to the cloud
Add Gmail, Linear, Slack, and other MCP servers
***
Not using Claude Code? See [Alternative Setup](/guide/alternative-setup) for other installation methods.
# Code Mode
Source: https://datagen.dev/guide/sdk-tools
Write Python or TypeScript scripts for bulk workflows and programmatic tool calling
Code mode lets you write local scripts that call MCP tools through the DataGen SDK. Use it when you need batch processing, complex logic, or production-grade automation that goes beyond interactive MCP tool calls.
**Using Claude Code?** Run `/datagen:code-mode` for guided scripting with tool discovery, durable checkpoint patterns, and large output handling.
## When to Use Code Mode
* Interactive discovery and debugging
* Simple one-off operations
* Learning tool schemas
* AI agent-assisted work
* Batch processing (100+ operations)
* Scheduled jobs and cron tasks
* CI/CD pipelines
* Complex data transformations
* Production applications
**Rule of thumb:** fewer than 5 tool calls with small results -- use MCP directly. More than 5 calls, large data, or complex logic -- write a script with the SDK.
***
## Installation
```bash theme={null}
pip install datagen-python-sdk
```
```bash theme={null}
npm install @datagen-dev/typescript-sdk
```
Set your API key:
```bash theme={null}
export DATAGEN_API_KEY="your_api_key_here"
```
***
## Quick Start
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient()
# Call any MCP tool as a Python function
result = client.execute_tool(
"mcp_Linear_list_issues",
{"filter": {"state": {"name": {"eq": "In Progress"}}}}
)
print(f"Found {len(result)} active issues")
```
```typescript theme={null}
import { DatagenClient } from '@datagen-dev/typescript-sdk';
const client = new DatagenClient();
const result = await client.executeTool(
"mcp_Linear_list_issues",
{ filter: { state: { name: { eq: "In Progress" } } } }
);
console.log(`Found ${result.length} active issues`);
```
***
## Patterns
### Simple Script
One-off data operations:
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient()
# Fetch leads from database
leads = client.execute_tool("mcp_Supabase_run_sql", {
"params": {
"sql": "SELECT * FROM leads WHERE score > 80",
"projectId": "your-project",
"databaseName": "your-db"
}
})
# Create follow-up tasks in Linear
for lead in leads:
client.execute_tool("mcp_Linear_create_issue", {
"title": f"Follow up with {lead['company']}",
"description": f"Contact: {lead['email']}\nScore: {lead['score']}",
"teamId": "your-team-id"
})
# Notify team on Slack
client.execute_tool("mcp_Slack_chat_postMessage", {
"channel": "#sales",
"text": f"Created {len(leads)} follow-up tasks for high-priority leads"
})
```
### Batch Processing with Error Handling
Process large datasets with retry logic:
```python theme={null}
from datagen_sdk import DatagenClient, DatagenToolError
client = DatagenClient(retries=3, backoff_seconds=1.0)
contacts = [...] # Your contact list
results = []
errors = []
for contact in contacts:
try:
result = client.execute_tool("mcp_Gmail_gmail_send_email", {
"to": contact["email"],
"subject": "Welcome!",
"body": f"Hi {contact['name']}, thanks for signing up!"
})
results.append({"email": contact["email"], "status": "sent"})
except DatagenToolError as e:
errors.append({"email": contact["email"], "error": str(e)})
print(f"Sent: {len(results)}, Failed: {len(errors)}")
```
### Deploy as Custom Tool
Turn your script into a deployed API endpoint:
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient()
# Deploy your script as a custom tool
deployment = client.deploy_custom_tool(
name="weekly_lead_enrichment",
description="Enrich new leads with LinkedIn and web data",
code=open("enrich.py").read(),
input_schema={
"type": "object",
"properties": {
"domains": {"type": "array", "items": {"type": "string"}}
},
"required": ["domains"]
},
output_vars=["enriched_leads", "total"],
expected_tools=["mcp_LinkedIn_get_company", "mcp_Perplexity_search"],
mcp_server_names=["LinkedIn", "Perplexity"]
)
print(f"Deployed: {deployment['deployment_uuid']}")
# Run it
result = client.run_custom_tool(
deployment["deployment_uuid"],
input_vars={"domains": ["acme.com", "globex.com"]}
)
print(result["output_vars"])
```
***
## Error Handling
```python theme={null}
from datagen_sdk import (
DatagenClient,
DatagenAuthError,
DatagenToolError,
DatagenHttpError
)
client = DatagenClient(retries=3, backoff_seconds=0.5)
try:
result = client.execute_tool("mcp_Linear_list_projects", {"limit": 10})
except DatagenAuthError:
print("Authentication failed - check your API key")
except DatagenToolError as e:
print(f"Tool execution failed: {e}")
except DatagenHttpError as e:
print(f"HTTP error: {e}")
```
| Error | Description |
| ------------------------ | ------------------------------------------------------------------ |
| `DatagenAuthError` | Authentication failed (401/403) -- check API key or MCP connection |
| `DatagenToolError` | Tool execution failed -- check parameters |
| `DatagenHttpError` | Network or HTTP-level errors |
| `DatagenDeploymentError` | Deployment or custom tool run failed |
| `DatagenSecretError` | Secret management errors |
***
## Full API Reference
For complete method signatures, parameters, and return types, see:
Every method, every parameter
Every method, every parameter
# CLI Command Reference
Source: https://datagen.dev/reference/cli
Complete reference for the DataGen CLI
## Installation
```bash theme={null}
curl -fsSL https://cli.datagen.dev/install.sh | sh
```
Windows:
```powershell theme={null}
irm https://cli.datagen.dev/install.ps1 | iex
```
Verify: `datagen --help`
***
## `datagen login`
Authenticate with DataGen via browser OAuth or API key.
```bash theme={null}
datagen login
datagen login --api-key "your-key"
```
| Flag | Short | Type | Default | Description |
| ----------- | ----- | ------ | ----------------- | --------------------------------------- |
| `--api-key` | | string | | API key (skips browser login) |
| `--shell` | | string | | Shell type: bash, zsh, fish, powershell |
| `--profile` | | string | | Shell profile file to update |
| `--env` | | string | `DATAGEN_API_KEY` | Environment variable name |
| `--yes` | `-y` | bool | false | Skip confirmation prompts |
| `--print` | | bool | false | Print export command only |
***
## `datagen mcp`
Configure the DataGen MCP server in local tools (Codex, Claude, Gemini).
```bash theme={null}
datagen mcp
datagen mcp --clients claude,codex --dry-run
```
| Flag | Short | Type | Default | Description |
| ---------------- | ----- | ------ | --------------------- | ------------------------------------------ |
| `--clients` | | string | `codex,claude,gemini` | Comma-separated clients to configure |
| `--api-key` | | string | | API key (uses env/profile lookup if empty) |
| `--env` | | string | `DATAGEN_API_KEY` | Environment variable to look up |
| `--yes` | `-y` | bool | false | Skip confirmation prompts |
| `--dry-run` | | bool | false | Show changes without writing |
| `--codex-static` | | bool | false | Use static header in Codex config |
***
## `datagen github`
Manage GitHub connection and repository access.
### `github connect`
Install the DataGen GitHub App via browser.
```bash theme={null}
datagen github connect
```
| Flag | Type | Default | Description |
| ----------- | ---- | ------- | -------------------------------- |
| `--timeout` | int | 300 | Seconds to wait for installation |
### `github repos`
List all repositories accessible via your GitHub App.
```bash theme={null}
datagen github repos
```
### `github connected`
List repositories already connected to DataGen.
```bash theme={null}
datagen github connected
```
### `github connect-repo`
Connect a specific repository.
```bash theme={null}
datagen github connect-repo owner/repo
```
**Argument:** `` (required)
### `github sync`
Re-sync agents from a connected repository.
```bash theme={null}
datagen github sync
```
**Argument:** `` (required)
### `github status`
Check GitHub App installation status.
```bash theme={null}
datagen github status
```
***
## `datagen agents`
Manage agents, skills, and commands discovered from GitHub repositories.
### `agents list`
List all discovered agents.
```bash theme={null}
datagen agents list
datagen agents list --type agent --deployed
```
| Flag | Type | Default | Description |
| ------------ | ------ | ------- | -------------------------------------- |
| `--repo` | string | | Filter by repository (owner/repo) |
| `--type` | string | | Filter: `agent`, `skill`, or `command` |
| `--deployed` | bool | false | Show only deployed agents |
### `agents show`
Show detailed info about an agent.
```bash theme={null}
datagen agents show
```
### `agents deploy`
Deploy an agent to DataGen.
```bash theme={null}
datagen agents deploy
```
### `agents undeploy`
Remove an agent deployment and its webhook.
```bash theme={null}
datagen agents undeploy
```
### `agents run`
Trigger an agent execution.
```bash theme={null}
datagen agents run
datagen agents run --payload '{"task": "review PRs"}'
```
| Flag | Type | Default | Description |
| ----------- | ------ | ------- | ------------------------ |
| `--payload` | string | `"{}"` | JSON payload for the run |
### `agents logs`
View execution history.
```bash theme={null}
datagen agents logs
datagen agents logs --limit 20
```
| Flag | Type | Default | Description |
| --------- | ---- | ------- | ---------------------- |
| `--limit` | int | 10 | Max executions to show |
### `agents output`
Show execution output.
```bash theme={null}
datagen agents output
datagen agents output --execution
```
| Flag | Type | Default | Description |
| ------------- | ------ | ------- | ------------------------- |
| `--execution` | string | | Specific execution ID |
| `--session` | string | | SDK session ID to look up |
| `--json` | bool | false | Output raw JSON |
### `agents config`
View or update agent configuration. With no flags, displays current config.
```bash theme={null}
datagen agents config
datagen agents config --set-prompt "Review all open PRs"
datagen agents config --secrets ANTHROPIC_API_KEY,GITHUB_TOKEN
```
| Flag | Type | Default | Description |
| -------------------- | ------ | ------- | ------------------------------------ |
| `--set-prompt` | string | | Set entry prompt |
| `--clear-prompt` | bool | false | Clear entry prompt |
| `--secrets` | string | | Comma-separated secret names |
| `--pr-mode` | string | | `create_pr`, `auto_merge`, or `skip` |
| `--add-recipient` | string | | Add recipient as `email[:role]` |
| `--remove-recipient` | string | | Remove recipient by ID |
| `--notify-success` | string | | `true`, `false`, or `default` |
| `--notify-failure` | string | | `true`, `false`, or `default` |
| `--notify-reply` | string | | `true`, `false`, or `default` |
### `agents schedule`
Manage cron schedules. With no flags, lists all schedules.
```bash theme={null}
datagen agents schedule
datagen agents schedule --cron "0 9 * * *" --timezone "America/New_York"
datagen agents schedule --pause
```
| Flag | Type | Default | Description |
| ------------ | ------ | ------- | ------------------------------------- |
| `--cron` | string | | Cron expression (e.g., `"0 9 * * *"`) |
| `--timezone` | string | `UTC` | Timezone (e.g., `America/New_York`) |
| `--name` | string | | Optional schedule name |
| `--pause` | string | | Pause a schedule by ID |
| `--resume` | string | | Resume a schedule by ID |
| `--delete` | string | | Delete a schedule by ID |
***
## `datagen skills` / `datagen commands`
Aliases for `datagen agents` with type filtering.
```bash theme={null}
datagen skills list # Same as: datagen agents list --type skill
datagen commands list # Same as: datagen agents list --type command
```
All `agents` subcommands are available (show, deploy, undeploy, run, logs, output, config, schedule).
***
## `datagen tools`
Manage custom Python tools deployed as API endpoints.
### `tools list`
List all custom tools.
```bash theme={null}
datagen tools list
```
### `tools show`
Show custom tool details including code and schemas.
```bash theme={null}
datagen tools show
```
### `tools deploy`
Deploy a new custom tool.
```bash theme={null}
datagen tools deploy my_tool --file ./tool.py --description "My tool"
datagen tools deploy my_tool --code "result = 'hello'" --outputs result
```
**Argument:** `` (required)
| Flag | Type | Description |
| ------------------- | ------ | ------------------------------------- |
| `--code` | string | Inline Python code |
| `--file` | string | Path to Python source file |
| `--schema` | string | Inline JSON input schema |
| `--schema-file` | string | Path to JSON schema file |
| `--defaults` | string | Inline JSON default input values |
| `--defaults-file` | string | Path to JSON defaults file |
| `--description` | string | Tool description |
| `--outputs` | string | Comma-separated output variable names |
| `--tools` | string | Comma-separated MCP tool names |
| `--imports` | string | Comma-separated Python packages |
| `--no-auto-imports` | bool | Disable import inference from source |
| `--mcp-servers` | string | Comma-separated MCP server names |
| `--secrets` | string | Comma-separated secret names |
| `--public` | bool | Deploy as public tool |
### `tools update`
Update an existing custom tool.
```bash theme={null}
datagen tools update --file ./updated_tool.py
```
Same flags as `tools deploy` (only provided fields are updated).
### `tools run`
Run a custom tool with input.
```bash theme={null}
datagen tools run --input '{"domain": "acme.com"}'
datagen tools run --input-file ./input.json
```
| Flag | Type | Description |
| -------------- | ------ | --------------------------- |
| `--input` | string | Inline JSON input variables |
| `--input-file` | string | Path to JSON input file |
***
## `datagen secrets`
Manage API keys and secrets for agents and tools.
### `secrets list`
List all stored secrets (values are masked).
```bash theme={null}
datagen secrets list
```
### `secrets set`
Create or update a secret.
```bash theme={null}
datagen secrets set OPENAI_API_KEY=sk-abc123 # Explicit value
datagen secrets set OPENAI_API_KEY # Read from environment
```
**Argument:** `` or `` (required)
***
## Environment Variables
| Variable | Default | Description |
| ---------------------- | ------------------------- | -------------------------------------- |
| `DATAGEN_API_KEY` | | API authentication key |
| `DATAGEN_API_BASE_URL` | `https://api.datagen.dev` | Custom API server |
| `DATAGEN_WEB_BASE_URL` | `https://datagen.dev` | Custom web app URL |
| `DATAGEN_VERSION` | | Pin CLI release version during install |
| `DATAGEN_INSTALL_DIR` | | Custom install location |
# DataGen MCP Server
Source: https://datagen.dev/reference/mcp-overview
Overview of the DataGen MCP server and available tool categories
The DataGen MCP server at `https://mcp.datagen.dev/mcp` exposes all DataGen capabilities as MCP tools. Connect it to Claude Code, Claude Desktop, Cursor, or any MCP client to access 50+ integrations.
## Connection
```
https://mcp.datagen.dev/mcp
```
Authentication uses your `DATAGEN_API_KEY` via the `X-API-Key` header. See [Quick Start](/guide/quickstart) or [Alternative Setup](/guide/alternative-setup) for connection instructions.
## Tool Categories
DataGen exposes **16 active tools** across 5 categories:
### Code Execution (1 tool)
| Tool | Description |
| ------------------------------------------------- | ----------------------------------------- |
| [`executeCode`](/reference/mcp-tools#executecode) | Run Python code with MCP tool integration |
### Custom Tool Management (5 tools)
| Tool | Description |
| ------------------------------------------------------------------- | ------------------------------------------------- |
| [`createCustomTool`](/reference/mcp-tools#createcustomtool) | Deploy Python workflows as reusable API endpoints |
| [`updateCustomTool`](/reference/mcp-tools#updatecustomtool) | Modify existing custom tools |
| [`getCustomToolDetails`](/reference/mcp-tools#getcustomtooldetails) | Get full specs, code, and curl examples |
| [`submitCustomToolRun`](/reference/mcp-tools#submitcustomtoolrun) | Execute a deployed custom tool |
| [`checkRunStatus`](/reference/mcp-tools#checkrunstatus) | Monitor custom tool execution progress |
### Tool Discovery & Execution (3 tools)
| Tool | Description |
| ------------------------------------------------------- | -------------------------------------- |
| [`searchTools`](/reference/mcp-tools#searchtools) | Find tools by functionality or keyword |
| [`getToolDetails`](/reference/mcp-tools#gettooldetails) | Get comprehensive tool documentation |
| [`executeTool`](/reference/mcp-tools#executetool) | Execute any MCP tool by alias name |
### MCP Server Management (6 tools)
| Tool | Description |
| ---------------------------------------------------------------------------- | -------------------------------------- |
| [`addRemoteMcpServer`](/reference/mcp-tools#addremotemcpserver) | Connect external MCP servers |
| [`searchBuiltInServers`](/reference/mcp-tools#searchbuiltinservers) | Browse pre-configured server templates |
| [`getBuiltInServerDetails`](/reference/mcp-tools#getbuiltinserverdetails) | View server requirements and config |
| [`checkRemoteMcpOauthStatus`](/reference/mcp-tools#checkrmotemcpoauthstatus) | Monitor OAuth authentication flows |
| [`ReAuthRemoteMcpServer`](/reference/mcp-tools#reauthremotemcpserver) | Reauthenticate expired connections |
| [`updateRemoteMcpServer`](/reference/mcp-tools#updateremotemcpserver) | Update server URLs and credentials |
### Utilities (1 tool)
| Tool | Description |
| --------------------------------------------------------- | ------------------------------ |
| [`datagen-sdk-doc`](/reference/mcp-tools#datagen-sdk-doc) | Fetch Python SDK documentation |
See every tool with complete parameter tables, return types, and examples.
# MCP Tools Reference
Source: https://datagen.dev/reference/mcp-tools
Complete parameter reference for all DataGen MCP tools
## Code Execution
### executeCode
Execute Python code with MCP tool integration in a remote sandbox.
| Parameter | Type | Required | Default | Description |
| -------------------- | --------- | -------- | ------- | ----------------------------------------------------------- |
| `script` | string | Yes | -- | Python code to execute |
| `name` | string | No | -- | Descriptive name for tracking |
| `description` | string | No | -- | Brief description of what the code does |
| `session_id` | string | No | -- | Session ID to group related executions |
| `input_vars` | object | No | -- | Variables available in the script |
| `output_vars` | object | No | -- | Expected output variables and types |
| `required_tools` | string\[] | No | -- | Required MCP tools (e.g., `["mcp_Supabase_list_projects"]`) |
| `additional_imports` | string\[] | No | -- | PyPI packages to import (package names only) |
| `local` | boolean | No | -- | Run locally (true) or in E2B sandbox (false) |
| `mcp_server_names` | string\[] | No | -- | MCP servers to spin up (reduces startup time) |
| `timeout` | number | No | 300 | Execution timeout in seconds (30-300) |
| `required_secrets` | string\[] | No | -- | Secret names to inject as Python variables |
**Notes:** Supports Python 3.12, synchronous code only. Use `httpx` for HTTP requests (not `requests`). Use `ThreadPoolExecutor` for I/O-bound workloads.
***
## Custom Tool Management
### createCustomTool
Deploy a Python workflow as a reusable API endpoint.
| Parameter | Type | Required | Default | Description |
| -------------------- | ------------------------- | -------- | ----------- | ---------------------------------------------------- |
| `script` | string | Yes | -- | Python code to deploy |
| `deployment_name` | string | Yes | -- | API name (e.g., `sync_supabase_to_heyreach`) |
| `description` | string | Yes | -- | What the custom tool does |
| `input_schema` | object | No | -- | OpenAPI/JSON Schema for input validation |
| `output_variables` | string\[] | No | -- | Output variable names (e.g., `["result", "status"]`) |
| `required_tools` | string\[] | No | -- | Required MCP tools |
| `additional_imports` | string\[] | No | -- | Python packages (names only, no versions) |
| `deployment_type` | `"private"` \| `"public"` | No | `"private"` | Visibility |
| `is_code_public` | boolean | No | false | Whether source code is visible when public |
| `local` | boolean | No | -- | Run locally or in E2B sandbox |
| `mcp_server_names` | string\[] | No | -- | MCP server names for tools |
| `default_input_vars` | object | No | -- | Default values for input variables |
| `required_secrets` | string\[] | No | -- | Secret names from secret management |
**Returns:** `deployment_uuid` on success.
### updateCustomTool
Update an existing custom tool. Only provided fields are updated.
| Parameter | Type | Required | Default | Description |
| -------------------- | ------------------------- | -------- | ------- | ----------------------------- |
| `custom_tool_uuid` | string | Yes | -- | UUID of the tool to update |
| `name` | string | No | -- | Updated name |
| `description` | string | No | -- | Updated description |
| `final_code` | string | No | -- | Updated Python code |
| `input_schema` | object | No | -- | Updated input schema |
| `output_variables` | string\[] | No | -- | Updated output variable names |
| `default_input_vars` | object | No | -- | Updated default input values |
| `additional_imports` | string\[] | No | -- | Updated Python imports |
| `expected_tools` | string\[] | No | -- | Updated required MCP tools |
| `required_secrets` | string\[] | No | -- | Updated required secrets |
| `is_code_public` | boolean | No | -- | Toggle source code visibility |
| `deployment_type` | `"private"` \| `"public"` | No | -- | Toggle deployment visibility |
| `mcp_server_names` | string\[] | No | -- | Updated MCP server names |
### getCustomToolDetails
Get full specs, code, input examples, and curl commands for a custom tool.
| Parameter | Type | Required | Default | Description |
| ------------------ | ------- | -------- | ------- | --------------------------------------------------------- |
| `custom_tool_uuid` | string | Yes | -- | UUID of the custom tool |
| `brief` | boolean | No | false | True for essential info only (name, description, schemas) |
### submitCustomToolRun
Execute a deployed custom tool asynchronously. Returns a `run_uuid` to monitor with `checkRunStatus`.
| Parameter | Type | Required | Default | Description |
| ------------------ | ------ | -------- | ------- | ---------------------------------------------------------------- |
| `custom_tool_uuid` | string | Yes | -- | UUID of the custom tool to execute |
| `input_vars` | object | No | -- | Input data (e.g., `{"url": "https://example.com", "count": 10}`) |
### checkRunStatus
Monitor the progress and results of a custom tool run with automatic polling.
| Parameter | Type | Required | Default | Description |
| ----------------------- | ------ | -------- | ------- | -------------------------------------------- |
| `run_uuid` | string | No | -- | Run UUID from `submitCustomToolRun` |
| `custom_tool_uuid` | string | No | -- | Custom tool UUID to find the most recent run |
| `timeout_seconds` | number | No | 180 | Max wait time (max 600) |
| `poll_interval_seconds` | number | No | 5 | Seconds between checks (2-30) |
Provide either `run_uuid` or `custom_tool_uuid`.
***
## Tool Discovery & Execution
### searchTools
Find tools by functionality, keywords, or provider.
| Parameter | Type | Required | Default | Description |
| ---------- | ------ | -------- | ------- | ------------------------------------------------ |
| `query` | string | Yes | -- | What you want to accomplish (e.g., "send email") |
| `provider` | string | No | -- | Filter by provider (e.g., "Supabase", "GitHub") |
| `limit` | number | No | 10 | Max results (1-100) |
| `offset` | number | No | 0 | Skip N results for pagination |
### getToolDetails
Get comprehensive documentation for a specific tool.
| Parameter | Type | Required | Default | Description |
| ----------- | ------ | -------- | ------- | -------------------------------------------------- |
| `tool_name` | string | Yes | -- | Exact tool name (e.g., `mcp_Supabase_execute_sql`) |
### executeTool
Execute any MCP or default tool by its alias name.
| Parameter | Type | Required | Default | Description |
| ----------------- | ------ | -------- | ------- | --------------------------------------------------- |
| `tool_alias_name` | string | Yes | -- | Tool alias (e.g., `mcp_github_search_repositories`) |
| `parameters` | object | No | -- | Parameters as key-value pairs |
***
## MCP Server Management
### addRemoteMcpServer
Connect an external MCP server. Supports template-based (with auto OAuth) or manual URL.
| Parameter | Type | Required | Default | Description |
| ------------- | ------ | -------- | ------- | ----------------------------------------------------------- |
| `template_id` | string | No | -- | Template ID for pre-configured servers (e.g., `linear-mcp`) |
| `server_name` | string | No | -- | Display name (CamelCase, e.g., `GoogleDrive`) |
| `server_url` | string | No | -- | Server endpoint URL |
| `credentials` | object | No | -- | API keys/tokens required by the template |
Provide either `template_id` or `server_name` + `server_url`.
### searchBuiltInServers
Browse pre-configured MCP server templates.
| Parameter | Type | Required | Default | Description |
| --------- | ------ | -------- | ------- | ------------------------------------------- |
| `name` | string | No | -- | Filter by name (case-insensitive substring) |
### getBuiltInServerDetails
Get full configuration details for a built-in server template.
| Parameter | Type | Required | Default | Description |
| ------------- | ------ | -------- | ------- | --------------------------------------- |
| `template_id` | string | Yes | -- | Template ID from `searchBuiltInServers` |
### checkRemoteMcpOauthStatus
Poll for OAuth completion after receiving an auth URL from `addRemoteMcpServer`.
| Parameter | Type | Required | Default | Description |
| ----------------- | ------ | -------- | ------- | --------------------------------------- |
| `flow_id` | string | Yes | -- | OAuth flow ID from `addRemoteMcpServer` |
| `timeout_seconds` | number | No | 120 | Max wait time (max 300) |
### ReAuthRemoteMcpServer
Reauthenticate an existing MCP server with expired OAuth tokens.
| Parameter | Type | Required | Default | Description |
| ------------- | ------ | -------- | ------- | --------------------------------------- |
| `server_name` | string | Yes | -- | Server name (CamelCase, e.g., `GitHub`) |
### updateRemoteMcpServer
Update an existing MCP server's URL and credentials.
| Parameter | Type | Required | Default | Description |
| ------------- | ------ | -------- | ------- | ------------------------------------ |
| `server_name` | string | Yes | -- | Server name (CamelCase) |
| `server_url` | string | Yes | -- | New endpoint URL |
| `env_args` | object | Yes | -- | Updated environment variables/config |
***
## Utilities
### datagen-sdk-doc
Fetch the DataGen Python SDK documentation from GitHub. Returns the README content without images.
**Parameters:** None
# Python SDK Reference
Source: https://datagen.dev/reference/sdk-python
Complete API reference for the DataGen Python SDK
## Installation
```bash theme={null}
pip install datagen-python-sdk
```
Requires Python 3.10+.
## Client Configuration
```python theme={null}
from datagen_sdk import DatagenClient
client = DatagenClient(
api_key=None, # Default: reads from DATAGEN_API_KEY env var
base_url="https://api.datagen.dev",
timeout=30, # Request timeout in seconds
retries=0, # Retry attempts for failed requests
backoff_seconds=0.5 # Initial backoff (exponential with 2^attempt multiplier)
)
```
| Parameter | Type | Default | Description |
| ----------------- | --------------- | --------------------------- | ------------------------------------------------ |
| `api_key` | `Optional[str]` | `None` | API key. Falls back to `DATAGEN_API_KEY` env var |
| `base_url` | `str` | `"https://api.datagen.dev"` | DataGen API base URL |
| `timeout` | `int` | `30` | Request timeout in seconds |
| `retries` | `int` | `0` | Number of retry attempts |
| `backoff_seconds` | `float` | `0.5` | Initial backoff time for retries |
***
## Tool Execution
### `execute_tool`
Execute an MCP tool by its alias name.
```python theme={null}
result = client.execute_tool(
tool_alias_name: str,
parameters: Optional[Dict[str, Any]] = None
) -> Any
```
| Parameter | Type | Required | Description |
| ----------------- | ---------------- | -------- | ------------------------------------------------- |
| `tool_alias_name` | `str` | Yes | Tool alias (e.g., `"mcp_Gmail_gmail_send_email"`) |
| `parameters` | `Dict[str, Any]` | No | Tool-specific parameters |
**Returns:** Tool execution result (type varies by tool).
**Raises:** `DatagenAuthError`, `DatagenToolError`, `DatagenHttpError`
***
## Custom Tool Deployment
### `deploy_custom_tool`
Deploy a Python workflow as an API endpoint.
```python theme={null}
result = client.deploy_custom_tool(
name: str,
code: str,
description: Optional[str] = None,
input_schema: Optional[Dict[str, Any]] = None,
output_vars: Optional[List[str]] = None,
expected_tools: Optional[List[str]] = None,
additional_imports: Optional[List[str]] = None,
deployment_type: str = "private",
default_input_vars: Optional[Dict[str, Any]] = None,
mcp_server_names: Optional[List[str]] = None,
required_secrets: Optional[List[str]] = None,
) -> Dict[str, Any]
```
| Parameter | Type | Required | Default | Description |
| -------------------- | ----------- | -------- | ----------- | ------------------------------ |
| `name` | `str` | Yes | -- | API name for the tool |
| `code` | `str` | Yes | -- | Python code to deploy |
| `description` | `str` | No | `None` | Tool description |
| `input_schema` | `Dict` | No | `None` | OpenAPI/JSON Schema for inputs |
| `output_vars` | `List[str]` | No | `None` | Output variable names |
| `expected_tools` | `List[str]` | No | `None` | Required MCP tools |
| `additional_imports` | `List[str]` | No | `None` | Python packages |
| `deployment_type` | `str` | No | `"private"` | `"private"` or `"public"` |
| `default_input_vars` | `Dict` | No | `None` | Default input values |
| `mcp_server_names` | `List[str]` | No | `None` | MCP server names |
| `required_secrets` | `List[str]` | No | `None` | Required secret names |
**Returns:** `Dict` with `deployment_uuid` and deployment details.
**Raises:** `DatagenDeploymentError`
### `update_custom_tool`
Update an existing custom tool. Only provided fields are updated.
```python theme={null}
result = client.update_custom_tool(
deployment_uuid: str,
name: Optional[str] = None,
description: Optional[str] = None,
code: Optional[str] = None,
input_schema: Optional[Dict[str, Any]] = None,
output_vars: Optional[List[str]] = None,
default_input_vars: Optional[Dict[str, Any]] = None,
additional_imports: Optional[List[str]] = None,
expected_tools: Optional[List[str]] = None,
required_secrets: Optional[List[str]] = None,
) -> Dict[str, Any]
```
| Parameter | Type | Required | Description |
| -------------------- | ----------- | -------- | -------------------------- |
| `deployment_uuid` | `str` | Yes | UUID of the tool to update |
| `name` | `str` | No | Updated name |
| `description` | `str` | No | Updated description |
| `code` | `str` | No | Updated Python code |
| `input_schema` | `Dict` | No | Updated input schema |
| `output_vars` | `List[str]` | No | Updated output variables |
| `default_input_vars` | `Dict` | No | Updated default inputs |
| `additional_imports` | `List[str]` | No | Updated imports |
| `expected_tools` | `List[str]` | No | Updated required tools |
| `required_secrets` | `List[str]` | No | Updated required secrets |
**Returns:** `Dict` with updated deployment details.
**Raises:** `DatagenDeploymentError`
### `get_custom_tool`
Get details of a custom tool.
```python theme={null}
result = client.get_custom_tool(deployment_uuid: str) -> Dict[str, Any]
```
### `list_custom_tools`
List all custom tools.
```python theme={null}
result = client.list_custom_tools(
sort_by: str = "created_at",
order_by: str = "desc",
skip: int = 0,
limit: int = 100,
) -> List[Dict[str, Any]]
```
| Parameter | Type | Default | Description |
| ---------- | ----- | -------------- | ------------------- |
| `sort_by` | `str` | `"created_at"` | Sort field |
| `order_by` | `str` | `"desc"` | `"asc"` or `"desc"` |
| `skip` | `int` | `0` | Pagination offset |
| `limit` | `int` | `100` | Max results |
***
## Custom Tool Execution
### `run_custom_tool`
Run a custom tool synchronously (blocks until complete).
```python theme={null}
result = client.run_custom_tool(
deployment_uuid: str,
input_vars: Optional[Dict[str, Any]] = None,
execution_timeout: int = 120,
) -> Dict[str, Any]
```
| Parameter | Type | Required | Default | Description |
| ------------------- | ------ | -------- | ------- | ----------------------------- |
| `deployment_uuid` | `str` | Yes | -- | Tool UUID |
| `input_vars` | `Dict` | No | `None` | Input variables |
| `execution_timeout` | `int` | No | `120` | Max execution time in seconds |
**Returns:** `Dict` with `run_uuid`, `status`, and `output_vars`.
**Raises:** `DatagenDeploymentError`
### `run_custom_tool_async`
Run a custom tool asynchronously (returns immediately).
```python theme={null}
result = client.run_custom_tool_async(
deployment_uuid: str,
input_vars: Optional[Dict[str, Any]] = None,
execution_timeout: int = 120,
) -> Dict[str, Any]
```
Same parameters as `run_custom_tool`.
**Returns:** `Dict` with `run_uuid` and `status: "pending"`.
**Raises:** `DatagenDeploymentError`
### `check_run_status`
Check the status of a custom tool run.
```python theme={null}
result = client.check_run_status(run_uuid: str) -> Dict[str, Any]
```
**Returns:** `Dict` with `run_uuid` and `status` (`"pending"`, `"running"`, `"completed"`, or `"failed"`).
### `get_run`
Get full details of a custom tool run including output.
```python theme={null}
result = client.get_run(run_uuid: str) -> Dict[str, Any]
```
**Returns:** `Dict` with complete run details including `output_vars`.
### `wait_for_run`
Poll until an async run completes or fails.
```python theme={null}
result = client.wait_for_run(
run_uuid: str,
timeout: int = 300,
poll_interval: float = 2.0,
) -> Dict[str, Any]
```
| Parameter | Type | Default | Description |
| --------------- | ------- | ------- | ----------------------------- |
| `run_uuid` | `str` | -- | Run UUID |
| `timeout` | `int` | `300` | Max wait time in seconds |
| `poll_interval` | `float` | `2.0` | Seconds between status checks |
**Returns:** Final run result with `output_vars`.
**Raises:** `DatagenDeploymentError` on failure or timeout.
***
## Secret Management
### `list_secrets`
List all secrets (values are never returned).
```python theme={null}
result = client.list_secrets() -> List[Dict[str, Any]]
```
**Returns:** List of secret metadata (`name`, `masked_value`, `provider`, etc.).
### `set_secret`
Create or update a secret.
```python theme={null}
result = client.set_secret(
name: str,
value: str,
display_name: Optional[str] = None,
description: Optional[str] = None,
category: str = "api_key",
force: bool = False,
) -> Dict[str, Any]
```
| Parameter | Type | Required | Default | Description |
| -------------- | ------ | -------- | ----------- | ------------------------------------------------ |
| `name` | `str` | Yes | -- | Secret name (alphanumeric, underscores, hyphens) |
| `value` | `str` | Yes | -- | Secret value |
| `display_name` | `str` | No | `None` | Human-readable name |
| `description` | `str` | No | `None` | Description |
| `category` | `str` | No | `"api_key"` | Secret category |
| `force` | `bool` | No | `False` | If True, updates existing secret |
**Raises:** `DatagenSecretError` if secret exists and `force=False`.
***
## Error Types
All exceptions inherit from `DatagenError`.
| Exception | Description |
| ------------------------ | -------------------------------------------------- |
| `DatagenError` | Base exception class |
| `DatagenAuthError` | Authentication failed (401/403) or missing API key |
| `DatagenToolError` | Tool execution failed |
| `DatagenHttpError` | HTTP-level errors (4xx/5xx) |
| `DatagenDeploymentError` | Custom tool deployment or run failed |
| `DatagenSecretError` | Secret management errors |
```python theme={null}
from datagen_sdk import (
DatagenClient,
DatagenError,
DatagenAuthError,
DatagenToolError,
DatagenHttpError,
DatagenDeploymentError,
DatagenSecretError,
)
```
# TypeScript SDK Reference
Source: https://datagen.dev/reference/sdk-typescript
Complete API reference for the DataGen TypeScript SDK
## Installation
```bash npm theme={null}
npm install @datagen-dev/typescript-sdk
```
```bash yarn theme={null}
yarn add @datagen-dev/typescript-sdk
```
```bash pnpm theme={null}
pnpm add @datagen-dev/typescript-sdk
```
Requires Node.js 18+ and TypeScript 5.0+.
## Client Configuration
```typescript theme={null}
import { DatagenClient } from '@datagen-dev/typescript-sdk';
const client = new DatagenClient({
apiKey: undefined, // Default: reads from DATAGEN_API_KEY env var
baseUrl: "https://api.datagen.dev",
timeout: 30000, // Request timeout in ms
retries: 0, // Retry attempts for failed requests
backoffSeconds: 0.5 // Initial backoff for retries
});
```
| Parameter | Type | Default | Description |
| ---------------- | --------- | --------------------------- | ------------------------------------------------ |
| `apiKey` | `string?` | `undefined` | API key. Falls back to `DATAGEN_API_KEY` env var |
| `baseUrl` | `string` | `"https://api.datagen.dev"` | DataGen API base URL |
| `timeout` | `number` | `30000` | Request timeout in milliseconds |
| `retries` | `number` | `0` | Number of retry attempts |
| `backoffSeconds` | `number` | `0.5` | Initial backoff time for retries |
***
## Tool Execution
### `executeTool`
Execute an MCP tool by its alias name.
```typescript theme={null}
const result = await client.executeTool(
toolAliasName: string,
parameters?: Record
): Promise
```
| Parameter | Type | Required | Description |
| --------------- | --------------------- | -------- | ------------------------------------------------- |
| `toolAliasName` | `string` | Yes | Tool alias (e.g., `"mcp_Gmail_gmail_send_email"`) |
| `parameters` | `Record` | No | Tool-specific parameters |
**Returns:** Tool execution result.
**Throws:** `DatagenAuthError`, `DatagenToolError`, `DatagenHttpError`
***
## Custom Tool Deployment
### `deployCustomTool`
Deploy a Python workflow as an API endpoint.
```typescript theme={null}
const result = await client.deployCustomTool({
name: string,
code: string,
description?: string,
inputSchema?: Record,
outputVars?: string[],
expectedTools?: string[],
additionalImports?: string[],
deploymentType?: "private" | "public",
defaultInputVars?: Record,
mcpServerNames?: string[],
requiredSecrets?: string[],
}): Promise
```
| Parameter | Type | Required | Default | Description |
| ------------------- | ---------- | -------- | ----------- | ------------------------------ |
| `name` | `string` | Yes | -- | API name for the tool |
| `code` | `string` | Yes | -- | Python code to deploy |
| `description` | `string` | No | -- | Tool description |
| `inputSchema` | `object` | No | -- | OpenAPI/JSON Schema for inputs |
| `outputVars` | `string[]` | No | -- | Output variable names |
| `expectedTools` | `string[]` | No | -- | Required MCP tools |
| `additionalImports` | `string[]` | No | -- | Python packages |
| `deploymentType` | `string` | No | `"private"` | `"private"` or `"public"` |
| `defaultInputVars` | `object` | No | -- | Default input values |
| `mcpServerNames` | `string[]` | No | -- | MCP server names |
| `requiredSecrets` | `string[]` | No | -- | Required secret names |
**Returns:** Object with `deploymentUuid` and deployment details.
**Throws:** `DatagenDeploymentError`
### `updateCustomTool`
Update an existing custom tool. Only provided fields are updated.
```typescript theme={null}
const result = await client.updateCustomTool(
deploymentUuid: string,
updates: {
name?: string,
description?: string,
code?: string,
inputSchema?: Record,
outputVars?: string[],
defaultInputVars?: Record,
additionalImports?: string[],
expectedTools?: string[],
requiredSecrets?: string[],
}
): Promise
```
### `getCustomTool`
```typescript theme={null}
const result = await client.getCustomTool(deploymentUuid: string): Promise
```
### `listCustomTools`
```typescript theme={null}
const result = await client.listCustomTools({
sortBy?: string, // Default: "created_at"
orderBy?: string, // Default: "desc"
skip?: number, // Default: 0
limit?: number, // Default: 100
}): Promise
```
***
## Custom Tool Execution
### `runCustomTool`
Run synchronously (blocks until complete).
```typescript theme={null}
const result = await client.runCustomTool(
deploymentUuid: string,
inputVars?: Record,
executionTimeout?: number // Default: 120
): Promise
```
### `runCustomToolAsync`
Run asynchronously (returns immediately).
```typescript theme={null}
const result = await client.runCustomToolAsync(
deploymentUuid: string,
inputVars?: Record,
executionTimeout?: number // Default: 120
): Promise<{ runUuid: string, status: "pending" }>
```
### `checkRunStatus`
```typescript theme={null}
const result = await client.checkRunStatus(runUuid: string): Promise
```
### `getRun`
```typescript theme={null}
const result = await client.getRun(runUuid: string): Promise
```
### `waitForRun`
Poll until an async run completes.
```typescript theme={null}
const result = await client.waitForRun(
runUuid: string,
timeout?: number, // Default: 300
pollInterval?: number // Default: 2.0
): Promise
```
***
## Secret Management
### `listSecrets`
```typescript theme={null}
const result = await client.listSecrets(): Promise
```
### `setSecret`
```typescript theme={null}
const result = await client.setSecret({
name: string,
value: string,
displayName?: string,
description?: string,
category?: string, // Default: "api_key"
force?: boolean, // Default: false
}): Promise
```
***
## Error Types
```typescript theme={null}
import {
DatagenClient,
DatagenError,
DatagenAuthError,
DatagenToolError,
DatagenHttpError,
DatagenDeploymentError,
DatagenSecretError,
} from '@datagen-dev/typescript-sdk';
```
| Exception | Description |
| ------------------------ | ------------------------------- |
| `DatagenError` | Base exception class |
| `DatagenAuthError` | Authentication failed (401/403) |
| `DatagenToolError` | Tool execution failed |
| `DatagenHttpError` | HTTP-level errors |
| `DatagenDeploymentError` | Deployment or run failed |
| `DatagenSecretError` | Secret management errors |