Automation API
Use Blobify's HTTP API from migration scripts, CLIs, CI jobs, and services. Create a bearer API key in Settings > Developer > API Keys and limit it to the smallest role and set of spaces the job needs.
The role hierarchy is viewer, editor, developer, and admin. Content writes require editor or higher. Schema writes and rebuilds require developer or admin.
API_URL="https://api.blobify.io"
ORG_ID="org_abc"
SPACE_ID="main"
API_KEY="YOUR_API_KEY"Every example below uses this header:
Authorization: Bearer YOUR_API_KEYRead automation context
Start an import by reading the organization context. It returns the visible spaces, locales, model summaries, block summaries, public bucket URL, and per-space contentPrefix settings without exposing bucket credentials.
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/automation/context"{
"org": {
"id": "org_abc",
"name": "Example",
"defaultLocale": "en",
"locales": [{ "code": "en", "label": "English" }],
"rootPrefix": "blobify",
"publicBucketUrl": "https://cdn.example.com",
"spaceSettings": {
"main": { "contentPrefix": "site_a1" }
}
},
"spaces": ["main"],
"models": [
{
"model": "article",
"name": "Article",
"version": 3,
"singleton": false,
"displayField": "title",
"summaryFields": ["title", "slug"],
"lookupFields": ["slug"],
"listIndexIds": ["latest"]
}
],
"blocks": []
}lookupFields in this response is a compact list derived from the model's current fieldIndexes configuration.
Read and validate schemas
Read full schema definitions when your script needs field shapes:
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 model and block bundle without writing it:
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", "unique": true },
"body": { "type": "richtext", "translatable": true }
}
}
],
"blocks": []
}'The response includes conflicts, normalized schemas, rebuild implications, and validation errors. Apply the same bundle with POST /v1/orgs/{orgId}/schemas/import. Add "override": true only when replacing conflicting schemas is intentional.
List or find content
The authenticated list endpoint reads summary shards. It is intended for the dashboard, migration tools, and automation, not as a website runtime API.
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article?state=draft&locale=en&page=1&perPage=100"Filter by an exact field and value by providing both query parameters:
curl -H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article?state=draft&locale=en&field=slug&value=hello-world"The default state is draft, the default page is 1, and the default perPage is 100. perPage is capped at 500. The response includes items, page, perPage, total, and a numeric nextPage or 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/$SPACE_ID/article/validate" \
-d '{
"fields": {
"title": { "en": "Hello world" },
"slug": "hello-world",
"body": {
"en": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [{ "type": "text", "value": "Created locally" }]
}
]
}
}
}
}'The response is { "valid": true, "errors": [] } when validation succeeds.
Create and update drafts
Create a draft and let Blobify generate its content ID:
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article" \
-d '{
"fields": {
"title": { "en": "Hello world" },
"slug": "hello-world"
}
}'Update a draft by posting fields to its ID. Fields omitted from the request remain unchanged. Each field you do send replaces that field's stored value, so send the complete locale map for a translatable field:
CONTENT_ID="cnt_123"
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article/$CONTENT_ID" \
-d '{
"fields": {
"title": { "en": "Hello world, updated" },
"slug": "hello-world"
}
}'Upsert by a stable field
Use upsert for restartable imports. Blobify resolves the key through a field index or summaries, then falls back to scanning source documents if derived output is still catching up.
curl -X PUT \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/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"] }
}'The response has action: "created" or action: "updated" plus the saved content document. If locale is omitted, the organization default locale is used.
Patch draft fields
PATCH accepts an RFC 6902 operation array against the draft's fields object. Paths therefore start at a field name, not at /fields.
curl -X PATCH \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article/$CONTENT_ID" \
-d '[
{ "op": "replace", "path": "/title/en", "value": "A corrected title" },
{ "op": "add", "path": "/excerpt", "value": { "en": "Short summary" } }
]'The patched fields pass through the normal validation and save pipeline. An optional If-Match: <etag> header enables optimistic concurrency. A stale ETag returns 409 Conflict instead of overwriting another writer.
Bulk-save drafts
The bulk endpoint accepts 1 to 100 items. Items with an id update that draft. Items without an id create a draft. Each item is processed independently.
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article/bulk" \
-d '{
"items": [
{ "fields": { "slug": "page-a", "title": { "en": "A" } } },
{ "id": "cnt_existing", "fields": { "slug": "page-b", "title": { "en": "B" } } }
]
}'A well-formed batch returns HTTP 200 even when an individual item fails. Inspect every result's status, which is created, updated, or failed. A malformed or empty batch, or a batch above 100 items, returns 400.
Publish and unpublish
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article/$CONTENT_ID/publish" \
-d '{ "locales": ["en"] }'Unpublish selected locales with the matching /unpublish endpoint. Omitting locales unpublishes all currently published locales.
Archive, restore, and permanently delete
The first delete of a live entry archives it:
curl -X DELETE \
-H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article/$CONTENT_ID"Restore an archived entry with POST .../$CONTENT_ID/restore. Permanently delete by issuing DELETE again while the entry is already in the archive. Keep this archive-first sequence in automation so accidental deletion remains recoverable.
Rebuild summaries and indexes
Rebuild routes are asynchronous. They return 202 Accepted after placing a model-level job on the queue worker.
curl -X POST \
-H "Authorization: Bearer $API_KEY" \
"$API_URL/v1/orgs/$ORG_ID/content/$SPACE_ID/article/rebuild-all?state=published"Replace rebuild-all with rebuild-summaries, rebuild-field-indexes, or rebuild-list-indexes for a narrower job. Omit state to rebuild both draft and published output. The equivalent routes under /schemas/models/{model}/ enqueue work for every space.
Recommended migration loop
- Read automation context and full schemas.
- List or filter existing content by a stable key.
- Validate schema and content payloads locally before writing.
- Upsert restartable items by a stable indexed field.
- Inspect every bulk result.
- Publish only the locales that should go live.
- Rebuild derived output after schema or index configuration changes, then wait for the asynchronous job to converge.