Skip to navigation

Ensure full product (config-as-code converge of the whole FPO)

Idempotently converge an entire Full Product Object (the nested product graph) in one shot. Fans out to the per-entity ensure services in dependency order (product → capability backing flows/agents → capability-as-tool composition → capability links → surfaces + surface items → records → schedules → secret bindings), returning a per-entity report. Identity is the product name + account scope. NON-atomic by design: a per-entity failure is reported in entities[].result = "failed" (and hasFailures) and a re-run self-heals; only a top-level product reject aborts. Converged capability agents and flows are published to live by default; set release to “none” to save changes as drafts. Set dryRun to plan without writing. Set prune to remove product-scoped capabilities/surfaces (and their items) absent from the FPO (account-scoped flows/agents/tools/records are never removed). A hash-only probe (name + contentHash, no fpo) with release “none” answers unchanged when the live graph reconstructs (as GET /products/pull-fpo does) to that hash, else definitionRequired (retry with the full fpo); a probe that publishes (the default release) always answers definitionRequired, because only a full converge can publish drafts that are not yet live. The probe, the dryRun remoteHash and expectedRemoteHash read the live graph, so API keys need PRODUCTS:READ for them. A dryRun reports the live graph’s remoteHash; pass it as expectedRemoteHash on the apply to refuse the write (409 remote_changed) if the product changed in between. The guard compares what GET /products/pull-fpo reconstructs, so edits to seed records, schedules or secrets (which pull-fpo omits) do not trip it. When pull-fpo has to omit part of the product (a capability, surface, schedule, eval suite or skill it cannot represent), a probe answers definitionRequired, a dryRun reports no remoteHash, and expectedRemoteHash is refused with 409. The guard is re-checked immediately before the first write but does not lock the graph, so an edit that lands while the apply is running can still be overwritten. API keys need PRODUCTS:CREATE to create the product and PRODUCTS:UPDATE to change an existing one (PRODUCTS:WRITE covers both). API keys converge each nested flow, agent, tool, surface, schedule, record, eval suite and skill only with that entity kind’s own write scope (FLOWS:WRITE, AGENTS:WRITE or AGENTS:CREATE/UPDATE, TOOLS:WRITE, PRODUCTS:SURFACES:WRITE, SCHEDULES:WRITE, RECORDS:WRITE, EVALS:WRITE, SKILLS:WRITE) on top of the product scope; otherwise that entity reports failed. Adding or changing a capability on an existing product needs PRODUCTS:CAPABILITIES:WRITE, and adding a route to an existing surface needs PRODUCTS:SURFACES:WRITE. Prune needs PRODUCTS:CAPABILITIES:WRITE to remove capabilities and PRODUCTS:SURFACES:WRITE to remove surfaces or their items, and a pruned surface’s client tokens are revoked. Binding a skill to an agent also needs agent update scope. Schedules also honor the plan’s active-schedule limit and minimum frequency.

Authentication

AuthorizationBearer
API key or Clerk session token

Request

This endpoint expects an object.
contentHashstringOptionalformat: "^[0-9a-f]{64}$"

Hash-only probe: the canonical FPO hash the caller holds. Answers unchanged when the live graph reconstructs (as pull-fpo does) to this hash, else definitionRequired. Only valid without fpo.

dryRunbooleanOptional

Plan without writing — returns a per-entity plan (CI drift gate).

expectedRemoteHashstringOptionalformat: "^[0-9a-f]{64}$"

TOCTOU guard binding a dry run to its apply: the write proceeds only while the live graph still hashes to this value (the dry run’s remoteHash); otherwise 409 remote_changed.

fpomap from strings to anyOptional

A complete Full Product Object (FPO): the nested product graph (product, capabilities, tools, surfaces, …). Validated server-side via the shared FPO validator. Omit it only for a hash-only probe (name + contentHash).

namestringOptional>=1 character

The product name a hash-only probe resolves. Only valid without fpo.

onConflictenumOptional

Per nested entity: “overwrite” converges over dashboard/API edits.

Allowed values:
prunebooleanOptional

Opt-in removal of product-scoped capabilities/surfaces (and their items) absent from the FPO, after the converge passes. NEVER touches account-scoped flows/agents/tools/records. Honors createPolicy:“skip”. With dryRun, reports would-be removals as pruned plan rows.

releaseenumOptional

Whether converged capability agents and flows go live. Defaults to “publish”: an agent or flow whose converged content is not yet live is versioned and published (the agent’s live alias moves to that version), matching product creation. “none” saves changes as drafts and leaves live where it was. Publishing needs update authority over that entity kind, and for an agent the live deploy scope (AGENTS:DEPLOY:LIVE; AGENTS:WRITE or AGENTS:UPDATE also accepted); an API key without it converges that kind as “none”.

Allowed values:

Response

Converge result: unchanged | converged | plan (dryRun), with a per-entity report; or definitionRequired (hash-only probe miss — retry with the full fpo).

object
OR
object

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
409
Conflict Error
422
Unprocessable Entity Error
500
Internal Server Error