Every endpoint below maps directly to a resource in the Draftbase content model: templates define the schema, entries hold the content, and media handles uploads. Each route documents its request body, response shape, and status codes, generated straight from the live OpenAPI spec so it never drifts from the deployed API. Prefer calling these endpoints through a typed client instead of raw fetch calls? The SDK wraps every route here with full TypeScript types.
/agents/typesThe prebuilt agent catalog, with each type's lock status under the org's current plan. Every type can be instantiated more than once — these are templates, not singletons.
curl -X GET "https://api.draftbase.co/agents/types" \ -H "Authorization: Bearer $ACCESS_TOKEN"
The request succeeded.
[
{
"type": "string",
"label": "string",
"description": "string",
"integrationType": "string",
"tags": [
"string"
],
"locked": true,
"overlayFields": [
{
"key": null,
"type": null,
"optional": null,
"defaultValue": null,
"enumValues": null
}
]
}
]Any endpoint can also return 401 (missing or invalid credentials), 403 (suspended org, insufficient role, or blocked IP), and 429 (100 requests per minute per IP; delivery routes add a 300 per minute per-org cap).
Every error response carries a stable `code` alongside the human-readable `error` message. Switch on `code` — the message wording can change at any time, the code cannot.
MISSING_ORG_HEADER400Missing x-org-id headerVALIDATION_FAILED400Request validation failedINVALID_TOKEN400Invalid or expired tokenINVALID_2FA_CODE400Invalid codeTWO_FACTOR_NOT_ENABLED4002FA is not enabledTWO_FACTOR_SETUP_REQUIRED400Start setup before enabling 2FAINCORRECT_PASSWORD400Current password is incorrectPASSWORD_REQUIRED400Set a password before unlinking GoogleDUPLICATE_FIELD_KEYS400Duplicate field keysDUPLICATE_PROP_NAMES400Duplicate prop namesINVALID_NAME400Name must contain at least one letter or digitUNKNOWN_ENVIRONMENT400Unknown environmentMAIN_ENVIRONMENT_IMMUTABLE400The main environment cannot be modified this waySAME_ENVIRONMENT400Source and target environments must differPLAN_LIMIT_EXCEEDED400Plan limit exceededALREADY_PUBLISHED400Entry is already publishedPUBLISH_AT_IN_PAST400publishAt must be in the futureINVITE_NOT_PENDING400Invite is not pendingSTORAGE_KEY_MISMATCH400storageKey does not belong to this org/environmentSELF_DISABLE_FORBIDDEN400Cannot disable your own accountRETRY_NOT_ALLOWED400Only failed deliveries can be retriedIDP_EMAIL_MISSING400Identity provider did not return an emailIDP_EMAIL_UNVERIFIED400Identity provider did not verify this emailENTRY_PUBLISHED400Published entries must be unpublished before they can be deletedNO_ACTIVE_SUBSCRIPTION400Org has no active subscriptionWEBHOOK_SIGNATURE_INVALID400Invalid webhook signatureUNAUTHORIZED401UnauthorizedINVALID_CREDENTIALS401Invalid email or passwordMISSING_REFRESH_TOKEN401Missing refresh tokenINVALID_REFRESH_TOKEN401Invalid or expired refresh tokenINVALID_CHALLENGE401Invalid or expired challengeFORBIDDEN403ForbiddenORG_SUSPENDED403Org is suspendedIP_NOT_ALLOWED403Request IP is not on the org's allowlistNOT_ORG_MEMBER403Not a member of this orgINSUFFICIENT_ROLE403Insufficient roleENVIRONMENT_FORBIDDEN403Not allowed to access this environmentOWNER_IMMUTABLE403The org owner cannot be changed or removedPLAN_FEATURE_REQUIRED403This feature is not included in the org's planEMAIL_NOT_VERIFIED403Email address is not verifiedNOT_INVITED403This account is not invited to this orgNO_ORG403User does not belong to an orgNOT_FOUND404Not foundREVISION_NOT_FOUND404Revision not foundSNAPSHOT_NOT_FOUND404Snapshot not foundSSO_CONNECTION_NOT_FOUND404SSO connection not foundENVIRONMENT_NOT_FOUND404Environment not foundALREADY_EXISTS409Already existsEMAIL_IN_USE409Email already in useALREADY_MEMBER409Already a memberALREADY_INVITED409Already invitedENTRY_MODIFIED409Entry was modified by another requestSTILL_REFERENCED409Still referenced by other contentTEMPLATE_HAS_ENTRIES409Template still has entriesAI_UNAVAILABLE502AI service is unavailableRATE_LIMITED429Rate limit exceededINTERNAL_ERROR500Internal server errorWebhooks fire signed HTTP POSTs on entry lifecycle events. Two ways to register one — there is no MCP tool for this yet, so an AI agent without dashboard access should call the API directly with a management API key.
POST /webhooks with a management-scoped API key. The response carries the webhook id and its secret once — nothing after this call can retrieve the secret again, so capture it from the response.
curl -X POST https://api.draftbase.co/webhooks \
-H "Authorization: Bearer <management API key>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/hooks/draftbase",
"events": ["entry.published", "entry.unpublished"],
"envId": "production",
"includeContent": false
}'entry.createdA new entry was created.entry.updatedAn entry’s fields changed.entry.status_changedAn entry moved between draft/review/etc.entry.publishedAn entry went live.entry.unpublishedAn entry was taken down.entry.archivedAn entry was archived.entry.deletedAn entry was permanently deleted.entry.rolled_backAn entry was reverted to an earlier revision.entry.tags_updatedOnly an entry’s tags changed, fields untouched.Every delivery carries X-Draftbase-Signature-256: sha256=<hex>, an HMAC-SHA256 of ${timestamp}.${body} using the webhook’s secret, plus X-Draftbase-Timestamp, X-Draftbase-Event, and X-Draftbase-Event-Id. Recompute the HMAC over the raw request body and compare — reject anything that doesn’t match.