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.

NameTypeRequiredDescription
specialist_idstringNoFilter by specialist
build_idstringNoFilter 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.

NameTypeRequiredDescription
namestringYesDisplay name
contentstringNoText content (use this or file_url)
file_urlstringNoURL to a file to ingest
specialist_idstringNoAttach to specialist
build_idstringNoAttach 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.

NameTypeRequiredDescription
knowledge_idstringYesEntry 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.

NameTypeRequiredDescription
knowledge_idstringYesKnowledge entry
workspacebooleanNoApply to the whole workspace
specialist_idstringNoTarget specialist
build_idstringNoTarget 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.

NameTypeRequiredDescription
agent_idstringNoFilter by agent
limitnumberNoMax 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.

NameTypeRequiredDescription
run_idstringYesThe 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.

NameTypeRequiredDescription
agent_idstringYesAgent to run
namestringNoCustom run name
goalstringNoGoal for the run
input_valuesobjectNoInput 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.

NameTypeRequiredDescription
run_idstringYesRun 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.

NameTypeRequiredDescription
run_idstringYesRun to delete
confirmbooleanNoMust 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.

NameTypeRequiredDescription
run_idstringYesRun 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.

NameTypeRequiredDescription
run_idstringYesRun 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.

NameTypeRequiredDescription
build_idstringYesBuild to list reviews for
statusstringNoproposed (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.

NameTypeRequiredDescription
build_idstringYesBuild to check
run_idstringNoRun 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.

NameTypeRequiredDescription
build_idstringYesThe review's build
review_idstringYesReview to accept
markdownstringNoCard 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.

NameTypeRequiredDescription
build_idstringYesThe review's build
review_idstringYesReview to dismiss
notestringNoWhy 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.

NameTypeRequiredDescription
run_idstringYesThe 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.

NameTypeRequiredDescription
card_idstringYesThe 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.

NameTypeRequiredDescription
agent_idstringNoFilter 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.

NameTypeRequiredDescription
agent_idstringYesAgent to schedule
namestringYesSchedule name
cronstringYesCron expression (e.g. "0 9 * * 1")
goalstringNoGoal for each run
input_valuesobjectNoInput 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.

NameTypeRequiredDescription
schedule_idstringYesSchedule ID
namestringNoNew name
cronstringNoNew cron expression
goalstringNoNew 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.

NameTypeRequiredDescription
schedule_idstringYesSchedule 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.

NameTypeRequiredDescription
schedule_idstringYesSchedule 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.

NameTypeRequiredDescription
schedule_idstringYesSchedule 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.

NameTypeRequiredDescription
agent_idstringYesAgent 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.

NameTypeRequiredDescription
specialist_idstringYesSpecialist 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" }
StatusMeaning
400Bad request, missing or invalid parameters
401Missing or invalid API key
403Insufficient permissions for this action
404Resource not found
500Internal server error