API & Developers
Complete endpoint reference for the Growhold REST API. To use Growhold from an AI assistant instead of code, see the MCP guide: the same actions as tools, no code needed.
Authentication
All API requests require an API key. Create and manage keys from the API & Devs page in your workspace settings.
API keys
API keys start with gh_ and are scoped with permissions for specific domains: knowledge, runs, schedules, agents, and specialists. Keys are hashed before storage. Copy your secret immediately after creation.
Request format
All API calls use a single POST endpoint with action-based routing. Send your key as a Bearer token and the action as a JSON field.
Base URL
https://api.growhold.com/v1
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "agents.list"}'Knowledge
Add, list, remove, and apply knowledge entries to agents and specialists.
knowledge.list
List knowledge entries, optionally filtered by specialist or build.
| Name | Type | Required | Description |
|---|---|---|---|
specialist_id | string | No | Filter by specialist |
build_id | string | No | Filter by build |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "knowledge.list"}'Response
{
"knowledge": [
{
"id": "uuid",
"name": "Product FAQ",
"type": "text",
"chunk_count": 12,
"created_at": "2026-03-01T10:00:00Z"
}
]
}knowledge.add
Add a knowledge entry. Provide either text content or a file URL. Content is automatically chunked and embedded.
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name |
content | string | No | Text content (use this or file_url) |
file_url | string | No | URL to a file to ingest |
specialist_id | string | No | Attach to specialist |
build_id | string | No | Attach to build |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{
"action": "knowledge.add",
"name": "Product FAQ",
"content": "Q: What is Growhold?\nA: An AI agent platform."
}'Response
{
"knowledge": {
"id": "new-uuid",
"name": "Product FAQ",
"type": "text",
"chunk_count": 3
}
}knowledge.remove
Remove a knowledge entry and all its embeddings.
| Name | Type | Required | Description |
|---|---|---|---|
knowledge_id | string | Yes | Entry to remove |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "knowledge.remove", "knowledge_id": "uuid"}'Response
{ "deleted": true }knowledge.apply
File a knowledge entry into one of its three homes: the workspace, a specialist, or a build. Filing it in one clears the others.
| Name | Type | Required | Description |
|---|---|---|---|
knowledge_id | string | Yes | Knowledge entry |
workspace | boolean | No | Apply to the whole workspace |
specialist_id | string | No | Target specialist |
build_id | string | No | Target build |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "knowledge.apply", "knowledge_id": "uuid", "specialist_id": "specialist-uuid"}'Response
{ "applied": true }Agent Runs
Start, monitor, pause, and stop agent runs. Retrieve output cards with content, images, and charts.
runs.list
List agent runs, newest first.
| Name | Type | Required | Description |
|---|---|---|---|
agent_id | string | No | Filter by agent |
limit | number | No | Max results (default 50) |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "runs.list"}'Response
{
"runs": [
{
"id": "run-uuid",
"name": "Market Analysis Q1",
"auto_status": "completed",
"created_at": "2026-03-31T10:00:00Z",
"agent": { "id": "agent-uuid", "name": "Market Analyzer" }
}
]
}runs.get
Get full details of a run including cards, assistant progress, and status.
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | The run ID |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "runs.get", "run_id": "run-uuid"}'Response
{
"run": {
"id": "run-uuid",
"name": "Market Analysis Q1",
"auto_status": "completed",
"card": [
{
"id": "card-uuid",
"order_id": 1,
"markdown_content": "## Analysis\n..."
}
],
"run_assistant": [
{ "id": "ra-uuid", "summary": "Completed" }
]
}
}runs.start
Start a new async agent run. Returns immediately with the run ID. Poll runs.get for status.
| Name | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent to run |
name | string | No | Custom run name |
goal | string | No | Goal for the run |
input_values | object | No | Input field values |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{
"action": "runs.start",
"agent_id": "agent-uuid",
"name": "Weekly Report",
"goal": "Generate the weekly market report"
}'Response
{
"run_id": "new-run-uuid",
"name": "Weekly Report",
"status": "running"
}runs.stop
Stop a running agent permanently.
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | Run to stop |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "runs.stop", "run_id": "run-uuid"}'Response
{ "run_id": "run-uuid", "status": "stopped" }runs.delete
Permanently delete a run and its cards. Without confirm the call deletes nothing and returns what would be lost.
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | Run to delete |
confirm | boolean | No | Must be true to actually delete |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "runs.delete", "run_id": "run-uuid", "confirm": true}'Response
{ "deleted": true, "run": { "id": "run-uuid", "name": "Weekly Report", "status": "completed", "build_id": "build-uuid" }, "cards": 3 }runs.pause
Pause a running agent. Use runs.resume to continue.
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | Run to pause |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "runs.pause", "run_id": "run-uuid"}'Response
{ "run_id": "run-uuid", "status": "paused" }runs.resume
Resume a paused agent run.
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | Run to resume |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "runs.resume", "run_id": "run-uuid"}'Response
{ "run_id": "run-uuid", "status": "running" }Deliverable Reviews
A build is read as deliverables: one per agent, its latest completed run. When a run completes, its result is compared with the other deliverables in the build, and every material conflict becomes a review: what disagrees, which run raised it, and for small conflicts the deliverable rewritten with the smallest change. Nothing is applied until it is accepted. Reviews use the runs permission.
reviews.list
Reviews in a build. Proposed reviews wait for a decision; a tune carries proposed_markdown, a rerun does not.
| Name | Type | Required | Description |
|---|---|---|---|
build_id | string | Yes | Build to list reviews for |
status | string | No | proposed (default), accepted, dismissed, superseded or all |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "reviews.list", "build_id": "build-uuid"}'Response
{
"reviews": [
{
"id": "review-uuid",
"source_run_id": "run-uuid",
"target_run_id": "run-uuid",
"direction": "downstream",
"severity": "tune",
"conflict": "The spec blocks bar edits after locking; the design treats an edited bar as a new bar.",
"change_summary": "Replaces the bar edit row and the change log in the data model.",
"proposed_markdown": "# Product Specification ...",
"status": "proposed",
"created_at": "2026-10-30T12:03:48Z"
}
]
}reviews.check
Compare a run's result (default: the latest completed run) with the build's other deliverables. Runs do this on completion by themselves; call it to re-check on request.
| Name | Type | Required | Description |
|---|---|---|---|
build_id | string | Yes | Build to check |
run_id | string | No | Run whose result to compare; default the latest completed run |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "reviews.check", "build_id": "build-uuid"}'Response
{ "reviews": [ ... ] }reviews.accept
Apply a tune. The deliverable's card is rewritten with the proposed text, or with the markdown passed here; the text it replaces is kept on the review.
| Name | Type | Required | Description |
|---|---|---|---|
build_id | string | Yes | The review's build |
review_id | string | Yes | Review to accept |
markdown | string | No | Card text to apply instead of the proposed one |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "reviews.accept", "build_id": "build-uuid", "review_id": "review-uuid"}'Response
{ "review": { "id": "review-uuid", "status": "accepted", "previous_markdown": "...", "applied_markdown": "..." } }reviews.dismiss
Leave the deliverable as it is and close the review.
| Name | Type | Required | Description |
|---|---|---|---|
build_id | string | Yes | The review's build |
review_id | string | Yes | Review to dismiss |
note | string | No | Why the deliverable stands |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "reviews.dismiss", "build_id": "build-uuid", "review_id": "review-uuid", "note": "The later run is the one to revisit"}'Response
{ "review": { "id": "review-uuid", "status": "dismissed" } }Cards
Retrieve output cards with markdown content, structured JSON, images, and charts. File URLs are signed and valid for 1 hour.
cards.list
List output cards for a run.
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | Yes | The run ID |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "cards.list", "run_id": "run-uuid"}'Response
{
"cards": [
{
"id": "card-uuid",
"order_id": 1,
"markdown_content": "## Report\n...",
"image_url": "https://...",
"is_starred": true
}
]
}cards.get
Get a single card with full content and attached files (images, charts). File URLs are signed.
| Name | Type | Required | Description |
|---|---|---|---|
card_id | string | Yes | The card ID |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "cards.get", "card_id": "card-uuid"}'Response
{
"card": {
"id": "card-uuid",
"markdown_content": "## Report\n...",
"content_json": { ... },
"image_url": "https://..."
},
"files": [
{
"id": "file-uuid",
"file_name": "chart.png",
"signed_url": "https://..."
}
]
}Schedules
Create and manage scheduled agent runs using cron expressions.
schedules.list
List all schedules in the workspace.
| Name | Type | Required | Description |
|---|---|---|---|
agent_id | string | No | Filter by agent |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "schedules.list"}'Response
{
"schedules": [
{
"id": "schedule-uuid",
"name": "Weekly Report",
"cron": "0 9 * * 1",
"is_active": true,
"next_run_at": "2026-03-31T09:00:00Z"
}
]
}schedules.create
Create a new schedule.
| Name | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent to schedule |
name | string | Yes | Schedule name |
cron | string | Yes | Cron expression (e.g. "0 9 * * 1") |
goal | string | No | Goal for each run |
input_values | object | No | Input values per run |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{
"action": "schedules.create",
"agent_id": "agent-uuid",
"name": "Daily Summary",
"cron": "0 8 * * *"
}'Response
{
"schedule": {
"id": "new-uuid",
"name": "Daily Summary",
"cron": "0 8 * * *",
"is_active": true
}
}schedules.update
Update schedule settings. Only provided fields are changed.
| Name | Type | Required | Description |
|---|---|---|---|
schedule_id | string | Yes | Schedule ID |
name | string | No | New name |
cron | string | No | New cron expression |
goal | string | No | New goal |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "schedules.update", "schedule_id": "uuid", "cron": "0 10 * * 1-5"}'Response
{ "schedule": { "id": "uuid", "cron": "0 10 * * 1-5", "is_active": true } }schedules.delete
Delete a schedule permanently.
| Name | Type | Required | Description |
|---|---|---|---|
schedule_id | string | Yes | Schedule to delete |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "schedules.delete", "schedule_id": "uuid"}'Response
{ "deleted": true }schedules.pause
Pause a schedule. Runs stop triggering until resumed.
| Name | Type | Required | Description |
|---|---|---|---|
schedule_id | string | Yes | Schedule to pause |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "schedules.pause", "schedule_id": "uuid"}'Response
{ "schedule_id": "uuid", "is_active": false }schedules.resume
Resume a paused schedule.
| Name | Type | Required | Description |
|---|---|---|---|
schedule_id | string | Yes | Schedule to resume |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "schedules.resume", "schedule_id": "uuid"}'Response
{ "schedule_id": "uuid", "is_active": true }Cron expression reference
# Format: minute hour day-of-month month day-of-week # # "0 9 * * *" Every day at 9:00 AM UTC # "0 9 * * 1" Every Monday at 9:00 AM UTC # "0 9 * * 1-5" Weekdays at 9:00 AM UTC # "0 */6 * * *" Every 6 hours # "30 14 1 * *" 1st of each month at 2:30 PM UTC
Agents & Specialists
List and inspect agents and specialists in your workspace.
agents.list
List all agents with their assistants.
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "agents.list"}'Response
{
"agents": [
{
"id": "agent-uuid",
"name": "Market Analyzer",
"deliverable": "Market Report",
"assistant": [
{ "id": "asst-uuid", "name": "Research Analyst" }
]
}
]
}agents.get
Get agent details.
| Name | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent ID |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "agents.get", "agent_id": "agent-uuid"}'Response
{ "agent": { "id": "agent-uuid", "name": "Market Analyzer", ... } }specialists.list
List all specialists.
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "specialists.list"}'Response
{
"specialists": [
{ "id": "uuid", "name": "SEO Expert", "is_default": false }
]
}specialists.get
Get specialist details.
| Name | Type | Required | Description |
|---|---|---|---|
specialist_id | string | Yes | Specialist ID |
Example
curl -X POST https://api.growhold.com/v1 \
-H "Authorization: Bearer gh_your_key" \
-H "Content-Type: application/json" \
-d '{"action": "specialists.get", "specialist_id": "uuid"}'Response
{ "specialist": { "id": "uuid", "name": "SEO Expert", ... } }Error Handling
API errors return a JSON object with an error field and an appropriate HTTP status code.
{ "error": "Invalid or expired API key" }| Status | Meaning |
|---|---|
| 400 | Bad request, missing or invalid parameters |
| 401 | Missing or invalid API key |
| 403 | Insufficient permissions for this action |
| 404 | Resource not found |
| 500 | Internal server error |