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.
/billing/subscriptionReturns the org's plan, billing status, and usage against plan limits.
curl -X GET "https://api.draftbase.co/billing/subscription" \ -H "Authorization: Bearer $ACCESS_TOKEN"
The request succeeded.
{
"planKey": "hobby",
"status": "active",
"currentPeriodEnd": "string",
"plan": {
"key": "hobby",
"name": "string",
"priceMonthly": 0,
"limits": {
"maxMembers": 0,
"maxEntries": 0,
"maxMediaFiles": 0,
"maxStorageBytes": 0,
"maxEnvironments": 0,
"monthlyAiTokens": 0
},
"features": [
"string"
]
},
"usage": {
"members": 0,
"entries": 0,
"mediaFiles": 0,
"storageBytes": 0,
"environments": 0,
"aiTokens": 0
}
}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 emailUNAUTHORIZED401UnauthorizedINVALID_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 error