Reference · Outlets API

Outlets API

Outlets are app.esy.com’s channels for publishing artifacts of any kind — separate from the Publications API (compose’s documents). An outlet is URL-defined (siteUrl + sectionPath): clip.art/free and clip.art/flowers are different outlets. All routes use a bearer token (session or esy_sk_ key). Publishing is per-item and gated; every publish or unpublish act fires one signed webhook to the outlet’s consumer.

Managing outlets

GET/v1/outletsYour outlets, with delivery health. Consumers discover which outlets to mirror here — filter siteUrl by your own domain; channel lists never live in consumer config.
POST/v1/outletsCreate an outlet. If a webhook is configured, the secret is revealed once.
PATCH/v1/outlets/{outletId}Update destination binding, accepted kinds, and metadata.
POST/v1/outlets/{outletId}/secret/rotateRotate the webhook secret (revealed once).
POST/v1/outlets/{outletId}/verifySend a test ping to the consumer’s webhook.

Publishing artifacts

POST/v1/outlets/{outletId}/items/publishPublish a batch of artifacts (gated: finished + classified + kind accepted). One webhook per act.
POST/v1/outlets/{outletId}/items/unpublishUnpublish a batch — the consumer hides those pages within seconds.
GET/v1/outlets/{outletId}/itemsThe published-items feed a consumer reads (artifact data embedded).
GET/v1/outlets/items/by-artifact/{artifactId}Everywhere one artifact is filed — powers publish/unpublish controls.
publish, with the gate explaining itselfjson
POST /v1/outlets/{outletId}/items/publish
{ "artifactIds": ["artifact-9f1e2d3c", "artifact-8a7b6c5d", "artifact-unclassified"] }

// per-id results — the gate explains itself
{
  "results": [
    { "artifactId": "artifact-9f1e2d3c", "ok": true },
    { "artifactId": "artifact-8a7b6c5d", "ok": true },
    { "artifactId": "artifact-unclassified", "ok": false,
      "problem": "Artifact has no classification (title + category) — the consumer can't build a page." }
  ],
  "changed": 2
}
the consumer feedjson
GET /v1/outlets/{outletId}/items?status=published&limit=100&offset=0

{
  "items": [{
    "id": "outitem-1a2b3c4d",
    "outletId": "outlet-3f9a1c2b",
    "artifactId": "artifact-9f1e2d3c",
    "status": "published",
    "publishedBy": "worker-06997927",
    "publishedAt": "2026-07-06T10:14:02Z",
    "artifact": {
      "id": "artifact-9f1e2d3c",
      "templateId": "generate-clip-art-asset-v2",
      "title": "Apple on Books",
      "content": { "type": "image", "url": "…", "classification": { "…": "…" } }
    }
  }],
  "total": 82
}

The webhook

One POST per act to the outlet’s revalidateUrl, authenticated twice: Authorization: Bearer <secret> and an HMAC-SHA256 signature over the exact body bytes. The payload is { outlet, action, artifactIds } (action publish, unpublish, or test). Delivery is best-effort — health lands on the outlet record, and your periodic re-pull is the backstop.

Outlets are not Publications

Documents (compose’s editorial pieces) publish through the separate Publications API, whose webhook sends { publication, slug, action, categories }. Outlets carry artifacts only.