{ "openapi": "3.0.0", "info": { "title": "Unified Approvals Connector", "version": "1.0", "description": "The Unified Approvals Connector is the HTTP API for managing approvals on Workfront document versions. Use it to create approvals, build multi-stage workflows with conditional stage triggers, add and remind participants, record decisions, manage reusable approval templates, search across every approval the requesting user can see, and retrieve AI brand-review results captured by bot reviewers on a stage.\n\n## Authentication\n\nThe connector supports one authentication method:\n\n| Method | Header/Cookie | Use case |\n|--------|--------------|----------|\n| **Bearer** | `Authorization: Bearer ` | IMS Bearer token from Adobe IO / Developer Console |\n\nAll endpoints accept Bearer token auth.\n\nFor Bearer token auth, the following Workfront context headers are also required:\n- `x-api-key` \u2014 `client_id` of the technical account generated from the Adobe Developer Console (identifies the calling integration to the API gateway)\n- `x-gw-subdomain` \u2014 Workfront customer subdomain\n- `wf-customerid` \u2014 Workfront customer ID\n- `wf-userid` \u2014 Workfront user ID\n- `wf-lane` \u2014 Workfront deployment lane (e.g. `prod`, `preview`, `devtest`)\n> **Note on auth error codes:** The AIO gateway performs credential pre-flight before routing to the service. If the `Authorization` header is absent entirely, the gateway returns HTTP 403 (`error_code: 403010`, \"Oauth token is missing.\") and the request never reaches the service. If a token is present but invalid or expired, the gateway forwards the request and the service returns HTTP 401 (`error_code: 401013`).\n\n## Asset Types\n\nEndpoints currently only support `DOCV` (Workfront document version) as the `assetType` path parameter.\n\n\n## Base URL\n\n`https://workfront.adobe.io/workfront-approvals/`\n\n## Endpoint Groups\n\n| Tag | Base path | Auth |\n|-----|-----------|------|\n| Approvals | `/api/v1/approvals` | Complex |\n| Templates | `/api/v1/templates` | Complex |\n| Bots | `/api/v1/bots` | Complex |\n| Bot Reviews | `/api/v1/bot-reviews` | Complex |\n", "contact": { "name": "", "email": "", "url": "" } }, "servers": [ { "url": "https://workfront.adobe.io/workfront-approvals/", "description": "Production" } ], "tags": [ { "name": "Approvals", "description": "Approval lifecycle: create, read, delete" }, { "name": "Stages", "description": "Stage management within an approval" }, { "name": "Decisions", "description": "Make and delete decisions on approval stages" }, { "name": "Participants", "description": "Add, remove, and remind participants" }, { "name": "Templates", "description": "Approval template CRUD" }, { "name": "Bots", "description": "Retrieve Workfront bot users that are eligible to be added as reviewer participants on an approval. A bot reviewer is invoked automatically when its assigned stage becomes active." }, { "name": "Bot Reviews", "description": "AI brand review results from the Bot Registry" } ], "components": { "securitySchemes": { "Bearer": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "IMS Bearer token from Adobe IO / Developer Console. When used, the following context headers are also required:\n- `x-api-key` \u2014 `client_id` of the technical account generated from the Adobe Developer Console (identifies the calling integration to the API gateway).\n- `x-gw-subdomain` \u2014 Workfront customer subdomain.\n- `wf-customerid` \u2014 Workfront customer ID.\n- `wf-userid` \u2014 Workfront user ID.\n- `wf-lane` \u2014 Workfront deployment lane (e.g. `prod`, `preview`, `devtest`)." } }, "parameters": { "AssetType": { "name": "assetType", "in": "path", "required": true, "description": "The type of asset", "schema": { "type": "string", "enum": [ "DOCV" ], "example": "DOCV" } }, "AssetId": { "name": "assetId", "in": "path", "required": true, "description": "The ID of the asset", "schema": { "type": "string", "example": "673fc29b0006af515e33732d1ebdc39a" } }, "StageId": { "name": "stageId", "in": "path", "required": true, "description": "The ID of the approval stage", "schema": { "type": "string", "example": "design-review" } }, "ParticipantId": { "name": "participantId", "in": "path", "required": true, "description": "The ID of the participant", "schema": { "type": "string" } }, "ParticipantType": { "name": "participantType", "in": "path", "required": true, "description": "The type of participant", "schema": { "type": "string", "enum": [ "USER", "TEAMOB" ] } }, "TemplateId": { "name": "templateId", "in": "path", "required": true, "description": "The ID of the approval template", "schema": { "type": "string" } }, "ImsOrgId": { "name": "imsOrgId", "in": "path", "required": true, "description": "IMS Organization ID", "schema": { "type": "string" } }, "XRequestId": { "name": "x-request-id", "in": "header", "required": false, "description": "Unique identifier for request tracing. Auto-generated if not provided.", "schema": { "type": "string", "format": "uuid" } }, "XCorrelationId": { "name": "x-correlation-id", "in": "header", "required": false, "description": "Unique identifier for correlation across multiple service calls. Auto-generated if not provided.", "schema": { "type": "string" } }, "XApiKey": { "name": "x-api-key", "in": "header", "required": true, "schema": { "type": "string" }, "description": "`client_id` of the Adobe Developer Console technical account. Identifies the calling integration to the AIO gateway." }, "XGwSubdomain": { "name": "x-gw-subdomain", "in": "header", "required": true, "schema": { "type": "string" }, "description": "Workfront customer subdomain (e.g. `mycompany`)." }, "WfCustomerId": { "name": "wf-customerid", "in": "header", "required": true, "schema": { "type": "string" }, "description": "Workfront customer ID." }, "WfUserId": { "name": "wf-userid", "in": "header", "required": true, "schema": { "type": "string" }, "description": "Workfront user ID of the acting user." }, "WfLane": { "name": "wf-lane", "in": "header", "required": true, "schema": { "type": "string", "enum": [ "prod", "preview", "hub", "staging", "devtest" ] }, "description": "Workfront deployment lane." } }, "schemas": { "Approval": { "type": "object", "description": "An approval record for an asset", "properties": { "approvalGuid": { "type": "string", "description": "Unique identifier for the approval" }, "assetId": { "type": "string" }, "assetType": { "type": "string", "enum": [ "DOCV" ] }, "creatorId": { "type": "string" }, "realCreatorId": { "type": "string", "nullable": true, "description": "ID of the proxy user who actually created the approval. When the approval is created on behalf of another user (e.g. via a technical account or another proxying integration), this is the ID of the actual user making the call (the technical-account / proxy user). The companion `creatorId` field still reflects the user the action is attributed to. When no proxying takes place, this matches the companion field." }, "customerDomain": { "type": "string" }, "eauthTenantId": { "type": "string" }, "templateId": { "type": "string", "description": "ID of the template used to create this approval, if any." }, "productId": { "type": "string", "enum": [ "workfront" ], "default": "workfront", "example": "workfront", "description": "Identifier of the Workfront product the approval is associated with. Always `workfront` for the Unified Approvals Connector." }, "status": { "type": "string", "enum": [ "in review", "pending review", "approved", "approved with changes", "needs work", "reviewed", "withdrawn" ], "description": "Overall lifecycle status of the approval, derived from the rolled-up stage and participant decisions.\n\n- `in review` \u2014 At least one stage is active and waiting for decisions.\n- `pending review` \u2014 Approval exists but no stage has been activated yet.\n- `approved` \u2014 All required participants have approved.\n- `approved with changes` \u2014 All required participants have decided; at least one with changes.\n- `needs work` \u2014 At least one required participant has returned needs work.\n- `reviewed` \u2014 All reviewer-role participants have reviewed (no approver decisions required).\n- `withdrawn` \u2014 The approval has been retracted; no further actions are possible." }, "isLocked": { "type": "boolean", "description": "Whether the approval is currently locked. Mirrors the lock state of the active stage (a stage being manually locked sets the approval inactive)." }, "decisionDate": { "type": "string", "format": "date-time", "nullable": true }, "createdAt": { "type": "string", "format": "date-time", "nullable": true }, "updatedAt": { "type": "string", "format": "date-time", "nullable": true }, "isApprovalActive": { "type": "boolean", "description": "Computed flag that indicates whether the version being accessed is still the document's active (head) version. Compares the document's `currentVersionID` against the `assetId` of the requested version: when they match, the version is current and `isApprovalActive` is `true`; when the document has been superseded by a newer upload, it is `false`." }, "isEsmAsset": { "type": "boolean", "description": "Whether the asset is an ESM (Experience Storage Manager) asset" }, "frameSyncStatus": { "type": "boolean", "nullable": true, "description": "Whether the Frame.io asset sync is complete" }, "userInfo": { "type": "object", "description": "Contextual information about the authenticated user's relationship to this approval", "properties": { "isEditable": { "type": "boolean", "nullable": true, "description": "Whether the requesting user can make changes to this approval. Computed per request as `canEdit AND isActive AND hasLicenseAccess` \u2014 the user must have edit permission on the underlying asset, the approval must be in an active state, and the user must have a Workfront license tier that grants edit access. Used by write-path middleware to gate mutating requests and surfaced on every approval response so consumers can mirror the same gate in the UI." }, "hasLicenseAccess": { "type": "boolean", "nullable": true, "description": "Whether the requesting user's Workfront license tier grants the access needed to edit this approval. One of the inputs to `isEditable`." }, "activeDecision": { "type": "string", "nullable": true, "description": "The current user's most recent decision", "enum": [ "approved", "needs work", "approved with changes", "reviewed", null ] }, "action": { "type": "string", "nullable": true, "enum": [ "approve", "review", "revoke", null ], "description": "The next decision-related action the requesting user can take on this approval, derived from the user's `participantRole` and current `activeDecision`. Frontends typically render this as a button label.\n\n| Role / Decision | `userInfo.action` |\n|---|---|\n| `approver` (no decision yet) | `approve` |\n| `reviewer` (no decision yet) | `review` |\n| Decision = `approved` | `revoke` |\n| Decision = `needs work` | `approve` |\n| Decision = `reviewed` | `review` |" }, "availableDecisions": { "type": "object", "nullable": true, "description": "Map of decision key to display label for the current user", "additionalProperties": { "type": "string" } }, "currentUserMadeDecision": { "type": "boolean", "nullable": true } } }, "paths": { "type": "array", "items": { "$ref": "#/components/schemas/ApprovalPath" }, "description": "Parallel paths in this approval. Present only when the approval was created with `paths`. Each path contains its own stages and structure." } }, "example": { "approvalGuid": "6744feadafbbfb97a7c1c325", "assetId": "673fc29b0006af515e33732d1ebdc39a", "assetType": "DOCV", "creatorId": "15401B8A66C8F9CB0A49423C@13cc192466c8c9a949410f.e", "customerDomain": "mycompany", "status": "in review", "isLocked": false, "isApprovalActive": true, "isEsmAsset": true, "createdAt": "2024-11-25T22:48:13.598Z", "updatedAt": "2024-11-25T22:48:13.598Z", "stages": [ { "stageId": "design-review", "name": "Design Review", "status": "in review", "isLocked": false, "isActive": true, "isStarted": true, "isCompleted": false, "participants": [ { "participantId": "66cf5cec0002204507c8ce6d532dfc08", "participantType": "USER", "participantRole": "approver", "status": "notified", "createdAt": "2024-11-25T22:48:13.598Z", "updatedAt": "2024-11-25T22:48:13.598Z" } ], "createdAt": "2024-11-25T22:48:13.598Z", "updatedAt": "2024-11-25T22:48:13.598Z" } ], "structure": [ { "stageId": "design-review", "parentIds": [] } ], "userInfo": { "isEditable": true, "hasLicenseAccess": true, "activeDecision": null, "availableDecisions": { "approved": "Approve", "needs work": "Request changes" }, "currentUserMadeDecision": false } } }, "ApprovalStage": { "type": "object", "properties": { "stageId": { "type": "string", "example": "design-review", "description": "Identifier for this stage. Must be unique across all stages on the approval. Can be a short, human-readable slug (e.g. `design-review`)." }, "name": { "type": "string" }, "status": { "type": "string", "enum": [ "not started", "pending review", "in review", "approved", "approved with changes", "needs work", "reviewed" ], "description": "Lifecycle status of the stage.\n\n- `not started` \u2014 Stage has not yet been triggered to `isActive`. Set on creation and remains until the stage's activation trigger fires (typically when its parent stages complete).\n- `pending review` \u2014 Stage is active and awaiting participant decisions.\n- `in review` \u2014 Stage is active and at least one participant has not yet decided.\n- `approved` \u2014 All required participants on this stage have approved.\n- `approved with changes` \u2014 All required participants have decided, at least one has chosen `approved with changes`, and the rest have chosen `approved` or `approved with changes`. If any required participant has returned `needs work`, the stage rolls up to `needs work` instead.\n- `needs work` \u2014 At least one required participant has responded with `needs work`. `needs work` outranks `approved` and `approved with changes`, so the stage rolls up to this status whenever any required participant has returned `needs work`.\n- `reviewed` \u2014 All reviewer participants have reviewed." }, "deadlineDate": { "type": "string", "format": "date-time", "nullable": true }, "deadlineBusinessDays": { "type": "number", "nullable": true }, "deadlineTime": { "type": "string", "nullable": true, "example": "17:00", "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$", "description": "Deadline time of day in 24-hour `HH:MM` format (e.g. `\"17:00\"`)." }, "deadlineTimeOfDay": { "type": "object", "nullable": true, "description": "Time-of-day component of the stage deadline. An object with two numeric properties \u2014 `hours` (0\u201323) and `minutes` (0\u201359) \u2014 that, paired with the date derived from `deadlineBusinessDays`, pins the deadline to a specific moment. Set to `null` when no time-of-day is configured.\n\nExample: `{ \"hours\": 17, \"minutes\": 0 }` for 5:00 PM.", "properties": { "hours": { "type": "number", "minimum": 0, "maximum": 23, "description": "Hour of the day (0\u201323)." }, "minutes": { "type": "number", "minimum": 0, "maximum": 59, "description": "Minute of the hour (0\u201359)." } }, "example": { "hours": 17, "minutes": 0 } }, "decisionDate": { "type": "string", "format": "date-time" }, "isLocked": { "type": "boolean", "description": "Stage has been manually locked (set inactive)." }, "isActive": { "type": "boolean", "description": "Stage is currently accepting decisions." }, "isLockOverridden": { "type": "boolean", "description": "Stage lock was overridden by an admin." }, "isStarted": { "type": "boolean", "description": "Stage has been started at least once." }, "isCompleted": { "type": "boolean", "description": "Stage has reached a terminal state." }, "stageMetadata": { "type": "object", "additionalProperties": true, "description": "Almost entirely a Frame.io integration artifact \u2014 when a Frame.io share is created for the stage it holds the generated review link and comments link. Defaults to `{}` if no Frame share was created (for example, on non-ESM or non-Frame assets).", "default": {} }, "participants": { "type": "array", "items": { "$ref": "#/components/schemas/ApprovalStageParticipant" } }, "config": { "$ref": "#/components/schemas/ApprovalStageConfig" }, "triggers": { "type": "array", "items": { "$ref": "#/components/schemas/StageTrigger" } }, "parentIds": { "type": "array", "description": "IDs of stages that must complete before this stage activates.", "items": { "type": "string" } }, "customMessage": { "type": "string", "maxLength": 500, "description": "Optional message sent to participants when this stage is activated" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "pathId": { "type": "string", "description": "ID of the path this stage belongs to. Present when the approval uses paths." } } }, "ApprovalStageParticipant": { "type": "object", "properties": { "participantId": { "type": "string" }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ] }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Role this participant plays on the stage.\n\n- `approver` \u2014 Has a binding vote; their decision directly affects stage and approval status.\n- `reviewer` \u2014 Non-binding; can mark reviewed but does not block approval progression.\n\nThe role, combined with the participant's current decision, also drives the `userInfo.action` value on every approval response \u2014 see [`Approval.userInfo.action`](#section/Schemas/Approval) for the role/decision \u2192 action mapping." }, "participantMetadata": { "$ref": "#/components/schemas/ParticipantMetadata" }, "requesterId": { "type": "string", "description": "ID of the user who added this participant" }, "realRequesterId": { "type": "string", "nullable": true, "description": "ID of the proxy user who actually added this participant to the stage. When the participant is added on behalf of another user (e.g. via a technical account or another proxying integration), this is the ID of the actual user making the call (the technical-account / proxy user). The companion `requesterId` field still reflects the user the action is attributed to. When no proxying takes place, this matches the companion field." }, "status": { "type": "string", "enum": [ "notified", "opened", "commented", "approved", "approved with changes", "needs work", "reviewed" ], "description": "Lifecycle status of this participant on the stage.\n\n- `notified` \u2014 Participant has been sent a notification but has not yet opened or decided.\n- `opened` \u2014 Participant has opened the review but has not yet decided.\n- `commented` \u2014 Participant has left a comment but has not made a final decision.\n- `approved` \u2014 Participant has approved.\n- `approved with changes` \u2014 Participant has approved with changes requested.\n- `needs work` \u2014 Participant returned needs work.\n- `reviewed` \u2014 Participant has marked the review complete (reviewer role only)." }, "activities": { "type": "array", "items": { "$ref": "#/components/schemas/ParticipantActivity" } }, "firstDecisionAt": { "type": "string", "format": "date-time" }, "decisionDate": { "type": "string", "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "wfMetadata": { "$ref": "#/components/schemas/ParticipantWfMetadata" } } }, "ParticipantActivity": { "type": "object", "properties": { "userId": { "type": "string" }, "realUserId": { "type": "string", "description": "ID of the proxy user who actually performed the activity. When the activity is performed on behalf of another user (e.g. via a technical account or another proxying integration), this is the ID of the actual user making the call (the technical-account / proxy user). The companion `userId` field still reflects the user the action is attributed to. When no proxying takes place, this matches the companion field." }, "decision": { "type": "string", "description": "Decision made (e.g. 'approved', 'needs work', 'approved with changes', 'reviewed')", "enum": [ "approved", "needs work", "approved with changes", "reviewed" ] }, "decisionDate": { "type": "string", "format": "date-time" }, "openedAt": { "type": "string", "format": "date-time" }, "notifiedAt": { "type": "string", "format": "date-time" }, "userName": { "type": "string" } } }, "ApprovalStageConfig": { "type": "object", "properties": { "autoLockEnabled": { "type": "boolean", "description": "Automatically lock the stage when all participants have decided" }, "decisionRules": { "type": "string", "nullable": true, "enum": [ "onlyOneDecisionRequired" ], "description": "Override rule for when the stage is considered decided. `onlyOneDecisionRequired` marks the stage complete when any one participant decides." } } }, "StageTrigger": { "type": "object", "required": [ "type", "when", "parameters" ], "description": "Defines when and how a stage is automatically activated", "properties": { "type": { "type": "string", "enum": [ "activation" ], "description": "Type of trigger action" }, "when": { "type": "string", "enum": [ "onCreate", "onStagesComplete" ], "description": "`onCreate` activates the stage immediately when the approval is created. `onStagesComplete` activates after specified parent stages complete." }, "parameters": { "type": "object", "properties": { "stages": { "type": "array", "items": { "type": "string" }, "description": "Stage IDs that must complete to fire this trigger (used with `onStagesComplete`)" }, "allowedDecisions": { "type": "array", "items": { "type": "string", "enum": [ "approved", "approved with changes", "needs work", "reviewed" ] }, "description": "Decisions that count as 'complete' for this trigger" }, "activateOnDecision": { "type": "integer", "description": "Number of qualifying decisions on the parent stages that must be reached before the stage activates. Combined with `allowedDecisions` to define which decisions count toward the threshold. Defaults to all required decisions on the listed stages." } } } }, "example": { "type": "activation", "when": "onStagesComplete", "parameters": { "stages": [ "design-review" ], "allowedDecisions": [ "approved", "approved with changes" ] } } }, "ApprovalStructure": { "type": "object", "description": "Represents one node in the stage dependency graph", "properties": { "stageId": { "type": "string", "example": "design-review", "description": "Identifier of the stage this structure node represents. Matches the `stageId` on one of the approval's `stages[]` entries; must be unique across all stages on the approval (e.g. `design-review`)." }, "parentIds": { "type": "array", "items": { "type": "string" }, "description": "IDs of stages that must complete before this stage activates." }, "triggers": { "type": "array", "items": { "$ref": "#/components/schemas/StageTrigger" } }, "pathId": { "type": "string", "description": "ID of the path this structure node belongs to. Present when the approval uses paths." } } }, "StageBody": { "type": "object", "required": [ "participants" ], "description": "Stage definition used when creating or updating an approval", "properties": { "name": { "type": "string" }, "deadlineDate": { "type": "string", "format": "date-time", "nullable": true }, "deadlineBusinessDays": { "type": "number", "nullable": true }, "deadlineTime": { "type": "string", "nullable": true, "example": "17:00", "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$", "description": "Deadline time of day in 24-hour `HH:MM` format (e.g. `\"17:00\"`)." }, "stageMetadata": { "type": "object", "additionalProperties": true, "description": "Almost entirely a Frame.io integration artifact \u2014 when a Frame.io share is created for the stage it holds the generated review link and comments link. Defaults to `{}` if no Frame share was created (for example, on non-ESM or non-Frame assets).", "default": {} }, "participants": { "type": "array", "minItems": 1, "items": { "type": "object", "required": [ "participantId", "participantType", "participantRole" ], "properties": { "participantId": { "type": "string" }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ] }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Role this participant plays on the stage.\n\n- `approver` \u2014 Has a binding vote; their decision directly affects stage and approval status.\n- `reviewer` \u2014 Non-binding; can mark reviewed but does not block approval progression.\n\nThe role, combined with the participant's current decision, also drives the `userInfo.action` value on every approval response \u2014 see [`Approval.userInfo.action`](#section/Schemas/Approval) for the role/decision \u2192 action mapping." }, "participantMetadata": { "$ref": "#/components/schemas/ParticipantMetadata" } } } }, "config": { "$ref": "#/components/schemas/ApprovalStageConfig" }, "parentIds": { "type": "array", "items": { "type": "string" }, "description": "IDs of stages that must complete before this stage activates." }, "triggers": { "type": "array", "items": { "$ref": "#/components/schemas/StageTrigger" } }, "customMessage": { "type": "string", "maxLength": 500, "description": "Optional message for participants when this stage activates" }, "pathId": { "type": "string", "description": "Path this stage belongs to. Only relevant when creating or updating with `paths`." } } }, "ParticipantBody": { "type": "object", "description": "Participant definition used in request bodies", "properties": { "stageId": { "type": "string", "example": "design-review", "description": "ID of an existing stage on the approval to attach this participant to (e.g. `design-review`)." }, "participantId": { "type": "string" }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ] }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Role this participant plays on the stage.\n\n- `approver` \u2014 Has a binding vote; their decision directly affects stage and approval status.\n- `reviewer` \u2014 Non-binding; can mark reviewed but does not block approval progression.\n\nThe role, combined with the participant's current decision, also drives the `userInfo.action` value on every approval response \u2014 see [`Approval.userInfo.action`](#section/Schemas/Approval) for the role/decision \u2192 action mapping." }, "participantMetadata": { "$ref": "#/components/schemas/ParticipantMetadata" } } }, "Template": { "type": "object", "properties": { "templateId": { "type": "string" }, "name": { "type": "string" }, "assetType": { "type": "string", "enum": [ "DOCV" ] }, "timeframeEstimate": { "type": "integer", "description": "Computed timeframe estimate, in business days, derived from the sum of each stage's `deadlineBusinessDays` value. Read-only.", "readOnly": true }, "usageCount": { "type": "integer" }, "lastUsedOnDate": { "type": "string", "format": "date-time" }, "creatorId": { "type": "string" }, "createdBy": { "type": "string", "description": "Display name of the creator" }, "createdByAvatarDate": { "type": "string", "nullable": true }, "createdByLinkTo": { "type": "string", "description": "Profile URL path, e.g. `/USER/{id}/detail`" }, "createdByMetadata": { "type": "object", "additionalProperties": true }, "customerId": { "type": "string" }, "companyId": { "type": "string", "nullable": true }, "stages": { "type": "array", "items": { "$ref": "#/components/schemas/TemplateStage" } }, "structure": { "type": "array", "items": { "$ref": "#/components/schemas/ApprovalStructure" }, "description": "Workflow structure defining stage ordering and trigger dependencies." }, "sharedWith": { "type": "array", "items": { "type": "object", "properties": { "userId": { "type": "string" }, "accessLevel": { "type": "string", "enum": [ "EDIT_ACCESS", "VIEW_ACCESS" ] } } } }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } }, "example": { "templateId": "template-id", "name": "Test Template", "assetType": "DOCV", "creatorId": "user-id", "customerId": "customer-id", "stages": [ { "stageId": "stage-1", "name": "Stage 1", "deadlineBusinessDays": 3, "deadlineTimeOfDay": { "hours": 17, "minutes": 0 }, "participants": [ { "participantId": "user-123", "participantType": "USER", "participantRole": "approver", "participantMetadata": {} } ] }, { "stageId": "stage-2", "name": "Stage 2", "deadlineBusinessDays": 2, "deadlineTimeOfDay": { "hours": 12, "minutes": 30 }, "participants": [] } ], "structure": [ { "stageId": "stage-1", "parentIds": [], "triggers": [ { "type": "activation", "when": "onCreate" } ] }, { "stageId": "stage-2", "parentIds": [ "stage-1" ], "triggers": [ { "type": "activation", "when": "onStagesComplete", "parameters": { "stages": [ "stage-1" ], "activateOnDecision": 2, "allowedDecisions": [ "approved" ] } } ] } ], "usageCount": 0, "createdAt": "2026-01-15T17:00:00.000Z", "updatedAt": "2026-01-15T17:00:00.000Z" } }, "TemplateStage": { "type": "object", "properties": { "stageId": { "type": "string", "example": "design-review", "description": "Identifier for this template stage. Must be unique across all stages within the template (e.g. `design-review`)." }, "name": { "type": "string" }, "deadlineBusinessDays": { "type": "integer" }, "participants": { "type": "array", "items": { "$ref": "#/components/schemas/TemplateStageParticipant" } }, "deadlineTimeOfDay": { "type": "object", "nullable": true, "description": "Time-of-day component of the stage deadline. An object with two numeric properties \u2014 `hours` (0\u201323) and `minutes` (0\u201359) \u2014 that, paired with the date derived from `deadlineBusinessDays`, pins the deadline to a specific moment. Set to `null` when no time-of-day is configured.\n\nExample: `{ \"hours\": 17, \"minutes\": 0 }` for 5:00 PM.", "properties": { "hours": { "type": "number", "minimum": 0, "maximum": 23, "description": "Hour of the day (0\u201323)." }, "minutes": { "type": "number", "minimum": 0, "maximum": 59, "description": "Minute of the hour (0\u201359)." } }, "example": { "hours": 17, "minutes": 0 } } } }, "TemplateStageParticipant": { "type": "object", "properties": { "participantId": { "type": "string" }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ], "description": "Type of participant.\n\n- `USER` \u2014 Individual Workfront user (or AI bot user).\n- `TEAMOB` \u2014 Workfront team." }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Role this participant plays on the stage.\n\n- `approver` \u2014 Has a binding vote; their decision directly affects stage and approval status.\n- `reviewer` \u2014 Non-binding; can mark reviewed but does not block approval progression.\n\nThe role, combined with the participant's current decision, also drives the `userInfo.action` value on every approval response \u2014 see [`Approval.userInfo.action`](#section/Schemas/Approval) for the role/decision \u2192 action mapping." }, "participantMetadata": { "$ref": "#/components/schemas/ParticipantMetadata" }, "name": { "type": "string" }, "emailAddr": { "type": "string", "nullable": true, "description": "User's email address. Populated only when `participantType` is `USER`." }, "licenseType": { "type": "string", "nullable": true, "description": "Workfront license tier of the user. Populated only when `participantType` is `USER`." }, "eauthUserID": { "type": "string", "nullable": true, "description": "IMS-bound external authentication user ID. Populated only when `participantType` is `USER`." }, "avatarDate": { "type": "string", "nullable": true, "description": "Avatar version timestamp used to bust the avatar image cache. Populated only when `participantType` is `USER`." }, "linkTo": { "type": "string", "nullable": true }, "teamMembers": { "type": "array", "description": "Members of the team. Populated only when `participantType` is `TEAMOB`.", "items": { "$ref": "#/components/schemas/TeamMember" } } } }, "TemplateBody": { "type": "object", "description": "Request body for creating or updating a template.", "required": [ "name", "stages" ], "properties": { "name": { "type": "string", "description": "Display name of the template." }, "assetType": { "type": "string", "enum": [ "DOCV" ], "description": "Asset type the template applies to." }, "companyId": { "type": "string", "nullable": true }, "stages": { "type": "array", "minItems": 1, "description": "Stages that make up the template, in graph form.", "items": { "type": "object", "required": [ "stageId", "name" ], "properties": { "stageId": { "type": "string", "example": "design-review", "description": "Identifier for this template stage. Must be unique across all stages within the template (e.g. `design-review`)." }, "name": { "type": "string" }, "parentIds": { "type": "array", "items": { "type": "string" }, "description": "IDs of stages that must complete before this stage activates." }, "triggers": { "type": "array", "description": "Activation triggers for the stage. Each entry defines when and how the stage becomes active relative to other stages on the template.", "items": { "$ref": "#/components/schemas/StageTrigger" } }, "deadlineBusinessDays": { "type": "integer", "description": "Number of business days from stage activation to its deadline." }, "deadlineTimeOfDay": { "type": "object", "nullable": true, "description": "Time-of-day component of the stage deadline. An object with two numeric properties \u2014 `hours` (0\u201323) and `minutes` (0\u201359) \u2014 that, paired with the date derived from `deadlineBusinessDays`, pins the deadline to a specific moment. Set to `null` when no time-of-day is configured.\n\nExample: `{ \"hours\": 17, \"minutes\": 0 }` for 5:00 PM.", "properties": { "hours": { "type": "number", "minimum": 0, "maximum": 23, "description": "Hour of the day (0\u201323)." }, "minutes": { "type": "number", "minimum": 0, "maximum": 59, "description": "Minute of the hour (0\u201359)." } }, "example": { "hours": 17, "minutes": 0 } }, "participants": { "type": "array", "items": { "type": "object", "required": [ "participantId", "participantType", "participantRole" ], "properties": { "participantId": { "type": "string" }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ], "description": "Type of participant.\n\n- `USER` \u2014 Individual Workfront user (or AI bot user).\n- `TEAMOB` \u2014 Workfront team." }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Role this participant plays on the stage.\n\n- `approver` \u2014 Has a binding vote; their decision directly affects stage and approval status.\n- `reviewer` \u2014 Non-binding; can mark reviewed but does not block approval progression." }, "participantMetadata": { "$ref": "#/components/schemas/ParticipantMetadata" } } } } } } }, "sharedWith": { "type": "array", "description": "Optional list of users the template is shared with.", "items": { "type": "object", "properties": { "userId": { "type": "string" }, "accessLevel": { "type": "string", "enum": [ "EDIT_ACCESS", "VIEW_ACCESS" ] } } } } }, "example": { "name": "Test Template", "stages": [ { "stageId": "stage-1", "name": "Stage 1", "parentIds": [], "triggers": [ { "type": "activation", "when": "onCreate" } ], "deadlineBusinessDays": 3, "deadlineTimeOfDay": { "hours": 17, "minutes": 0 }, "participants": [ { "participantId": "user-123", "participantType": "USER", "participantRole": "approver", "participantMetadata": {} } ] }, { "stageId": "stage-2", "name": "Stage 2", "parentIds": [ "stage-1" ], "triggers": [ { "type": "activation", "when": "onStagesComplete", "parameters": { "stages": [ "stage-1" ], "activateOnDecision": 2, "allowedDecisions": [ "approved" ] } } ], "deadlineBusinessDays": 2, "deadlineTimeOfDay": { "hours": 12, "minutes": 30 }, "participants": [ { "participantId": "user-456", "participantType": "USER", "participantRole": "reviewer", "participantMetadata": {} } ] } ] } }, "ErrorResponse": { "type": "object", "properties": { "statusCode": { "type": "integer" }, "message": { "type": "string" }, "errors": { "type": "array", "description": "Validation error details (present on 400 FST_ERR_VALIDATION errors)", "items": { "type": "object" } }, "response": { "type": "object", "description": "Upstream service error response, if applicable" } } }, "GuidelineCheckResult": { "type": "object", "properties": { "guideline": { "type": "string", "description": "Guideline identifier." }, "guidelineAttribute": { "type": "string", "description": "Attribute of the guideline being evaluated." }, "guidelineTrait": { "type": "string", "description": "Specific trait under the attribute." }, "guidelineTraitType": { "type": "string", "description": "Trait type (e.g. critical, non-critical)." }, "passed": { "type": "boolean" }, "score": { "type": "number" }, "reason": { "type": "string", "description": "Explanation for the pass/fail outcome." } } }, "ParticipantUserMetadata": { "type": "object", "description": "Metadata fields populated when `participantType` is `USER`.", "additionalProperties": true, "properties": { "isBot": { "type": "boolean", "description": "Whether this user is an AI bot participant." }, "participantIdType": { "type": "string", "enum": [ "wf_guid", "ims", "email" ], "description": "How `participantId` is typed:\n- `wf_guid` \u2014 non-ESM assets.\n- `ims` \u2014 ESM assets with an IMS `eauthUserID`.\n- `email` \u2014 ESM assets without an IMS `eauthUserID`." }, "wfUserId": { "type": "string", "description": "The Workfront internal user ID (32-character hex)." }, "emailAddr": { "type": "string", "description": "User's email address. Omitted when not available from Workfront." } } }, "ParticipantTeamMetadata": { "type": "object", "description": "Metadata fields populated when `participantType` is `TEAMOB`.", "additionalProperties": true, "properties": { "isBot": { "type": "boolean", "description": "Whether this team is an AI bot participant." } } }, "ParticipantMetadata": { "type": "object", "additionalProperties": true, "description": "Free-form metadata about the participant. The shape varies by `participantType`:\n\n**`USER` participants**\n```\n{\n \"isBot\": boolean,\n \"participantIdType\": \"wf_guid\" | \"ims\" | \"email\",\n \"wfUserId\": \"string\",\n \"emailAddr\": \"string\" // omitted when not available\n}\n```\n\n**`TEAMOB` (team) participants**\n```\n{\n \"isBot\": boolean\n}\n```\n\nSee `ParticipantUserMetadata` and `ParticipantTeamMetadata` for the typed shapes. Additional context-specific properties may be present; consumers should treat unknown keys as informational.", "oneOf": [ { "$ref": "#/components/schemas/ParticipantUserMetadata" }, { "$ref": "#/components/schemas/ParticipantTeamMetadata" } ] }, "TeamMember": { "type": "object", "description": "Workfront user that is a member of a team participant.", "properties": { "ID": { "type": "string", "description": "Workfront user ID." }, "name": { "type": "string" }, "firstName": { "type": "string" }, "lastName": { "type": "string" }, "emailAddr": { "type": "string", "nullable": true }, "avatarDate": { "type": "string", "nullable": true }, "locale": { "type": "string", "nullable": true }, "isActive": { "type": "boolean" } } }, "ParticipantUserWfMetadata": { "type": "object", "description": "Workfront-derived enrichment fields populated when `participantType` is `USER`.", "properties": { "name": { "type": "string", "description": "Display name of the user." }, "emailAddr": { "type": "string", "nullable": true, "description": "User's email address." }, "licenseType": { "type": "string", "nullable": true, "description": "Workfront license tier." }, "wfUserId": { "type": "string", "description": "Workfront internal user ID." }, "eauthUserID": { "type": "string", "nullable": true, "description": "IMS-bound external authentication user ID." }, "avatarDate": { "type": "string", "nullable": true, "description": "Avatar version timestamp used to bust avatar cache." } } }, "ParticipantTeamWfMetadata": { "type": "object", "description": "Workfront-derived enrichment fields populated when `participantType` is `TEAMOB`.", "properties": { "name": { "type": "string", "description": "Team display name." }, "avatarDate": { "type": "string", "nullable": true }, "teamMembers": { "type": "array", "description": "Members of the team.", "items": { "$ref": "#/components/schemas/TeamMember" } } } }, "ParticipantWfMetadata": { "type": "object", "additionalProperties": true, "description": "Workfront-derived enrichment fields for the participant. The shape depends on `participantType` \u2014 see `ParticipantUserWfMetadata` and `ParticipantTeamWfMetadata`.", "oneOf": [ { "$ref": "#/components/schemas/ParticipantUserWfMetadata" }, { "$ref": "#/components/schemas/ParticipantTeamWfMetadata" } ] }, "ApprovalDeletedResponse": { "type": "object", "description": "Returned when removing the last remaining participant on the approval causes the approval itself to be deleted. The body contains user-context flags only (no approval payload), with `deleted: true` to signal the cascading delete.", "required": [ "deleted" ], "properties": { "deleted": { "type": "boolean", "enum": [ true ], "description": "Always `true` on this response shape; the approval no longer exists." }, "isApprovalActive": { "type": "boolean", "description": "Whether the version being accessed is the document's active head version." }, "userInfo": { "type": "object", "properties": { "isEditable": { "type": "boolean", "nullable": true }, "hasLicenseAccess": { "type": "boolean", "nullable": true } } }, "frameSyncStatus": { "type": "string", "nullable": true }, "isEsmAsset": { "type": "boolean" } } }, "BotReviewFieldResult": { "type": "object", "properties": { "fieldSummary": { "type": "object", "properties": { "totalGuidelineTraitsChecked": { "type": "integer", "description": "Total guideline traits evaluated." }, "totalGuidelineTraitsPassed": { "type": "integer", "description": "Number of guideline traits that passed." }, "totalCriticalGuidelineTraitsChecked": { "type": "integer", "description": "Total critical guideline traits evaluated." }, "totalCriticalGuidelineTraitsPassed": { "type": "integer", "description": "Number of critical guideline traits that passed." }, "totalNonCriticalGuidelineTraitsChecked": { "type": "integer", "description": "Total non-critical guideline traits evaluated." }, "totalNonCriticalGuidelineTraitsPassed": { "type": "integer", "description": "Number of non-critical guideline traits that passed." } } }, "results": { "type": "array", "items": { "$ref": "#/components/schemas/GuidelineCheckResult" } } } }, "BotReviewValidationResult": { "type": "object", "properties": { "validationSummary": { "type": "object", "description": "Aggregate result across all checks for the asset (or page).", "properties": { "passed": { "type": "boolean", "description": "Whether the asset passed validation overall." }, "imageGuidelines": { "type": "object", "description": "Aggregate guideline-trait counts plus an overall pass flag and score.", "properties": { "totalGuidelineTraitsChecked": { "type": "integer", "description": "Total guideline traits evaluated." }, "totalGuidelineTraitsPassed": { "type": "integer", "description": "Number of guideline traits that passed." }, "totalCriticalGuidelineTraitsChecked": { "type": "integer", "description": "Total critical guideline traits evaluated." }, "totalCriticalGuidelineTraitsPassed": { "type": "integer", "description": "Number of critical guideline traits that passed." }, "totalNonCriticalGuidelineTraitsChecked": { "type": "integer", "description": "Total non-critical guideline traits evaluated." }, "totalNonCriticalGuidelineTraitsPassed": { "type": "integer", "description": "Number of non-critical guideline traits that passed." }, "passed": { "type": "boolean" }, "score": { "type": "number" } } } } }, "fieldResults": { "type": "object", "description": "Per-field validation results, keyed by field name.", "additionalProperties": { "$ref": "#/components/schemas/BotReviewFieldResult" } } } }, "BotReview": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique review ID." }, "botId": { "type": "string", "description": "ID of the bot that produced this review." }, "brandId": { "type": "string", "description": "ID of the brand associated with the bot." }, "categoryId": { "type": "string", "nullable": true, "description": "Category for this review, if any." }, "validationTypes": { "type": "array", "items": { "type": "string" }, "description": "Validation types applied to this asset." }, "parentObjType": { "type": "string", "description": "Type of the parent object (e.g. `DOCU`)." }, "parentObjId": { "type": "string", "description": "ID of the parent object." }, "objType": { "type": "string", "description": "Type of the object reviewed (e.g. `DOCV`)." }, "objId": { "type": "string", "description": "ID of the object reviewed." }, "stageId": { "type": "string", "description": "ID of the approval stage this review is attached to." }, "pdfDownloadUrl": { "type": "string", "nullable": true, "description": "Pre-signed URL to download a PDF of the review, when available." }, "bot": { "type": "string", "description": "Display name of the bot at the time of review." }, "status": { "type": "string", "description": "Lifecycle status of the review (e.g. completed, failed)." }, "failureCode": { "type": "string", "description": "Machine-readable failure code when the review could not complete." }, "failureMessage": { "type": "string", "description": "Human-readable failure message paired with `failureCode`." }, "createdAt": { "type": "string", "format": "date-time" }, "validationResult": { "$ref": "#/components/schemas/BotReviewValidationResult" }, "multiPageValidationResult": { "type": "object", "description": "Per-page validation results for multi-page assets, keyed by page identifier. Each value follows the same shape as `validationResult`.", "additionalProperties": { "$ref": "#/components/schemas/BotReviewValidationResult" } } } }, "ApprovalPathCreate": { "type": "object", "description": "A path grouping stages together for a parallel or branching approval flow. Used in create requests.", "required": [ "stages" ], "properties": { "pathId": { "type": "string", "description": "Optional identifier for the path. Auto-generated if omitted." }, "name": { "type": "string", "description": "Display name for the path" }, "stages": { "type": "array", "minItems": 1, "description": "Stages belonging to this path. Each item follows the `StageBody` shape.", "items": { "$ref": "#/components/schemas/StageBody" } } } }, "ApprovalPathUpdate": { "type": "object", "description": "A path grouping stages together for a parallel or branching approval flow. Used in update (PUT) requests. `pathId` is required to identify the path being updated.", "required": [ "pathId", "stages" ], "properties": { "pathId": { "type": "string", "description": "Identifier of the path to update" }, "name": { "type": "string", "description": "Display name for the path" }, "stages": { "type": "array", "minItems": 1, "description": "Stages belonging to this path. Each item follows the `StageBody` shape.", "items": { "$ref": "#/components/schemas/StageBody" } } } }, "ApprovalPath": { "type": "object", "description": "A path in the approval response \u2014 a named group of stages that run in parallel with other paths.", "properties": { "pathId": { "type": "string", "description": "Unique identifier for this path" }, "name": { "type": "string", "description": "Display name of the path" }, "status": { "type": "string", "description": "Aggregate status of the path" }, "stages": { "type": "array", "items": { "$ref": "#/components/schemas/ApprovalStage" }, "description": "Stages belonging to this path" }, "structure": { "type": "array", "items": { "$ref": "#/components/schemas/ApprovalStructure" }, "description": "Stage dependency graph for this path" } } } }, "responses": { "ApprovalResponse": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } }, "UnauthorizedResponse": { "description": "Unauthorized \u2014 no valid auth credentials provided", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "NotFoundResponse": { "description": "Not Found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "BadRequestResponse": { "description": "Bad Request \u2014 validation failure or invalid state", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "InternalServerErrorResponse": { "description": "Internal Server Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "LengthRequiredResponse": { "description": "Length Required \u2014 the service requires a `Content-Length` header. Send an empty JSON object (`{}`) as the request body." } } }, "paths": { "/api/v1/approvals/{assetType}/{assetId}": { "get": { "tags": [ "Approvals" ], "summary": "Get approval", "description": "Get approval details for an asset.", "operationId": "getApproval", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "post": { "tags": [ "Approvals" ], "summary": "Create approval", "description": "Creates an approval with the supplied stage data. The `stages` array in the body defines the approval structure and is used as-is. `templateId` is optional metadata: the caller is expected to have fetched the template separately (`GET /api/v1/templates/{templateId}`) and copied its stages into the request body. When `templateId` is supplied, it is recorded on the new approval and the corresponding template's `usageCount` is incremented and `lastUsedOnDate` is refreshed.", "operationId": "createApproval", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "stages": { "type": "array", "minItems": 1, "description": "Stage definitions used to build the approval. The server uses this array as-is \u2014 it does not look up or expand any referenced template. To create an approval from a template, the caller must fetch the template independently (`GET /api/v1/templates/{templateId}`), copy its `stages` into this array, and optionally pass the same `templateId` to record the source on the approval and increment its usage counter.", "items": { "$ref": "#/components/schemas/StageBody" } }, "templateId": { "type": "string", "description": "ID of the template used to create this approval, if any. Recorded on the approval for traceability and used to increment the template's `usageCount` and refresh `lastUsedOnDate`. The server does **not** load stages from the template \u2014 the caller must fetch the template via `GET /api/v1/templates/{templateId}` and copy its stages into the `stages` array." }, "paths": { "type": "array", "minItems": 1, "description": "Parallel paths for the approval. Either `stages` or `paths` must be provided, not both. When `paths` is used, each path groups its own stages; `stages` should be omitted.", "items": { "$ref": "#/components/schemas/ApprovalPathCreate" } } }, "anyOf": [ { "required": [ "stages" ] }, { "required": [ "paths" ] } ] } } } }, "responses": { "201": { "$ref": "#/components/responses/ApprovalResponse", "description": "Approval created." }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "delete": { "tags": [ "Approvals" ], "summary": "Delete approval", "description": "Deletes the approval for the given asset. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "deleteApproval", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "204": { "description": "Approval deleted successfully \u2014 no content returned" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/getSuggestedApprovals": { "get": { "tags": [ "Approvals" ], "summary": "Get suggested approvals", "description": "Returns suggested approval payloads derived from prior document versions, shaped for use when creating a new approval on the current asset. Results are ordered newest version first.", "operationId": "getSuggestedApprovals", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "required": [ "suggestedApprovals" ], "properties": { "suggestedApprovals": { "type": "array", "items": { "type": "object", "properties": { "sourceVersion": { "description": "Document version number this suggestion was derived from", "oneOf": [ { "type": "number" }, { "type": "string" } ] } }, "additionalProperties": true } } } } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/stages": { "post": { "tags": [ "Stages" ], "summary": "Create stages (auto-creates approval)", "description": "Adds one or more stages to the approval for the given asset. If no approval exists for the asset yet, one is created automatically \u2014 so this endpoint can be used in place of `POST /api/v1/approvals/{assetType}/{assetId}` to create an approval and its initial stages in a single call. Returns 201 on success.", "operationId": "postStages", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "stages": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/StageBody", "properties": { "pathId": { "type": "string", "description": "Path this stage belongs to" } } } }, "templateId": { "type": "string", "description": "ID of the template used to create this approval, if any." }, "paths": { "type": "array", "minItems": 1, "description": "Parallel paths to add. Either `stages` or `paths` must be provided.", "items": { "$ref": "#/components/schemas/ApprovalPathCreate" } } }, "anyOf": [ { "required": [ "stages" ] }, { "required": [ "paths" ] } ] } } } }, "responses": { "201": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "put": { "tags": [ "Stages" ], "summary": "Update all stages", "description": "Replaces all stages on an existing approval with the given stage data. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "putStages", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "stages": { "type": "array", "items": { "$ref": "#/components/schemas/StageBody" } }, "paths": { "type": "array", "minItems": 1, "description": "Parallel paths to update. Either `stages` or `paths` must be provided.", "items": { "$ref": "#/components/schemas/ApprovalPathUpdate" } } }, "anyOf": [ { "required": [ "stages" ] }, { "required": [ "paths" ] } ] } } } }, "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/stages/{stageId}": { "patch": { "tags": [ "Stages" ], "summary": "Update a stage", "description": "Partially updates any field on the specified stage. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "patchStage", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StageBody" } } } }, "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "delete": { "tags": [ "Stages" ], "summary": "Delete a stage", "description": "Deletes the specified stage from the approval. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "deleteStage", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/stages/{stageId}/lock": { "put": { "tags": [ "Stages" ], "summary": "Lock a stage", "description": "Locks the specified stage. All decisions on the stage must have been made before locking. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "lockStage", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } }, "requestBody": { "required": true, "description": "Send an empty JSON object. The service returns HTTP 411 if no body is provided.", "content": { "application/json": { "schema": { "type": "object", "properties": {} } } } } } }, "/api/v1/approvals/{assetType}/{assetId}/stages/{stageId}/unlock": { "put": { "tags": [ "Stages" ], "summary": "Unlock a stage", "description": "Unlocks the specified stage, making it editable again. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "unlockStage", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } }, "requestBody": { "required": true, "description": "Send an empty JSON object. The service returns HTTP 411 if no body is provided.", "content": { "application/json": { "schema": { "type": "object", "properties": {} } } } } } }, "/api/v1/approvals/{assetType}/{assetId}/decisions": { "post": { "tags": [ "Decisions" ], "summary": "Make decisions", "description": "Makes a decision on one or more stages. If the decision already exists it will be updated. Overall stage and approval status is recalculated after each decision. Throws an error if the approval is not found or the current user is not a participant.", "operationId": "makeDecisions", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "decision": { "type": "string", "description": "The decision value (e.g. `approved`, `needs work`, `approved with changes`, `reviewed`)", "enum": [ "approved", "needs work", "approved with changes", "reviewed" ] }, "stageIds": { "type": "array", "items": { "type": "string" }, "description": "Stage IDs to apply the decision to. Defaults to all active stages if omitted." } } } } } }, "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "delete": { "tags": [ "Decisions" ], "summary": "Delete decisions", "description": "Removes the current user's decision(s) from all active stages. The approval must be active.", "operationId": "deleteDecisions", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/decisions/stage/{stageId}": { "post": { "tags": [ "Decisions" ], "summary": "Make decision on a stage", "description": "Makes a decision on a specific stage. Equivalent to `POST /decisions` with a single stage ID.", "operationId": "makeDecisionOnStage", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "decision": { "type": "string", "description": "The decision value", "enum": [ "approved", "needs work", "approved with changes", "reviewed" ] } } } } } }, "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "delete": { "tags": [ "Decisions" ], "summary": "Delete decision on a stage", "description": "Removes the current user's decision from the specified stage.", "operationId": "deleteDecisionOnStage", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/getSuggestedParticipants": { "get": { "tags": [ "Participants" ], "summary": "Get suggested participants", "description": "Returns participant suggestions derived from the previous document version's approval.", "operationId": "getSuggestedParticipants", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "participantSuggestions": { "type": "array", "items": { "type": "object", "properties": { "participantId": { "type": "string" }, "participantType": { "type": "string" }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Role this participant plays on the stage.\n\n- `approver` \u2014 Has a binding vote; their decision directly affects stage and approval status.\n- `reviewer` \u2014 Non-binding; can mark reviewed but does not block approval progression.\n\nThe role, combined with the participant's current decision, also drives the `userInfo.action` value on every approval response \u2014 see [`Approval.userInfo.action`](#section/Schemas/Approval) for the role/decision \u2192 action mapping." } } } }, "prevVersionWithApprovers": { "type": "string", "description": "The prior document version that had approvers" } } } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/participants": { "post": { "tags": [ "Participants" ], "summary": "Add participants", "description": "Adds one or more participants to an approval. If the approval does not yet exist, one will be created. If a participant already exists they will be merged and updated. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "addParticipants", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ParticipantBody" } } } } }, "responses": { "200": { "$ref": "#/components/responses/ApprovalResponse" }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/participants/{participantType}/{participantId}": { "delete": { "tags": [ "Participants" ], "summary": "Delete participant", "description": "Removes a participant from the approval. If all participants are removed, the stage and approval are also deleted. The asset must be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "deleteParticipant", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/ParticipantType" }, { "$ref": "#/components/parameters/ParticipantId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK. Returns the updated approval when participants remain. When removing this participant empties the approval, the approval is deleted and the response is an `ApprovalDeletedResponse` envelope with `deleted: true` instead of the full approval payload.", "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/Approval" }, { "$ref": "#/components/schemas/ApprovalDeletedResponse" } ] } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/{assetType}/{assetId}/participants/{participantId}/remind": { "post": { "tags": [ "Participants" ], "summary": "Remind participant", "description": "Sends a reminder notification to the specified participant. The approval must exist and be in an editable state. Check `userInfo.isEditable` on the approval response to determine whether the requesting user can perform write operations.", "operationId": "remindParticipant", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/ParticipantId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "participantId" ], "properties": { "participantId": { "type": "string", "description": "ID of the participant to remind. Must match the `participantId` in the URL path." }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ], "description": "Optional. Type of the participant being reminded.\n\n- `USER` \u2014 Individual Workfront user (or AI bot user).\n- `TEAMOB` \u2014 Workfront team." }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Optional. Role of the participant being reminded.\n\n- `approver` \u2014 Has a binding vote.\n- `reviewer` \u2014 Non-binding." } } } } } } } }, "/api/v1/approvals/{assetType}/{assetId}/participants/remindUndecided": { "post": { "tags": [ "Participants" ], "summary": "Remind all undecided participants", "description": "Sends reminder notifications to all participants across all stages who have not yet made a decision.", "operationId": "remindUndecidedParticipants", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": {} } } }, "description": "Send an empty JSON object at minimum. The service returns HTTP 411 if no body is provided." } } }, "/api/v1/approvals/{assetType}/{assetId}/stages/{stageId}/participants/{participantId}/remind": { "post": { "tags": [ "Participants" ], "summary": "Remind participant on a stage", "description": "Sends a reminder notification to a specific participant within a specific stage.", "operationId": "remindMultiStageParticipant", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/ParticipantId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "participantId": { "type": "string", "description": "ID of the participant to remind. Must match the `participantId` in the URL path." }, "participantType": { "type": "string", "enum": [ "USER", "TEAMOB" ], "description": "Optional. Type of the participant being reminded.\n\n- `USER` \u2014 Individual Workfront user (or AI bot user).\n- `TEAMOB` \u2014 Workfront team." }, "participantRole": { "type": "string", "enum": [ "approver", "reviewer" ], "description": "Optional. Role of the participant being reminded.\n\n- `approver` \u2014 Has a binding vote.\n- `reviewer` \u2014 Non-binding." } } } } } } } }, "/api/v1/approvals/{assetType}/{assetId}/stages/{stageId}/participants/remindUndecided": { "post": { "tags": [ "Participants" ], "summary": "Remind undecided participants on a stage", "description": "Sends reminder notifications to all undecided participants within a specific stage.", "operationId": "remindMultiStageUndecidedParticipants", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/AssetId" }, { "$ref": "#/components/parameters/StageId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Approval" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } }, "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": {} } } }, "description": "Send an empty JSON object at minimum. The service returns HTTP 411 if no body is provided." } } }, "/api/v1/templates": { "get": { "tags": [ "Templates" ], "summary": "List templates", "description": "Returns all approval templates visible to the current user.", "operationId": "getTemplates", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "templates": { "type": "array", "items": { "$ref": "#/components/schemas/Template" } } }, "required": [ "templates" ] } } } }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "post": { "tags": [ "Templates" ], "summary": "Create template", "description": "Creates an approval template. A customer can create a maximum of 1000 templates. Requires template management permissions.", "operationId": "createTemplate", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplateBody" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Template" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/templates/{templateId}": { "get": { "tags": [ "Templates" ], "summary": "Get template", "description": "Returns a single approval template by ID.\n\n> **Known issue:** When the template ID does not exist, the service currently returns HTTP 500 instead of 404.", "operationId": "getTemplate", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/TemplateId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Template" } } } }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "put": { "tags": [ "Templates" ], "summary": "Update template", "description": "Partially updates an approval template. Requires template management permissions.", "operationId": "putTemplate", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/TemplateId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplateBody" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Template" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "patch": { "tags": [ "Templates" ], "summary": "Update template", "description": "Partially updates an approval template. Requires template management permissions.", "operationId": "patchTemplate", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/TemplateId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TemplateBody" } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Template" } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } }, "delete": { "tags": [ "Templates" ], "summary": "Delete template", "description": "Deletes a single approval template. Requires template management permissions.", "operationId": "deleteTemplate", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/TemplateId" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "204": { "description": "Template deleted. No content." }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "404": { "$ref": "#/components/responses/NotFoundResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/templates/bulkDelete/{ids}": { "delete": { "tags": [ "Templates" ], "summary": "Bulk delete templates", "description": "Deletes multiple approval templates in one call. IDs are comma-separated in the path. Requires template management permissions.\n\n> **Known issue:** When none of the supplied IDs exist, the service currently returns HTTP 500 instead of `200 {\"acknowledged\":true,\"deletedCount\":0}`.", "operationId": "bulkDeleteTemplates", "security": [ { "Bearer": [] } ], "parameters": [ { "name": "ids", "in": "path", "required": true, "description": "Comma-separated list of template IDs to delete", "schema": { "type": "string", "example": "templateId1,templateId2,templateId3" } }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "acknowledged": { "type": "boolean", "description": "Whether MongoDB acknowledged the bulk-delete operation." }, "deletedCount": { "type": "integer", "description": "Number of templates actually deleted." } }, "example": { "acknowledged": true, "deletedCount": 2 } } } } }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/bots": { "get": { "tags": [ "Bots" ], "summary": "List bot reviewers", "description": "Returns a paginated list of Workfront bot users that are eligible to be added as reviewer participants on an approval. A bot reviewer is invoked automatically when its assigned stage becomes active.", "operationId": "getBots", "security": [ { "Bearer": [] } ], "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } }, { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 } }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "required": [ "metadata", "results" ], "properties": { "metadata": { "type": "object", "properties": { "totalItems": { "type": "integer" }, "currentPage": { "type": "integer" }, "totalPages": { "type": "integer" }, "pageSize": { "type": "integer" } } }, "results": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "id": { "type": "string", "description": "The unique identifier for the bot" }, "name": { "type": "string", "description": "The name the creator gave to the bot" }, "description": { "type": "string", "description": "The description of what the bot does or is used for" }, "type": { "type": "string", "enum": [ "doc-brand-reviewer" ] }, "isActive": { "type": "boolean", "description": "Whether the bot has been enabled" }, "brandId": { "type": "string", "description": "The ID of the brand the bot is associated with" }, "creatorId": { "type": "string", "description": "The ID of the user who created the bot" }, "customerId": { "type": "string", "description": "The ID of the Workfront customer the bot is associated with" }, "imsOrgId": { "type": "string", "description": "The IMS organization ID associated with the bot" }, "eauthUserID": { "type": "string", "description": "The IMS user ID associated with the bot" }, "wfUserId": { "type": "string", "description": "The Workfront user ID associated with the bot" } } } } } } } } }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/bot-reviews/search": { "post": { "tags": [ "Bot Reviews" ], "summary": "Search AI brand reviews", "description": "Returns AI brand-review results produced for a document version under an approval. Each review is generated when a bot reviewer participant runs against a stage on the approval and captures the bot\u2019s pass/fail findings against the brand\u2019s guidelines. Filter results by bot, document version, parent document, or stage to narrow the response to a specific asset, review run, or stage on its approval.", "operationId": "searchBotReviews", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "botEauthUserId": { "type": "string", "description": "The Workfront eauthUserID of the bot. Maps to associatedTechnicalAccountId on the bot record." }, "parentObjType": { "type": "string", "enum": [ "DOCU" ], "description": "Type of the parent object." }, "parentObjId": { "type": "string", "description": "ID of the parent object (the document)." }, "objType": { "type": "string", "enum": [ "DOCV" ], "description": "Type of the object being reviewed." }, "objId": { "type": "string", "description": "ID of the object being reviewed (the document version)." }, "stageId": { "type": "string", "description": "ID of the stage on the approval." }, "page": { "type": "integer", "default": 1 }, "limit": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 } } } } } }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "required": [ "reviews" ], "properties": { "reviews": { "type": "array", "items": { "$ref": "#/components/schemas/BotReview" } } } } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" } } } }, "/api/v1/approvals/search/{assetType}": { "post": { "tags": [ "Approvals" ], "summary": "Bulk lookup approvals by asset ID", "description": "Simple bulk lookup of approvals for a known list of asset IDs within a specific asset type. Provide the asset type in the path and an array of `assetIds` in the body to retrieve their approvals in a single call. If no body is supplied, the endpoint returns approvals for projects owned by the requesting user that are currently in review.", "operationId": "bulkLookupApprovalsByAssetType", "security": [ { "Bearer": [] } ], "parameters": [ { "$ref": "#/components/parameters/AssetType" }, { "$ref": "#/components/parameters/XApiKey" }, { "$ref": "#/components/parameters/XGwSubdomain" }, { "$ref": "#/components/parameters/WfCustomerId" }, { "$ref": "#/components/parameters/WfUserId" }, { "$ref": "#/components/parameters/WfLane" }, { "$ref": "#/components/parameters/XRequestId" }, { "$ref": "#/components/parameters/XCorrelationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "assetIds": { "type": "array", "items": { "type": "string" }, "description": "Asset IDs to look up approvals for." }, "assetType": { "type": "string", "description": "Optional. Asset type in the body. The path-level `assetType` is authoritative.", "enum": [ "DOCV" ] } } } } }, "description": "Send an empty JSON object at minimum. The service returns HTTP 411 if no body is provided." }, "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "approvals": { "type": "array", "items": { "$ref": "#/components/schemas/Approval" } } } } } } }, "400": { "$ref": "#/components/responses/BadRequestResponse" }, "401": { "$ref": "#/components/responses/UnauthorizedResponse" }, "500": { "$ref": "#/components/responses/InternalServerErrorResponse" }, "411": { "$ref": "#/components/responses/LengthRequiredResponse" } } } } } }