Automation API
Blobify can be managed over HTTP from scripts, CLIs, and services.
What automation can do
- read models and blocks
- validate schema bundles before applying them
- import models and blocks
- create and update drafts
- patch drafts with JSON Patch ops (atomic, with optional optimistic concurrency)
- bulk-import up to 100 items per request (for migrations)
- publish and unpublish content
API keys use the same access model as members:
admindevelopereditorviewer
Each key can be limited to specific spaces.
Workflow
- Create an API key in
Settings → Developer → API Keys - Read automation context for locales, spaces, models, and blocks
- List or search existing content by stable fields such as
slug - Generate JSON in your script or service
- Validate before writing
- Save drafts or upsert by a stable key
- Publish when ready
Read automation context
Use this first in import scripts. It returns the org settings that migration tools need without exposing storage credentials.
API_URL="https://api.blobify.io"
ORG_ID="org_..."
API_KEY="bk_live_..."
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/automation/context"Example response:
{
"org": {
"id": "org_...",
"name": "Example",
"defaultLocale": "en",
"locales": [{ "code": "en", "label": "English" }],
"rootPrefix": "blobify",
"publicBucketUrl": "https://cdn.example.com",
"spaceSettings": {
"main": { "contentPrefix": "content_abc123" }
}
},
"spaces": ["main"],
"models": [
{
"model": "article",
"name": "Article",
"version": 3,
"singleton": false,
"displayField": "title",
"summaryFields": ["title", "slug"],
"lookupFields": ["slug"],
"listIndexIds": ["latest"]
}
],
"blocks": []
}Read schema
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/schemas/models"curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/schemas/blocks"Validate a schema bundle
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/schemas/validate-import" \
-d '{
"models": [
{
"model": "article",
"name": "Article",
"displayField": "title",
"summaryFields": ["title", "slug"],
"fields": {
"title": { "type": "text", "required": true, "translatable": true },
"slug": { "type": "slug", "required": true, "sourceField": "title" },
"body": { "type": "richtext", "translatable": true }
}
}
],
"blocks": []
}'Import models and blocks
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/schemas/import" \
-d '{
"models": [
{
"model": "article",
"name": "Article",
"displayField": "title",
"summaryFields": ["title", "slug"],
"fields": {
"title": { "type": "text", "required": true, "translatable": true },
"slug": { "type": "slug", "required": true, "sourceField": "title" },
"body": { "type": "richtext", "translatable": true }
}
}
],
"blocks": []
}'List or search content
List content from summary shards. Responses include IDs, publishing metadata, and the model's configured summary fields, so import scripts can decide whether to create, update, skip, or publish without fetching every full document.
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article?state=draft&locale=en&page=1&perPage=100"Search by a summary or indexed field:
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article?state=draft&locale=en&field=slug&value=hello-world"Example response:
{
"items": [
{
"id": "cnt_...",
"model": "article",
"spaceId": "main",
"state": "draft",
"created": "2026-04-24T10:00:00.000Z",
"updated": "2026-04-24T10:05:00.000Z",
"updatedAt": "2026-04-24T10:05:00.000Z",
"publishedLocales": ["en"],
"fields": {
"title": { "en": "Hello world" },
"slug": "hello-world"
}
}
],
"page": 1,
"perPage": 100,
"total": 1,
"nextPage": null
}Validate content before saving
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article/validate" \
-d '{
"fields": {
"title": { "en": "Hello world" },
"slug": "hello-world",
"body": {
"en": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [{ "type": "text", "value": "Created locally" }]
}
]
}
}
}
}'Upsert by stable key
Use upsert for restartable imports. Blobify looks up an existing entry by the specified field and updates it; if none exists, it creates a new draft.
curl -X PUT \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article/upsert" \
-d '{
"key": {
"field": "slug",
"value": "hello-world",
"locale": "en",
"state": "draft"
},
"fields": {
"title": { "en": "Hello world, updated" },
"slug": "hello-world"
},
"publish": {
"locales": ["en"]
}
}'Response:
{
"action": "updated",
"content": {
"id": "cnt_...",
"model": "article",
"publishedLocales": ["en"],
"fields": {
"title": { "en": "Hello world, updated" },
"slug": "hello-world"
}
}
}Create a draft
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article" \
-d '{
"fields": {
"title": { "en": "Hello world" },
"slug": "hello-world",
"body": {
"en": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [{ "type": "text", "value": "Created locally" }]
}
]
}
}
}
}'Bulk import
Save up to 100 items in one request. Each item is processed independently —
a per-item validation failure does not abort the rest of the batch. The
response carries a results array preserving input order with a status
of created, updated, or failed plus the saved doc (or the error
message) for each item. Designed for migrations from another CMS and
large-scale agent writes; items with id upsert, items without create new.
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article/bulk" \
-d '{
"items": [
{ "fields": { "slug": "page-a", "title": { "en": "A" } } },
{ "id": "cnt_existing", "fields": { "slug": "page-b", "title": { "en": "B" } } },
{ "fields": { "slug": "page-c", "title": { "en": "C" } } }
]
}'Response:
{
"results": [
{ "index": 0, "id": "cnt_new1", "status": "created", "doc": { ... } },
{ "index": 1, "id": "cnt_existing", "status": "updated", "doc": { ... } },
{ "index": 2, "id": "cnt_new2", "status": "failed", "error": "..." }
]
}The HTTP response is always 200 when the batch as a whole is
well-formed. Inspect each item's status and decide whether to retry
the failures. The endpoint rejects the request with 400 only when the
batch itself is malformed (empty, more than 100 items).
Patch a draft (small, atomic edits)
For surgical edits — e.g. an agent appending a single block to a long
page — use JSON Patch (RFC 6902) instead of a full document update. The
endpoint accepts an op array against the draft's fields object and
runs the patched result through the same validation + save pipeline.
Optional If-Match: <etag> header enables optimistic concurrency: pass
the ETag you read the draft at, and the API rejects with 409 if
another writer has modified the draft since.
curl -X PATCH \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article/$CONTENT_ID" \
-d '[
{ "op": "add", "path": "/blocks/-", "value": { "type": "callout", "id": "blk_x", "title": "New section" } },
{ "op": "replace", "path": "/title/en", "value": "New title" }
]'Update a draft
CONTENT_ID="cnt_..."
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article/$CONTENT_ID" \
-d '{
"fields": {
"title": { "en": "Hello world, updated" },
"slug": "hello-world",
"body": {
"en": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [{ "type": "text", "value": "Updated locally" }]
}
]
}
}
}
}'Publish
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/main/article/$CONTENT_ID/publish" \
-d '{
"locales": ["en"]
}'Local tool pattern
- Fetch automation context.
- Fetch current schemas if you need full field definitions.
- List/search existing content using stable keys.
- Generate JSON on your machine.
- Validate before writing.
- Upsert drafts by stable key.
- Publish only when explicitly requested.