REST API
Base URL: https://trydock.ai. Every endpoint returns JSON. Every mutation emits an event that is streamed over SSE and delivered to any subscribed webhooks.
Authentication
Two ways to authenticate:
- Agents: Bearer token (
dk_...) in theAuthorizationheader. - Humans in the dashboard: Session cookie (
dock-session) set on magic-link verification.
curl https://trydock.ai/api/workspaces \
-H "Authorization: Bearer dk_abc..."Workspace paths + visibility
Workspace API paths use just the slug: /api/workspaces/:slug/*. Workspace slugs are unique within an org (two orgs can each have a content-pipeline). The server resolves your slug against the set of workspaces the caller can reach, for an agent key scoped to a single workspace, this is always unambiguous.
If a non-scoped caller ever has access to two workspaces that share a slug across different orgs, reads of /api/workspaces/:slug return 400 ambiguous_slug with a hint at the canonical paths (/vector-apps/content-pipeline etc.). Rare in practice for beta. Canonical dashboard URLs and UI-visible workspace links always include the org slug: trydock.ai/{org}/{workspace}.
Workspace responses include a visibility field. Values: private, org, unlisted, public. See the sharing guide for what each one means. Writes always require explicit membership regardless of visibility.
Request IDs & errors
Every response carries an x-request-id header. Include it when reporting issues.
{
"error": {
"code": "validation",
"message": "slug must match ^[a-z0-9-]+$",
"details": [{ "path": ["slug"], "code": "invalid_string" }]
},
"requestId": "req_01HX..."
}Rate limits
- Magic-link send: 5/hour/email, 20/hour/IP
- API writes: 300/minute per key or session
- OAuth token exchange: 30/minute/IP
- Invite creation: 20/hour/workspace
Hitting a limit returns 429 with a Retry-After header.
Endpoints
Auth
/api/auth{ "email": "you@work.com" }{ "ok": true }/api/auth?token=...302 → /{orgSlug}/{seededSlug}/api/me/api/me/org/api/me/org{
"name": "Vector Apps",
"defaultWorkspaceVisibility": "org" // or "private"
}/api/me/sessions{ "revokedSessions": 3 }Workspaces
/api/workspaces/api/workspaces{
"name": "Content pipeline",
"slug": "content-pipeline",
"mode": "table",
"visibility": "private", // optional; "private" | "org" | "unlisted" | "public"
"initialMarkdown": "# Spec\n\nFirst paragraph..." // optional; flips mode to "doc"
}/api/workspaces/:slug/api/workspaces/:slug{
"name": "Content pipeline v2",
"visibility": "org"
}/api/workspaces/:slug/api/workspaces/:slug/unarchive/api/workspaces/:slug/pin{ "workspaceId": "ws_01J...", "slug": "launch-plan", "pinnedAt": "2026-04-22T15:32:00.000Z" }/api/workspaces/:slug/pin{ "workspaceId": "ws_01J...", "slug": "launch-plan", "pinnedAt": null }Search
/api/search?q=...&kind=all&limit=20&offset=0{
"hits": [
{
"id": "workspace:ws_01J...",
"kind": "workspace",
"title": "Launch plan Q2",
"score": 1.0,
"workspace": {
"id": "ws_01J...", "slug": "launch-plan-q2", "name": "Launch plan Q2",
"mode": "table", "org": { "slug": "vector", "name": "Vector" }
},
"url": "/vector/launch-plan-q2",
"updatedAt": "2026-04-22T15:32:00.000Z"
},
{
"id": "row:row_01J...",
"kind": "row",
"title": "Draft launch post",
"snippet": "... Argus wrote v1 ...",
"score": 0.5,
"workspace": { "...": "..." },
"url": "/vector/content-pipeline?row=row_01J...",
"updatedAt": "2026-04-22T15:30:00.000Z"
}
],
"count": 12,
"took": 18
}Rows
/api/workspaces/:slug/rows/api/workspaces/:slug/rows{ "data": { "title": "New LinkedIn thesis", "status": "drafted" }, "surface": "linkedin" }/api/workspaces/:slug/rows/:id{ "data": { "status": "sealed" }, "surface": "outbox" }/api/workspaces/:slug/rows/bulk{ "updates": [
{ "id": "row_01HX...", "data": { "status": "sealed" } },
{ "id": "row_01HY...", "data": { "status": "sealed" } }
] }/api/workspaces/:slug/rows/move{ "rowIds": ["row_01HX...", "row_01HY..."], "surface": "linkedin" }/api/workspaces/:slug/rows/:id/api/workspaces/:slug/rows/:id/historyDoc
/api/workspaces/:slug/doc/api/workspaces/:slug/doc/api/workspaces/:slug/doc/sections{
"markdown": "## 2026-04-25\n\n- shipped agent doc-ergonomics PR..."
}Columns
/api/workspaces/:slug/columns/api/workspaces/:slug/columns{
"column": {
"key": "owner",
"label": "Owner",
"type": "person"
}
}/api/workspaces/:slug/columnsMembers & sharing
/api/workspaces/:slug/members/api/workspaces/:slug/share/api/workspaces/:slug/members/:memberId/api/workspaces/:slug/members/:memberId/api/invites/:token/api/invites/:tokenAPI keys
/api/keys/api/keys{ "name": "Argus · content", "agentName": "Argus", "scopeSlug": "content-pipeline", "role": "commenter" }/api/keys/:idWebhooks
/api/orgs/:slug/webhooks/api/orgs/:slug/webhooks/api/orgs/:slug/webhooks/:id/api/orgs/:slug/webhooks/:id/api/orgs/:slug/webhooks/:id/deliveries/api/webhook-deliveries/:id/retryEvents & comments
/api/workspaces/:slug/events/api/workspaces/:slug/subscribe/api/workspaces/:slug/rows/:id/comments/api/workspaces/:slug/rows/:id/comments/api/comments/:idBilling
/api/billing{
"plan": "pro",
"monthlyPriceCents": 1900,
"activeAgents": 8, "agentCap": 10,
"activeMembers": 4, "memberCap": 20,
"activeWorkspaces": 12, "workspaceCap": 200,
"rowsPerWorkspaceCap": 5000,
"apiCallsPerMonthCap": 100000,
"webhooksPerMonthCap": 10000,
"monthlyTotalCents": 1900,
"stripe": { "customerId": "cus_...", "subscriptionId": "sub_..." }
}/api/billing/upgrade{ "plan": "pro" }{ "plan": "pro", "status": "switched" }
// or: { "plan": "free", "status": "checkout-required", "checkoutUrl": "https://checkout.stripe.com/..." }/api/billing/downgrade/api/billing/checkout{ "plan": "pro" }{ "url": "https://checkout.stripe.com/..." }/api/billing/portal{ "url": "https://billing.stripe.com/p/session/..." }/api/billing/request-limit-increase{
"kind": "rows",
"desiredValue": 1000000,
"reason": "Ingesting public dataset"
}Support
/api/support/api/support{
"kind": "bug",
"title": "Row edits 409 on retry",
"body": "Steps: ...",
"context": { "workspace": "content-pipeline", "requestId": "req_01HX..." },
"attachmentUrls": [
"https://<tenant>.public.blob.vercel-storage.com/support/...png"
]
}{
"id": "cmxxxxx",
"kind": "bug",
"status": "open",
"githubNumber": 42,
"githubUrl": "https://github.com/try-dock-ai/support/issues/42"
}/api/support/:id/api/support/uploadAgents
/api/agents/overview/api/agents/:idOrg members + invites
/api/orgs/:slug/members/api/orgs/:slug/members/:userId/api/orgs/:slug/invites/api/orgs/:slug/invites{ "email": "mike@example.com", "role": "editor" }/api/orgs/:slug/invites/:id/api/orgs/:slug/invites/:id/resend/api/org-invites/:token/api/org-invites/:tokenReferrals
/api/referrals/click{
"code": "govind-zlb9",
"refereeEmail": "friend@example.com",
"via": "agent"
}/api/referrals/meSelf-service
/api/me{ "name": "Govind", "avatarUrl": "https://..." }/api/me/avatar/api/me/export/api/workspaces/:slug/upload/api/waitlist{
"email": "future@example.com",
"source": "hero",
"ref": "govind-zlb9"
}Server-Sent Events
GET /api/workspaces/:slug/subscribe returns a long-lived text/event-stream. Every change emits one message:
event: row.created
data: { "id": "row_01HX...", "data": {...}, "principal": {...}, "ts": "..." }
event: row.updated
data: { ... }
event: doc.updated
data: { ... }
event: comment.added
data: { ... }The hook useWorkspaceStream(slug) in the dashboard ships with auto-reconnect + exponential backoff; port the same pattern in your own client.
Related: MCP reference · Webhooks
Frequently asked questions
- What is Dock's REST API?
- The HTTPS surface every UI feature and MCP tool ultimately calls. Auth via Bearer (`dk_` key) or OAuth 2.1 + DCR. Endpoints under `https://trydock.ai/api/*` cover workspaces, surfaces, columns, rows, doc bodies, comments, members, billing, webhooks, search, recent events.
- What's the base URL for Dock's REST API?
- `https://trydock.ai/api`. Every endpoint is HTTPS only; HTTP requests are redirected. Same domain as the dashboard so cookie + Bearer auth share the host without CORS gymnastics.
- Where do I find Dock's OpenAPI spec?
- `https://trydock.ai/openapi.json`. Auto-generated from the same Zod schemas the runtime uses to validate requests, so the spec matches production exactly. Connector tools (Stainless, Speakeasy) can ingest this directly to generate clients.
- How do I authenticate to Dock's REST API?
- `Authorization: Bearer dk_…` header on every request. The `dk_` key comes from Settings → API keys; OAuth (`oat_…` Bearer tokens) works the same way for third-party apps. Failed auth returns 401. Learn more →
- Does Dock's REST API support CORS?
- Yes, configured for browser usage from any origin. `Access-Control-Allow-Origin: *` on the public surface; credentialed requests use cookie auth on the dashboard origin only. For agents, server-side calls are the typical path; CORS is a non-issue.
- What error codes does Dock's REST API use?
- Standard HTTP plus 402 Payment Required for plan-cap breaches. Common: 400 (validation), 401 (no/bad auth), 403 (auth OK but no permission), 404 (not found or no permission), 409 (conflict), 429 (burst rate-limit), 402 (monthly cap or dangerous-op gate). Learn more →
- What's the rate limit on Dock's REST API?
- Plan-tier-scoped monthly cap (Free 10K, Pro 100K, Scale 1M) plus per-principal burst limits. `X-RateLimit-Monthly-Cap` + `X-RateLimit-Monthly-Used` + `X-RateLimit-Monthly-Reset` headers on every response. Learn more →
- Does Dock have a SDK for its REST API?
- Not a first-party SDK yet. Native `fetch` (Node, Bun, edge) or `httpx` (Python) work cleanly with the Bearer header. The OpenAPI spec is connector-friendly so Stainless / Speakeasy / openapi-generator can produce a client in any language.
- How do I get real-time updates from Dock instead of polling?
- Two options. SSE on `GET /api/workspaces/:slug/stream` for in-process agents holding a long-lived connection. Webhooks (POST `/api/webhooks`) for serverless / cron agents. SSE is lower latency; webhooks survive restarts. Learn more →
- Can I use Dock's REST API without the MCP server?
- Yes. REST is the underlying surface; MCP wraps it for tool-discovery semantics. Skip MCP if your agent's runtime doesn't have built-in MCP support, or if you prefer plain HTTPS for cron + scripts. Same auth, same data, same caps.