Concepts · Outlets

Outlets

An outlet is the channel artifacts ship to — a factory outlet and a media outlet at once. Artifacts of any kind, published from app.esy.com (by you, or by a worker whose job says so), with unpublishing a single flip at the platform. Outlets are their own plane: hand-authored documents publish through Publications instead — same pattern, separate systems.

The outlet record

an outletjson
{
  "name": "clip.art/flowers",
  "slug": "clip-art-flowers",
  "siteUrl": "https://clip.art",
  "sectionPath": "/flowers",
  "description": "The flowers section of the clip.art catalog",
  "projectId": null,
  "acceptedKinds": ["clip-art", "coloring-page"],
  "revalidateUrl": "https://clip.art/api/ingest/esy",
  "lastDeliveryStatus": "ok"
}

An outlet is URL-defined: siteUrl + sectionPath. clip.art/free and clip.art/flowers are different outlets; another site is another outlet. Beyond the address, an outlet owns the artifact kinds it accepts (empty = any kind), an optional project scope (a project-bound outlet is invisible to other projects’ workers), the consumer’s revalidation webhook with an encrypted reveal-once secret, and delivery health.

One site, many sections — many sites, one account

The URL-defined model is how the system scales. A catalog site fans out into as many section outlets as its taxonomy needs, each with its own kind gate; other sites — including esy.com itself — are simply more outlets on the same account:

OutletsectionPathacceptedKindsWhat ships there
clip.art/free/freeclip-art, coloring-pagethe general catalog (the fallback channel)
clip.art/flowers/flowersclip-artcategory routing catches flowers-classified artifacts
clip.art/coloring-pages/coloring-pagescoloring-pagekind-gated: only coloring pages pass
clip.art/worksheets/worksheetsworksheetworksheets get their own channel when their URL taxonomy lands
esy.com/…/…anyesy.com surfaces consume artifact outlets too — see below

Nothing about this list lives in any consumer’s configuration: adding clip.art/school is one create in app.esy.com, discovered by the site on its next ping. The routing ladder (below) spreads a single worker’s shift across all of them — kind gates and section matches decide, not per-site plumbing.

esy.com consumes both planes

esy.com already renders hand-authored documents through Publications (/research, /learn — compose’s plane). As artifacts start publishing to esy.com/* surfaces, the same domain also consumes Outlets. The two planes coexist on one site and never merge: documents keep their editorial machinery, artifacts keep theirs, and each surface reads from the plane it belongs to.

Outlet vs Publication

Outlet (artifacts)Publication (documents)
The contentrun-produced artifacts of any kind (images, research, …)hand-authored articles (compose)
Filing + stateoutlet items: artifact ↔ outlet, published | unpublishedthe document’s publication + draft/published status
The gatefinished + classified (title + category) + kind accepted (empty acceptedKinds = any kind)title, slug, description, category, video
Who publishesyou — or a worker whose job says so (its report accounts for it)you, per item
Where it lives/v1/outlets/v1/publications

How your site follows

the outlet webhook (Bearer secret + HMAC signature)json
{ "outlet": "clip-art-catalog", "action": "publish",
  "artifactIds": ["artifact-9f1e2d3c", "artifact-8a7b6c5d"] }

{ "outlet": "clip-art-catalog", "action": "unpublish",
  "artifactIds": ["artifact-9f1e2d3c"] }

Publish and unpublish fire one signed webhook per act; delivery is best-effort with health recorded on the outlet, and your site’s periodic re-pull is the backstop. Thin sites render straight from the read API (the esy.com pattern); catalog sites with local search and related-item machinery mirror the outlet’s published items into their own rows (the clip.art pattern — an ingest).

The secret belongs to the endpoint, not the channel. Outlets pointing at the same revalidateUrl share one webhook secret — creating a sibling adopts it, rotating any of them rotates the endpoint (all together). Your site holds exactly one secret no matter how many outlets ship to it, and discovers which outlets those are from the platform roster (GET /v1/outlets, filtered by its own domain) rather than configuring channel lists.

Which consumption pattern?

Render-time reads are the default: fetch the outlet’s published items, cache, revalidate on webhook — zero infrastructure. Build an ingest only when your pages need local rows (full-text search, related items, sitemaps at catalog scale).

Workers publish to outlets — the framework

The job’s publishPolicy decides if a shift publishes ("classified" — what passed the classifier; "none" — nothing, the default). Where each artifact ships follows one law: goals decide what gets made; designations and sections decide where it ships.

  1. A designated team’s outlet takes everything — the fence. A team with an outlet is a publishing contract for the whole crew: nothing overrides it — not a member’s Solo outlet, not a matching sibling section. “This team publishes only to X” is provable by one query.
  2. Otherwise, sections sort. An artifact routes to the same-site outlet whose sectionPath matches its classification category (/flowers catches flowers) — permanent site taxonomy, opt-in by construction.
  3. The rest lands on the worker’s Solo outlet — its own channel, active while solo (dormant on a team, never erased). No home channel → the artifact stays unpublished, never a wrong page.

Every published item records why it landed where it did (routedVia: team:… | section:… | solo | manual | subscription), and every assignment change is on the record — designations are audit-grade.

Syndication — one artifact, many outlets

An outlet with syndicate on carries every published artifact of its accepted kinds, wherever it was published — the wire-service model: the crew files to its designated desk, subscribing channels pick the piece up off the wire. Carrying is the outlet’s own act, so team fences stay whole. An artifact’s presence in each outlet is its own record, so unpublish is per-outlet: hiding a piece on esy.com/clipart leaves clip.art untouched, and a syndicating outlet never re-carries what you’ve hidden.

Publishing happens in one act per outlet, stamped publishedBy: worker-…, and the report accounts per channel: “Published 76/80 — clip.art/flowers: 16, clip.art catalog: 60.” See Workers and Assigned work.