Skip to content

Docs

REST API v1 for pipelines you already run

Base URL https://app.unspar.com/api/v1. Bearer team API keys, one JSON envelope, public ids only, and idempotent writes. The contract is published as OpenAPI so your code, or your agent, can read it directly.

Authentication

Create a key under Team settings, API keys. Full-access keys can read, generate and publish; read-only and custom keys narrow that down, optionally to selected projects. Send the key as a bearer token on every request:

curl https://app.unspar.com/api/v1/whoami \
  -H "Authorization: Bearer $UNSPAR_API_KEY"

GET /whoami tells you which team, permissions and projects the key resolves to. Keys can be rotated and revoked from the same settings page, or through the API key endpoints listed below.

Responses and errors

Successful responses wrap the resource in a data envelope. List endpoints add meta.pagination.

{ "data": { "id": "prj_xxx", "name": "Bakery blog", "language": "en" } }

Errors use one shape everywhere, with a stable code you can branch on and a request_id you can quote when you contact us:

{ "error": { "code": "insufficient_credits", "message": "..." }, "request_id": "..." }

Status codes follow the usual meaning: 201 for a draft that was created without starting generation, 202 when work was accepted and is running, 402 when the team has too few credits for the run, 422 for validation errors, 429 when a rate limit applies. Every response carries an X-Request-Id header and rate-limit headers.

Public ids

The API only ever exposes public ids such as prj_xxx for projects, art_xxx for articles and out_xxx for outlets. Use them as path parameters and in request bodies. Internal database ids never appear, so nothing about your account can be guessed from an id.

Idempotent writes

Send an Idempotency-Key header on writes (POST and PATCH). If the same key arrives again with the same body, the stored response is replayed and the work is not done twice. The same key with a different body is rejected as a conflict. Keys are kept for 24 hours.

curl -X POST https://app.unspar.com/api/v1/articles \
  -H "Authorization: Bearer $UNSPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f2c1c1e-order-2026-09-18" \
  -d '{"project":"prj_xxx","brief":"How small bakeries pick a domain name"}'

The CLI and the MCP tools send a key automatically.

Quick start: from brief to published article

List the projects the key can reach and pick one:

curl https://app.unspar.com/api/v1/projects \
  -H "Authorization: Bearer $UNSPAR_API_KEY"

Create an article. Generation starts right away and spends credits; the response is 202 with the article resource. Optional fields include title, language, template and outlet. Set "queue": false to store a draft without starting it, then start it later with POST /articles/{article}/queue.

curl -X POST https://app.unspar.com/api/v1/articles \
  -H "Authorization: Bearer $UNSPAR_API_KEY" -H "Content-Type: application/json" \
  -d '{"project":"prj_xxx","brief":"How small bakeries pick a domain name"}'

Poll the status until it reports completed (or failed or cancelled). A 202 means accepted, not finished, so poll instead of creating a second article.

curl https://app.unspar.com/api/v1/articles/art_xxx/status \
  -H "Authorization: Bearer $UNSPAR_API_KEY"

Fetch the markdown through the artifacts endpoints: list the artifacts, then read the content of the final_markdown artifact.

curl https://app.unspar.com/api/v1/articles/art_xxx/artifacts \
  -H "Authorization: Bearer $UNSPAR_API_KEY"

curl https://app.unspar.com/api/v1/articles/art_xxx/artifacts/art_yyy/content \
  -H "Authorization: Bearer $UNSPAR_API_KEY"

When the draft is approved, schedule publication to a connected outlet:

curl -X POST https://app.unspar.com/api/v1/articles/art_xxx/publish \
  -H "Authorization: Bearer $UNSPAR_API_KEY" -H "Content-Type: application/json" \
  -d '{"outlet":"out_xxx"}'

Operations

Every operation, its method and path, and the capability a key needs for it. The live operation map adds the rollout state on that server.

OperationMethod and pathCapability
getWhoamiGET /whoamiany key
getAccountGET /accountany key
listProjects, getProjectGET /projects, GET /projects/{project}projects: read
createProject, updateProjectPOST /projects, PATCH /projects/{project}projects: create, update
listTemplates, getTemplateGET /templates, GET /templates/{template}templates: read
listVoices, getVoiceGET /voices, GET /voices/{voice}voices: read
listOutlets, getOutletGET /outlets, GET /outlets/{outlet}outlets: read
listArticles, getArticleGET /articles, GET /articles/{article}articles: read
getArticleStatusGET /articles/{article}/statusarticles: read
listArticleArtifacts, getArticleArtifactContentGET /articles/{article}/artifacts, GET /articles/{article}/artifacts/{artifact}/contentartifacts: read
createArticle, queueArticlePOST /articles, POST /articles/{article}/queuegeneration: write
cancelArticle, retryArticlePOST /articles/{article}/cancel, POST /articles/{article}/retrygeneration: cancel, retry
approveArticlePOST /articles/{article}/approvepublish: approve
publishArticlePOST /articles/{article}/publishpublish: schedule
getCreditBalance, listCreditTransactionsGET /credits/balance, GET /credits/transactionscredits: read
listApiKeys, getApiKeyGET /api-keys, GET /api-keys/{apiKey}api keys: read
createApiKey, updateApiKey, rotateApiKey, revokeApiKeyPOST /api-keys, PATCH /api-keys/{apiKey}, POST /api-keys/{apiKey}/rotate, POST /api-keys/{apiKey}/revokeapi keys: write
getOpenApiYaml, listOperationsGET /openapi.yaml, GET /operationspublic, no key
discoverCliAuth, createCliDeviceAuthorization, pollCliDeviceTokenGET /cli-auth/discovery, POST /cli-auth/device, POST /cli-auth/tokenpublic, used by the CLI login

Paths are relative to https://app.unspar.com/api/v1.

OpenAPI and discovery

  • OpenAPI document: the full request and response schemas. Generate a client from it or hand it to your agent.
  • Operation map (JSON): operations with method, path, capability, scope and rollout state.
  • llms.txt: a plain-text summary of the API, the CLI and MCP for language models.

The discovery endpoints need no key. If you prefer a client that already speaks this API, the unspar CLI wraps every operation above and adds --json output for scripts.