API Overview
The Blox REST API — base URL, request and response formats, error handling, and rate limits.
The Blox REST API lets you programmatically manage workspaces, sites, pages, forms, collections, and blog content — and configure outbound webhooks. Anything you build manually in the dashboard can be automated through the API.
This section covers everything a developer needs:
Authentication
Find your secret key and authenticate every request.
API Reference
All endpoints, grouped by resource, with examples.
Webhooks
Receive real-time event notifications on your server.
Event Types
The full catalog of webhook events and payloads.
The API and webhooks require a plan that includes the Webhooks & API feature (typically the higher tiers). If your workspace doesn't include it, the Webhooks & API area shows a locked overlay — its upgrade prompt is titled "API & Webhooks," the same feature under a slightly different name. See Feature Access.
Base URL
All endpoints are served under a single versioned base URL:
https://yourapp.com/api/v1/Every path in the API Reference is relative to this base.
Request Format
- Transport: HTTPS only. Plain HTTP requests are redirected to HTTPS before they ever reach the API — there's no way to call it over an unencrypted connection.
- Authentication: A Bearer token in the
Authorizationheader on every request. Your API key starts withtdc_. See Authentication. - Body: Send JSON with
Content-Type: application/jsonfor writing/mutation endpoints (e.g. configuring webhooks).
curl -X POST https://yourapp.com/api/v1/webhooks \
-H "Authorization: Bearer tdc_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "ws_abc123",
"name": "CRM Sync",
"url": "https://hooks.example.com/tdc",
"events": ["form.submission.created"]
}'Response Format
Successful responses return HTTP 2xx with a JSON envelope indicating ok: true. Most responses carry the resource under a data key; a few action endpoints that don't have a resource to hand back — like deleting a webhook, or queuing a delivery replay — return just ok and a message instead.
{
"ok": true,
"data": {
"id": "site_a1b2c3",
"name": "Marketing Site",
"subdomain": "marketing-site.sites.tdcapps.com"
}
}A paginated list response:
{
"ok": true,
"data": [ { "id": "page_1" }, { "id": "page_2" } ],
"meta": {
"page": 1,
"limit": 20,
"total": 42,
"hasMore": true
}
}Not every list is paginated. GET /workspaces, GET /sites, and GET /workspaces/:workspaceId/members return their full array directly under data with no meta object. Every other list endpoint (pages, forms, submissions, collections, items, blog posts/authors/categories, webhooks, deliveries) returns meta as shown above.
Error Handling
Errors return a non-2xx status and a flat JSON body containing ok: false, a machine-readable error code, and a human-readable message.
{
"ok": false,
"error": "UNAUTHORIZED",
"message": "Invalid or revoked API key."
}| Status | Code | Meaning |
|---|---|---|
400 | BAD_REQUEST | Malformed JSON, invalid query parameters, or missing required fields. |
401 | UNAUTHORIZED | Missing, malformed, or revoked API key. |
403 | FORBIDDEN | Reserved for role/plan restrictions. Not currently returned by any endpoint — anything visible to your key is also fully usable by it. |
404 | NOT_FOUND | The resource doesn't exist, or isn't visible to your key. |
429 | RATE_LIMITED | Too many requests — slow down (see below). |
There's no JSON shape for an unexpected server failure today. If something goes wrong unexpectedly on our side, you may get a plain-text 500 Internal Server Error instead of the { "ok": false, ... } envelope above — so don't assume every non-2xx response is JSON. Check the response before parsing it.
Rate Limits
Requests are limited to 1,000 per hour, tracked per API key and per source IP together — calling the same key from several different IPs gives each IP its own 1,000/hour bucket. The limiter is a sliding window held in memory on each server instance, so it isn't shared across instances and resets on deploy.
If you send too many requests, the API returns a 429 status with the error code RATE_LIMITED. When this happens, wait a moment and try again. For apps that make lots of requests, add a delay that gets longer after each failed attempt (for example, wait 1 second, then 2, then 4, then 8—this is called "exponential backoff").
