{
  "openapi": "3.1.0",
  "info": {
    "title": "composerID Intent API",
    "version": "1.0.0-draft",
    "summary": "Publish a decision into any destination system of record, under one Intent ID.",
    "description": "The composerID Intent API: mint an intent at the decision, plan its\ndestinations, preflight against a tenant's own requirements, publish idempotently,\nand reconcile drift, with every step on an append-only timeline under one Intent ID.\n\n**Status.** This is the documented contract, served today by the reference sandbox\n(`service/` in the composerID repository) over mock destination tenants. The\nproduction service behind `https://api.composer.id` is in build; nothing here is a\nclaim that it is live. The sandbox implements this document exactly, so a client\ngenerated from it works against the sandbox now and against production unchanged.\n\n**Authentication.** Bearer token on every request (`Authorization: Bearer\n<token>`). Production clients use OAuth 2.0 client credentials: exchange a\n`client_id` and `client_secret` at `POST /v1/oauth/token` for a token that\nexpires in an hour and carries only the scopes the client was granted\n(`intents:read`, `intents:write`, `publish`, `reconcile`, `passthrough`,\n`destinations:read`); a token without the scope a route needs gets 403\n`insufficient_scope`. Personal sandbox API keys (issued per person from the\ndeveloper access page) are also accepted as bearer tokens and carry every\nscope. All comparisons are constant-time. Destination credentials are never\nsupplied by the caller: they are held per tenant and injected by the adapter.\n\n**Idempotency.** Publishing is idempotent on\n`{intent_id}-{intent_version}-{target_system}`. A replayed publish returns the\nstored receipt with `replayed: true` and never creates a second record in the\ndestination system. Where a destination documents no idempotency header, the\nadapter dedupes by querying the destination's own client-supplied id before\ncreating.\n\n**What crosses the boundary.** A destination receives a valid request plus the\nIntent ID. Diagnostic answers, scores and the Compliance File never leave\ncomposerID.\n",
    "contact": {
      "name": "composerID developer access",
      "url": "https://composer.id/docs/access/index.html"
    }
  },
  "servers": [
    {
      "url": "https://api.composer.id/v1",
      "description": "Production. In build: see the status note above."
    },
    {
      "url": "http://127.0.0.1:8080/v1",
      "description": "Reference sandbox (service/server.py), mock destination tenants."
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "OAuth 2.0 client credentials. Exchange a client id and secret for a short-lived bearer token carrying only the scopes the client was granted."
    },
    {
      "name": "Intent",
      "description": "Mint, read, amend and audit an intent. The timeline is append-only."
    },
    {
      "name": "Routing",
      "description": "Apply the Channel Map, then validate against the destination tenant's own requirements before publishing."
    },
    {
      "name": "Publishing",
      "description": "Idempotent publish, drift reconciliation, and a raw escape hatch that stays anchored to the Intent ID."
    },
    {
      "name": "Discovery",
      "description": "What composerID can reach, and what each destination requires."
    }
  ],
  "security": [
    {
      "oauth2": [
        "destinations:read",
        "intents:read",
        "intents:write",
        "passthrough",
        "publish",
        "reconcile"
      ]
    },
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/oauth/token": {
      "post": {
        "operationId": "issueToken",
        "tags": [
          "Auth"
        ],
        "summary": "Exchange client credentials for a short-lived, scoped bearer token",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "security": [],
        "description": "RFC 6749 section 4.4. Send `grant_type=client_credentials` with the client id and secret as HTTP Basic credentials (or in the body), optionally narrowing `scope`. The response is not cacheable. Tokens expire after `expires_in` seconds; request a new one on 401.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "unsupported_grant_type, invalid_scope or invalid_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          },
          "401": {
            "description": "invalid_client: the client id or secret is wrong",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          }
        }
      }
    },
    "/intent": {
      "post": {
        "operationId": "createIntent",
        "tags": [
          "Intent"
        ],
        "summary": "Create an intent record (returns intent_id)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntentCreateRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "intents:write"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:write`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/intent/{intent_id}": {
      "patch": {
        "operationId": "patchIntent",
        "tags": [
          "Intent"
        ],
        "summary": "Patch diagnostics/routing/admin fields",
        "parameters": [
          {
            "name": "intent_id",
            "in": "path",
            "required": true,
            "description": "The Intent ID minted by POST /intent.",
            "schema": {
              "$ref": "#/components/schemas/IntentId"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntentPatchRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "intents:write"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:write`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getIntent",
        "tags": [
          "Intent"
        ],
        "summary": "Fetch the canonical intent record",
        "parameters": [
          {
            "name": "intent_id",
            "in": "path",
            "required": true,
            "description": "The Intent ID minted by POST /intent.",
            "schema": {
              "$ref": "#/components/schemas/IntentId"
            }
          }
        ],
        "security": [
          {
            "oauth2": [
              "intents:read"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:read`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/plan": {
      "post": {
        "operationId": "plan",
        "tags": [
          "Routing"
        ],
        "summary": "Generate destination plan from Channel Map + intent",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanGenerateRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "intents:write"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlanGenerateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:write`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/preflight": {
      "post": {
        "operationId": "preflight",
        "tags": [
          "Routing"
        ],
        "summary": "Validate intent against platform requirements",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreflightRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "intents:write"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreflightResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:write`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The destination tenant requires fields the intent does not carry yet. The body's enrichment_request is the question to ask back upstream.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichmentGap"
                }
              }
            }
          }
        }
      }
    },
    "/publish": {
      "post": {
        "operationId": "publish",
        "tags": [
          "Publishing"
        ],
        "summary": "Idempotent publish to target platform via adapter",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "publish"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublishReceipt"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `publish`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The destination tenant requires fields the intent does not carry yet. The body's enrichment_request is the question to ask back upstream.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichmentGap"
                }
              }
            }
          }
        }
      }
    },
    "/intent/{intent_id}/timeline": {
      "get": {
        "operationId": "getTimeline",
        "tags": [
          "Intent"
        ],
        "summary": "Fetch timeline events for audit",
        "parameters": [
          {
            "name": "intent_id",
            "in": "path",
            "required": true,
            "description": "The Intent ID minted by POST /intent.",
            "schema": {
              "$ref": "#/components/schemas/IntentId"
            }
          }
        ],
        "security": [
          {
            "oauth2": [
              "intents:read"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:read`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/platforms": {
      "get": {
        "operationId": "listPlatforms",
        "tags": [
          "Discovery"
        ],
        "summary": "List platforms and doc availability",
        "security": [
          {
            "oauth2": [
              "destinations:read"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PlatformDoc"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `destinations:read`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/destinations": {
      "get": {
        "operationId": "listDestinations",
        "tags": [
          "Discovery"
        ],
        "summary": "List connected destinations and capabilities",
        "security": [
          {
            "oauth2": [
              "destinations:read"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LinkedDestination"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `destinations:read`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/destinations/{id}/capabilities": {
      "get": {
        "operationId": "getCapabilities",
        "tags": [
          "Discovery"
        ],
        "summary": "Capability matrix + required fields per object/op",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Destination key, e.g. beeline or fieldglass.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "oauth2": [
              "destinations:read"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapabilitiesResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `destinations:read`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/passthrough": {
      "post": {
        "operationId": "passthrough",
        "tags": [
          "Publishing"
        ],
        "summary": "Send raw JSON to a platform endpoint",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PassthroughRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "passthrough"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PassthroughResponse"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `passthrough`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/reconcile": {
      "post": {
        "operationId": "reconcile",
        "tags": [
          "Publishing"
        ],
        "summary": "Detect drift between VMS state and canonical intent",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReconcileRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "reconcile"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DriftReport"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `reconcile`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/enrichment-request": {
      "post": {
        "operationId": "fulfilEnrichment",
        "tags": [
          "Intent"
        ],
        "summary": "Emit missing fields back to Triage/Intake",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrichmentFulfilRequest"
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "intents:write"
            ]
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntentRecord"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or missing required field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or expired bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: the token lacks `intents:write`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown intent or destination",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "vms.requisition.updated": {
      "post": {
        "operationId": "onVmsRequisitionUpdated",
        "tags": [
          "Publishing"
        ],
        "summary": "A requisition changed in the destination system",
        "description": "Delivered to the subscriber's endpoint and signed with HMAC-SHA256 over the raw body. Verification is multi-key so signing keys can rotate; an unverifiable delivery is rejected, not queued.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged"
          }
        }
      }
    },
    "vms.assignment.updated": {
      "post": {
        "operationId": "onVmsAssignmentUpdated",
        "tags": [
          "Publishing"
        ],
        "summary": "An assignment changed",
        "description": "Delivered to the subscriber's endpoint and signed with HMAC-SHA256 over the raw body. Verification is multi-key so signing keys can rotate; an unverifiable delivery is rejected, not queued.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged"
          }
        }
      }
    },
    "vms.timesheet.updated": {
      "post": {
        "operationId": "onVmsTimesheetUpdated",
        "tags": [
          "Publishing"
        ],
        "summary": "Timesheet changed",
        "description": "Delivered to the subscriber's endpoint and signed with HMAC-SHA256 over the raw body. Verification is multi-key so signing keys can rotate; an unverifiable delivery is rejected, not queued.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged"
          }
        }
      }
    },
    "vms.connection.revoked": {
      "post": {
        "operationId": "onVmsConnectionRevoked",
        "tags": [
          "Publishing"
        ],
        "summary": "Tenant auth revoked",
        "description": "Delivered to the subscriber's endpoint and signed with HMAC-SHA256 over the raw body. Verification is multi-key so signing keys can rotate; an unverifiable delivery is rejected, not queued.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "Client credentials, the production model: server-to-server, short-lived tokens, least-privilege scopes, rotation by issuing a new client secret.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://api.composer.id/v1/oauth/token",
            "scopes": {
              "intents:read": "Read intent records and their timelines.",
              "intents:write": "Create, patch, plan, preflight and enrich intents.",
              "publish": "Publish an intent into a destination system.",
              "reconcile": "Run reconciliation against a destination.",
              "passthrough": "Raw platform calls anchored to an Intent ID.",
              "destinations:read": "List platforms, destinations and capabilities."
            }
          }
        }
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A personal sandbox API key, issued per person from the developer access page and carrying every scope; or a token from the oauth2 flow. Compared in constant time. Destination credentials are never passed by the caller."
      }
    },
    "schemas": {
      "IntentRecord": {
        "title": "IntentRecord",
        "description": "Canonical system-of-engagement record keyed by intent_id.",
        "type": "object",
        "required": [
          "intent_id",
          "intent_version",
          "state",
          "created_at"
        ],
        "properties": {
          "intent_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{10,64}$",
            "description": "Identifier-safe ID minted by composerID. URI-safe, no special characters."
          },
          "intent_version": {
            "type": "integer",
            "minimum": 1,
            "description": "Monotonically increasing version; a bump mints a new idempotency key."
          },
          "state": {
            "type": "string",
            "enum": [
              "draft",
              "diagnosed",
              "decided",
              "planned",
              "published",
              "failed",
              "cancelled"
            ],
            "description": "Lifecycle state. Transitions enforce minimum-viable guards."
          },
          "payload": {
            "type": "object",
            "description": "Opaque intent payload \u2014 diagnostic answers, routing, admin fields. Structure depends on the Triage questionnaire; composerID does not interpret it.",
            "properties": {
              "diagnostics": {
                "$ref": "#/components/schemas/DiagnosticsBundle"
              },
              "routing": {
                "$ref": "#/components/schemas/RoutingPayload"
              },
              "admin": {
                "$ref": "#/components/schemas/AdminPayload"
              }
            },
            "additionalProperties": true
          },
          "publishing": {
            "$ref": "#/components/schemas/PublishingBundle",
            "description": "Populated after the first successful publish."
          },
          "defence_file_ref": {
            "type": "string",
            "format": "uri",
            "description": "URI to the DefenceFile (JSON-LD) evidence artifact."
          },
          "override_event": {
            "type": [
              "object",
              "null"
            ],
            "description": "Present when a human override bypassed standard diagnostic scoring.",
            "properties": {
              "reason": {
                "type": "string"
              },
              "actor": {
                "type": "string"
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of intent creation."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "$defs": {
          "state_transitions": {
            "description": "Minimum-viable transition guards (illustrative, enforced by the service). draft\u2192diagnosed: diagnostics present and scored OR override_event. diagnosed\u2192decided: routing decision recorded. decided\u2192planned: routing + admin present + destination selected. planned\u2192published: publish receipt + external IDs + intent_version. Any state\u2192failed: adapter error or preflight rejection. Any state\u2192cancelled: explicit cancellation.",
            "type": "null"
          }
        },
        "x-canonical-url": "https://composer.id/schemas/intent-record.json"
      },
      "TimelineEvent": {
        "title": "TimelineEvent",
        "description": "Immutable append-only event for the intent audit trail. Events are never mutated or deleted.",
        "type": "object",
        "required": [
          "intent_id",
          "type",
          "at"
        ],
        "properties": {
          "intent_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{10,64}$"
          },
          "type": {
            "type": "string",
            "enum": [
              "intent.created",
              "intent.updated",
              "intent.version_bumped",
              "intent.stamped",
              "intent.linked",
              "intent.published",
              "intent.failed",
              "intent.cancelled",
              "enrichment.requested",
              "enrichment.fulfilled",
              "reconciliation.detected",
              "reconciliation.resolved",
              "webhook.received"
            ],
            "description": "Event type. The spine emits intent.created, intent.stamped, intent.linked, and intent.version_bumped today; additional types are reserved for phase two."
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp."
          },
          "version": {
            "type": "integer",
            "minimum": 1,
            "description": "Intent version at the time of the event."
          },
          "provider": {
            "type": "string",
            "description": "Provider key, present on stamp/link/publish events."
          },
          "external_id": {
            "type": "string",
            "description": "Destination object ID, present on stamp/link events."
          },
          "actor": {
            "type": "string",
            "description": "Who or what triggered the event (user ID, 'system', 'webhook')."
          },
          "detail": {
            "type": "object",
            "description": "Event-type-specific metadata.",
            "additionalProperties": true
          }
        },
        "additionalProperties": false,
        "x-canonical-url": "https://composer.id/schemas/timeline-event.json"
      },
      "LinkedDestination": {
        "title": "LinkedDestination",
        "description": "Capability and requirements metadata for a connected tenant destination.",
        "type": "object",
        "required": [
          "id",
          "provider",
          "object_types",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "composerID-assigned destination identifier."
          },
          "provider": {
            "type": "string",
            "description": "Provider key from the carrier table."
          },
          "tenant_id": {
            "type": "string",
            "description": "Customer's tenant identifier in the destination system."
          },
          "tenant_host": {
            "type": "string",
            "format": "uri",
            "description": "Tenant-specific base URL (e.g. 'https://acme.fgvms.com')."
          },
          "object_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LinkedDestination/$defs/object_capability"
            },
            "minItems": 1
          },
          "carrier_field": {
            "type": "string",
            "description": "Confirmed carrier field path for the Intent ID (indicative until onboarding)."
          },
          "deep_link_template": {
            "type": "string",
            "description": "URL template for one-click deep links. Placeholders: {tenant_host}, {object_type}, {external_id}."
          },
          "access_tier": {
            "type": "string",
            "enum": [
              "open",
              "tenant",
              "partner"
            ],
            "description": "Credential gating tier."
          },
          "mode": {
            "type": "string",
            "enum": [
              "stamp",
              "link"
            ],
            "description": "'stamp' writes the Intent ID into the destination; 'link' records the linkage on the composerID side only."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "pending",
              "revoked"
            ],
            "description": "Connection status."
          },
          "connected_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "$defs": {
          "object_capability": {
            "type": "object",
            "required": [
              "object_type",
              "operations"
            ],
            "properties": {
              "object_type": {
                "type": "string",
                "description": "Destination object type (e.g. 'job_posting', 'envelope')."
              },
              "operations": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "create",
                    "read",
                    "update"
                  ]
                },
                "description": "Supported operations for this object type."
              },
              "required_fields": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Fields the destination requires for create/update."
              },
              "mapping_profile": {
                "type": "string",
                "description": "Name of the MappingProfile for this object type."
              }
            },
            "additionalProperties": false
          }
        },
        "x-canonical-url": "https://composer.id/schemas/linked-destination.json"
      },
      "PassthroughRequest": {
        "title": "PassthroughRequest",
        "description": "Raw platform API call anchored to an intent_id. Escape hatch for fields or endpoints not covered by MappingProfiles \u2014 the call is logged on the intent timeline for auditability.",
        "type": "object",
        "required": [
          "intent_id",
          "provider",
          "method",
          "path"
        ],
        "properties": {
          "intent_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{10,64}$",
            "description": "The intent this passthrough is anchored to."
          },
          "provider": {
            "type": "string",
            "description": "Target provider key."
          },
          "method": {
            "type": "string",
            "enum": [
              "GET",
              "POST",
              "PUT",
              "PATCH",
              "DELETE"
            ],
            "description": "HTTP method for the destination call."
          },
          "path": {
            "type": "string",
            "description": "Relative path on the destination API (e.g. '/api/1/job_postings/FG-JP-41521')."
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Additional headers. Auth headers are injected by the adapter \u2014 do not include credentials."
          },
          "body": {
            "type": "object",
            "description": "Request body (for POST/PUT/PATCH).",
            "additionalProperties": true
          },
          "idempotency_key": {
            "type": "string",
            "description": "Optional idempotency key. If omitted, the call is not idempotent."
          }
        },
        "additionalProperties": false,
        "x-canonical-url": "https://composer.id/schemas/passthrough-request.json"
      },
      "EnrichmentRequest": {
        "title": "EnrichmentRequest",
        "description": "Emitted back to Triage when preflight finds missing platform-required fields. The publish is withheld until all gaps are filled \u2014 the intent is never half-published.",
        "type": "object",
        "required": [
          "type",
          "intent_id",
          "intent_version",
          "target_system",
          "profile",
          "missing_fields"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "enrichment_request"
          },
          "intent_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{10,64}$"
          },
          "intent_version": {
            "type": "integer",
            "minimum": 1
          },
          "target_system": {
            "type": "string",
            "description": "Provider key."
          },
          "profile": {
            "type": "string",
            "description": "MappingProfile name that flagged the gaps."
          },
          "missing_fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnrichmentRequest/$defs/missing_field"
            },
            "minItems": 1,
            "description": "Canonical source paths that are required but absent or empty."
          }
        },
        "additionalProperties": false,
        "$defs": {
          "missing_field": {
            "oneOf": [
              {
                "type": "string",
                "description": "Canonical dot-path of the missing field (e.g. 'location.country')."
              },
              {
                "type": "object",
                "required": [
                  "source_path"
                ],
                "properties": {
                  "source_path": {
                    "type": "string",
                    "description": "Canonical dot-path."
                  },
                  "target_field": {
                    "type": "string",
                    "description": "Destination-dialect field name for context."
                  },
                  "hint": {
                    "type": "string",
                    "description": "Human-readable hint about what's needed."
                  }
                },
                "additionalProperties": false
              }
            ]
          }
        },
        "x-canonical-url": "https://composer.id/schemas/enrichment-request.json"
      },
      "WebhookEvent": {
        "title": "WebhookEvent",
        "description": "Back-sync event envelope delivered by composerID webhooks. HMAC-SHA256 signed; multi-key rotation supported.",
        "type": "object",
        "required": [
          "event",
          "intent_id",
          "timestamp",
          "payload"
        ],
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "vms.requisition.updated",
              "vms.assignment.updated",
              "vms.timesheet.updated",
              "vms.connection.revoked"
            ],
            "description": "Event type. Current taxonomy is VMS-scoped; additional event families (assessment, document, workflow) are planned."
          },
          "intent_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{10,64}$",
            "description": "The intent this event relates to."
          },
          "intent_version": {
            "type": "integer",
            "minimum": 1
          },
          "provider": {
            "type": "string",
            "description": "Source provider key."
          },
          "external_id": {
            "type": "string",
            "description": "Object ID in the source system."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "payload": {
            "type": "object",
            "description": "Event-specific payload. Structure depends on the event type.",
            "additionalProperties": true
          },
          "signature": {
            "type": "string",
            "description": "HMAC-SHA256 signature for verification. Header: X-ComposerID-Signature."
          },
          "delivery_id": {
            "type": "string",
            "description": "Unique delivery ID for deduplication."
          }
        },
        "additionalProperties": false,
        "x-canonical-url": "https://composer.id/schemas/webhook-event.json"
      },
      "DiagnosticsBundle": {
        "title": "DiagnosticsBundle",
        "description": "Scored diagnostic evidence produced by Triage. Contains the assessment answers, scores, and ranked outcomes that drive the routing decision. This is path-2 (MSP reporting) data \u2014 only the resulting intent_id is published to destination systems.",
        "type": "object",
        "required": [
          "assessment_id",
          "scored",
          "scores"
        ],
        "properties": {
          "assessment_id": {
            "type": "string",
            "description": "WorkAuthor assessment identifier."
          },
          "scored": {
            "type": "boolean",
            "description": "True when scoring is complete and the bundle is decision-ready."
          },
          "scores": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "dimension",
                "value"
              ],
              "properties": {
                "dimension": {
                  "type": "string",
                  "description": "Scoring dimension (e.g. 'urgency', 'complexity', 'compliance_risk')."
                },
                "value": {
                  "type": "number",
                  "description": "Normalised score."
                },
                "weight": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              }
            },
            "description": "Scored dimensions from the Triage assessment."
          },
          "answers": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "question_id",
                "value"
              ],
              "properties": {
                "question_id": {
                  "type": "string"
                },
                "value": {},
                "label": {
                  "type": "string"
                }
              }
            },
            "description": "Raw assessment answers."
          },
          "ranked_outcomes": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "outcome",
                "score"
              ],
              "properties": {
                "outcome": {
                  "type": "string",
                  "enum": [
                    "contingent",
                    "permanent",
                    "sow",
                    "ic",
                    "outsource"
                  ],
                  "description": "Workforce channel."
                },
                "score": {
                  "type": "number"
                },
                "proportion": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1,
                  "description": "Perm-vs-contingent proportion when applicable."
                }
              }
            },
            "description": "Ranked channel recommendations."
          },
          "override_event": {
            "type": [
              "object",
              "null"
            ],
            "description": "Non-null when a human overrode the scored recommendation.",
            "properties": {
              "reason": {
                "type": "string"
              },
              "actor": {
                "type": "string"
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "completed_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "x-canonical-url": "https://composer.id/schemas/diagnostics-bundle.json"
      },
      "RoutingPayload": {
        "title": "RoutingPayload",
        "description": "Channel + destination payload in canonical field names (the Common Workforce Model). These are the platform-neutral fields that MappingProfiles translate into destination-specific API dialects.",
        "type": "object",
        "required": [
          "role_title",
          "worker_type"
        ],
        "properties": {
          "role_title": {
            "type": "string",
            "description": "Canonical role/position title."
          },
          "worker_type": {
            "type": "string",
            "enum": [
              "contingent",
              "permanent",
              "sow",
              "ic"
            ],
            "description": "Workforce channel determined by Triage."
          },
          "location": {
            "type": "object",
            "properties": {
              "country": {
                "type": "string",
                "pattern": "^[A-Z]{2}$",
                "description": "ISO 3166-1 alpha-2."
              },
              "state": {
                "type": "string"
              },
              "city": {
                "type": "string"
              },
              "postal_code": {
                "type": "string"
              },
              "remote": {
                "type": "boolean"
              }
            }
          },
          "start_date": {
            "type": "string",
            "format": "date",
            "description": "Requested start date (ISO 8601 date)."
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "description": {
            "type": "string",
            "description": "Role/engagement description."
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "headcount": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "destination": {
            "type": "object",
            "description": "Target system selected by the Channel Map.",
            "required": [
              "provider"
            ],
            "properties": {
              "provider": {
                "type": "string",
                "description": "Provider key from the carrier table (e.g. 'fieldglass', 'greenhouse')."
              },
              "object_type": {
                "type": "string",
                "description": "Destination object type (e.g. 'job_posting', 'envelope')."
              },
              "tenant_id": {
                "type": "string",
                "description": "Tenant identifier for multi-tenant destinations."
              }
            }
          }
        },
        "additionalProperties": true,
        "x-canonical-url": "https://composer.id/schemas/routing-payload.json"
      },
      "AdminPayload": {
        "title": "AdminPayload",
        "description": "Dates, budgets, cost centers, approvals, and administrative fields. Populated by the intake process; consumed by MappingProfiles during publish.",
        "type": "object",
        "properties": {
          "cost_center": {
            "type": "string",
            "description": "Cost center code for charge-back."
          },
          "budget": {
            "type": "object",
            "properties": {
              "max_bill_rate": {
                "type": "number",
                "description": "Maximum bill rate in the budget currency."
              },
              "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$",
                "description": "ISO 4217 currency code."
              },
              "total_budget": {
                "type": "number"
              }
            }
          },
          "approvals": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "approver",
                "status"
              ],
              "properties": {
                "approver": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "pending",
                    "approved",
                    "rejected"
                  ]
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "department": {
            "type": "string"
          },
          "business_unit": {
            "type": "string"
          },
          "project_code": {
            "type": "string"
          },
          "requester": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "format": "email"
              }
            }
          },
          "hiring_manager": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "format": "email"
              }
            }
          }
        },
        "additionalProperties": true,
        "x-canonical-url": "https://composer.id/schemas/admin-payload.json"
      },
      "PublishingBundle": {
        "title": "PublishingBundle",
        "description": "Publish receipts, external IDs, idempotency keys, and adapter status. Populated on the IntentRecord after the first successful publish.",
        "type": "object",
        "required": [
          "receipts"
        ],
        "properties": {
          "receipts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublishingBundle/$defs/publish_receipt"
            },
            "description": "One entry per publish attempt (successful replays included)."
          },
          "current_external_id": {
            "type": "string",
            "description": "The external ID in the destination system for the latest successful publish."
          },
          "current_idempotency_key": {
            "type": "string",
            "description": "The idempotency key for the latest publish, format: {intent_id}-{intent_version}-{provider}."
          },
          "adapter_status": {
            "type": "string",
            "enum": [
              "pending",
              "published",
              "failed",
              "replayed"
            ],
            "description": "Aggregate adapter status."
          }
        },
        "additionalProperties": false,
        "$defs": {
          "publish_receipt": {
            "type": "object",
            "required": [
              "target_system",
              "object_type",
              "external_id",
              "idempotency_key",
              "status",
              "at"
            ],
            "properties": {
              "target_system": {
                "type": "string",
                "description": "Provider key (e.g. 'fieldglass', 'docusign')."
              },
              "object_type": {
                "type": "string",
                "description": "Destination object type (e.g. 'job_posting', 'envelope')."
              },
              "external_id": {
                "type": "string",
                "description": "The ID assigned by the destination system."
              },
              "idempotency_key": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]+-[0-9]+-[a-z0-9]+",
                "description": "Deterministic key: {intent_id}-{intent_version}-{provider}."
              },
              "status": {
                "type": "string",
                "enum": [
                  "published",
                  "failed"
                ]
              },
              "replayed": {
                "type": "boolean",
                "description": "True if this was an idempotent replay of a prior publish."
              },
              "deep_link": {
                "type": "string",
                "format": "uri",
                "description": "One-click URL to the record in the destination system."
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "additionalProperties": false
          }
        },
        "x-canonical-url": "https://composer.id/schemas/publishing-bundle.json"
      },
      "TokenRequest": {
        "type": "object",
        "required": [
          "grant_type"
        ],
        "description": "OAuth 2.0 client-credentials grant. Client id and secret go in an HTTP Basic Authorization header (preferred) or in these fields.",
        "properties": {
          "grant_type": {
            "type": "string",
            "enum": [
              "client_credentials"
            ]
          },
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "type": "string",
            "format": "password"
          },
          "scope": {
            "type": "string",
            "description": "Space-separated subset of the client's granted scopes. Omit for all of them."
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "scope"
        ],
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Opaque; send as `Authorization: Bearer <access_token>`."
          },
          "token_type": {
            "type": "string",
            "const": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds until expiry (3600). Request a new token on 401."
          },
          "scope": {
            "type": "string",
            "description": "Space-separated scopes the token carries."
          }
        }
      },
      "OAuthError": {
        "type": "object",
        "required": [
          "error"
        ],
        "description": "RFC 6749 section 5.2 error body.",
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "invalid_request",
              "invalid_client",
              "unsupported_grant_type",
              "invalid_scope"
            ]
          },
          "error_description": {
            "type": "string"
          }
        }
      },
      "IntentCreateRequest": {
        "type": "object",
        "additionalProperties": false,
        "description": "The decision's canonical payload. Fields are the Common Workforce Model names a MappingProfile reads.",
        "properties": {
          "payload": {
            "type": "object",
            "description": "Canonical intent fields, e.g. channel, role_title, start_date, location, quantity.",
            "additionalProperties": true
          }
        }
      },
      "IntentPatchRequest": {
        "type": "object",
        "additionalProperties": false,
        "description": "Merge payload fields, or set a patchable top-level field. A patch bumps intent_version: a changed intent is a new publishable version by design.",
        "properties": {
          "payload": {
            "type": "object",
            "additionalProperties": true
          },
          "defence_file_ref": {
            "type": "string",
            "format": "uri",
            "description": "Reference to the Compliance File (the field keeps its original name until a versioned schema rename)."
          }
        }
      },
      "TimelineResponse": {
        "type": "object",
        "required": [
          "intent_id",
          "events"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimelineEvent"
            },
            "description": "Append-only. Corrections are new events, never edits."
          }
        }
      },
      "PlanGenerateRequest": {
        "type": "object",
        "required": [
          "intent_id"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "channel": {
            "type": "string",
            "description": "Work channel to route. Defaults to payload.channel on the intent.",
            "examples": [
              "contingent_hire",
              "services_sow",
              "permanent_hire",
              "signature",
              "contract",
              "purchase"
            ]
          },
          "platform": {
            "type": "string",
            "description": "Explicit destination override, bypassing the Channel Map."
          }
        }
      },
      "PlanGenerateResponse": {
        "type": "object",
        "required": [
          "intent_id",
          "intent_version",
          "channel",
          "destinations",
          "rationale"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "intent_version": {
            "type": "integer",
            "minimum": 1
          },
          "channel": {
            "type": "string"
          },
          "destinations": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "platform",
                "object_type",
                "carrier_field",
                "mode"
              ],
              "properties": {
                "platform": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                },
                "object_type": {
                  "type": "string"
                },
                "carrier_field": {
                  "type": "string",
                  "description": "Where the Intent ID is written in the destination record."
                },
                "mode": {
                  "enum": [
                    "stamp",
                    "link"
                  ]
                },
                "events_posture": {
                  "enum": [
                    "push",
                    "poll",
                    "mixed"
                  ]
                }
              }
            }
          },
          "rationale": {
            "type": "string",
            "description": "Why this destination was chosen. Deterministic and explainable."
          }
        }
      },
      "PreflightRequest": {
        "type": "object",
        "required": [
          "intent_id",
          "platform"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "platform": {
            "type": "string"
          }
        }
      },
      "PreflightResponse": {
        "type": "object",
        "required": [
          "intent_id",
          "platform",
          "profile",
          "ok",
          "missing_fields"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "platform": {
            "type": "string"
          },
          "profile": {
            "type": "string",
            "description": "The MappingProfile validated against."
          },
          "ok": {
            "type": "boolean"
          },
          "missing_fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "PublishRequest": {
        "type": "object",
        "required": [
          "intent_id",
          "platform"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "platform": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "description": "Supply when the destination record already exists: composerID stamps the Intent ID onto it instead of creating a duplicate. Required for link-mode destinations."
          }
        }
      },
      "PublishReceipt": {
        "type": "object",
        "required": [
          "intent_id",
          "target_system",
          "object_type",
          "external_id",
          "idempotency_key",
          "status",
          "replayed",
          "at"
        ],
        "additionalProperties": true,
        "description": "One receipt per publish attempt, as carried in PublishingBundle.receipts.",
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "intent_version": {
            "type": "integer",
            "minimum": 1
          },
          "target_system": {
            "type": "string"
          },
          "object_type": {
            "type": "string"
          },
          "profile": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "description": "The destination's own record identifier."
          },
          "idempotency_key": {
            "type": "string",
            "description": "{intent_id}-{intent_version}-{target_system}[-{object_type}]."
          },
          "deep_link": {
            "type": "string",
            "format": "uri",
            "description": "One click from the receipt to the record in the destination system."
          },
          "status": {
            "type": "string",
            "examples": [
              "published"
            ]
          },
          "replayed": {
            "type": "boolean",
            "description": "true when a prior identical publish was returned instead of creating a second record."
          },
          "at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ReconcileRequest": {
        "type": "object",
        "required": [
          "intent_id",
          "platform"
        ],
        "additionalProperties": false,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "platform": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "description": "Needed only for records composerID linked rather than created."
          }
        }
      },
      "DriftReport": {
        "type": "object",
        "required": [
          "intent_id",
          "platform",
          "external_id",
          "drift"
        ],
        "additionalProperties": false,
        "description": "Compares the destination record against the payload that was actually published, not against today's intent.",
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "platform": {
            "type": "string"
          },
          "external_id": {
            "type": "string"
          },
          "drift": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "published",
                "current"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "published": {},
                "current": {}
              }
            }
          }
        }
      },
      "EnrichmentFulfilRequest": {
        "type": "object",
        "required": [
          "intent_id"
        ],
        "additionalProperties": false,
        "description": "Answers to a previous enrichment_request. Filling gaps completes the same decision, so this does not bump intent_version.",
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "answers": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "PassthroughResponse": {
        "type": "object",
        "required": [
          "intent_id",
          "provider",
          "method",
          "path",
          "recorded"
        ],
        "additionalProperties": true,
        "properties": {
          "intent_id": {
            "$ref": "#/components/schemas/IntentId"
          },
          "provider": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "recorded": {
            "type": "boolean"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "PlatformDoc": {
        "type": "object",
        "required": [
          "platform",
          "key",
          "category",
          "docs_confidence",
          "events_posture"
        ],
        "additionalProperties": false,
        "properties": {
          "platform": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "pattern": "^[a-z0-9]+$"
          },
          "category": {
            "type": "string"
          },
          "docs_confidence": {
            "enum": [
              "Public",
              "Customer"
            ]
          },
          "events_posture": {
            "enum": [
              "push",
              "poll",
              "mixed"
            ]
          }
        }
      },
      "CapabilitiesResponse": {
        "type": "object",
        "required": [
          "platform",
          "carrier",
          "profile"
        ],
        "additionalProperties": true,
        "properties": {
          "platform": {
            "type": "string"
          },
          "sandbox": {
            "type": "boolean",
            "description": "true while the destination is a mock tenant rather than a live one."
          },
          "api": {
            "type": "object",
            "description": "The destination's public API posture: auth, style, base URL, webhooks, rate limits, objects.",
            "additionalProperties": true
          },
          "carrier": {
            "type": "object",
            "required": [
              "object_type",
              "field",
              "mode",
              "access"
            ],
            "properties": {
              "object_type": {
                "type": "string"
              },
              "field": {
                "type": "string"
              },
              "mode": {
                "enum": [
                  "stamp",
                  "link"
                ]
              },
              "access": {
                "enum": [
                  "open",
                  "tenant"
                ]
              }
            }
          },
          "profile": {
            "type": "object",
            "required": [
              "name",
              "object_type",
              "required_fields"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "object_type": {
                "type": "string"
              },
              "required_fields": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "optional_fields": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "additionalProperties": true,
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "EnrichmentGap": {
        "type": "object",
        "required": [
          "error",
          "enrichment_request"
        ],
        "additionalProperties": false,
        "description": "Preflight found fields the tenant requires that the intent does not carry yet.",
        "properties": {
          "error": {
            "type": "string"
          },
          "enrichment_request": {
            "$ref": "#/components/schemas/EnrichmentRequest"
          }
        }
      },
      "IntentId": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]{10,64}$",
        "description": "Minted at the decision and carried unchanged into every destination record. Fits a 64-character client-supplied id field, which is how the same id finds the record in either direction.",
        "examples": [
          "itn_7f3aK2mQ9xLp"
        ]
      }
    }
  },
  "externalDocs": {
    "description": "Human API reference, schema registry and destination coverage",
    "url": "https://composer.id/docs/api/index.html"
  }
}
