openapi: 3.2.0 info: title: Vaquill Ai Playbooks API version: 1.0.0 description: 'Operations tagged Playbooks across 2 of this provider''s published API definitions: vaquill-ai-workspace-openapi.json, vaquill-ai-workspace-openapi.yml. Each path carries the servers of the definition it was published in.' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) security: - WorkspaceAuth: [] tags: - name: Playbooks description: The organization's negotiating positions, per contract type, and the starter templates to build them from. A playbook is the input a contract review is measured against. paths: /v1/playbooks: get: tags: - Playbooks summary: List playbooks description: 'Every playbook this organization owns, one page at a time. Organization-visible only. Personal playbooks authored in the web app against no organization are deliberately invisible here, because a machine credential has no person behind it.' operationId: playbooks.list parameters: - name: limit in: query required: false schema: type: integer maximum: 200 minimum: 1 description: How many rows to return, 1 to 200. Defaults to 50. default: 50 title: Limit description: How many rows to return, 1 to 200. Defaults to 50. - name: offset in: query required: false schema: type: integer minimum: 0 description: 'How many rows to skip before returning any. Combine with `limit` to page: `offset=0`, then `offset=50`, and so on. Offsets are positional, not stable, so a set that changes while you page can show a row twice or not at all.' default: 0 title: Offset description: 'How many rows to skip before returning any. Combine with `limit` to page: `offset=0`, then `offset=50`, and so on. Offsets are positional, not stable, so a set that changes while you page can show a row twice or not at all.' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Page_Playbook_' example: data: - id: pbk_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: msa positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true isDefault: false sourceFilename: msa-acme-v3.docx createdAt: '2026-08-19T14:32:10Z' updatedAt: '2026-08-19T14:32:10Z' pagination: limit: 50 offset: 0 total: 128 hasMore: false '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' post: tags: - Playbooks summary: Create a playbook description: 'Author a playbook from positions you supply. `contractType` is fixed at creation and cannot be changed afterwards, since it determines which reviews resolve this playbook; create a second playbook instead. `positions` may be empty, so creating the shell and filling it clause by clause is a supported flow. Playbooks cannot be deleted, because every review that ever ran against one references it.' operationId: playbooks.create requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PlaybookCreateRequest' example: name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: saas positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Playbook' example: id: pbk_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: msa positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true isDefault: false sourceFilename: msa-acme-v3.docx createdAt: '2026-08-19T14:32:10Z' updatedAt: '2026-08-19T14:32:10Z' '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) /v1/playbooks/from-template: post: tags: - Playbooks summary: Create a playbook from a starter template description: 'Adopt a starter template as an organization playbook. The result is an ordinary playbook, owned and editable. Nothing links it back to the template afterwards, because a live link would imply an update path that does not exist.' operationId: playbooks.fromTemplate requestBody: content: application/json: schema: $ref: '#/components/schemas/PlaybookFromTemplateRequest' example: templateSlug: msa-buyer-side name: Acme Corporation description: Master services agreement with Acme for the 2026 platform rollout. jurisdiction: US required: true responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Playbook' example: id: pbk_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: msa positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true isDefault: false sourceFilename: msa-acme-v3.docx createdAt: '2026-08-19T14:32:10Z' updatedAt: '2026-08-19T14:32:10Z' '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) /v1/playbooks/{playbookId}: get: tags: - Playbooks summary: Get a playbook description: 'One playbook, with every position it holds. Positions are returned in full rather than summarized, because a playbook is the input a review is measured against and a caller that cannot read the positions cannot tell what its reviews mean.' operationId: playbooks.get parameters: - name: playbookId in: path required: true schema: type: string title: Playbookid description: '`pbk_` identifier of the playbook. Take it from `GET /v1/playbooks`. A starter template is addressed by its `slug` instead, not by this.' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Playbook' example: id: pbk_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: msa positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true isDefault: false sourceFilename: msa-acme-v3.docx createdAt: '2026-08-19T14:32:10Z' updatedAt: '2026-08-19T14:32:10Z' '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '404': description: The resource does not exist, is not this organization's, or is outside this installation's matter allowlist. The three are deliberately indistinguishable, so the status code cannot be used to discover which ids exist in another organization. Each resource has its own `type`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' put: tags: - Playbooks summary: Replace a playbook description: 'Replace a playbook''s name, description and positions. A clause type absent from `positions` is removed. Within a clause type that is present, the authoring fields this API does not publish are preserved, so a write through the API cannot delete work done in the product.' operationId: playbooks.update parameters: - name: playbookId in: path required: true schema: type: string title: Playbookid description: '`pbk_` identifier of the playbook. Take it from `GET /v1/playbooks`. A starter template is addressed by its `slug` instead, not by this.' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PlaybookUpdateRequest' example: name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Playbook' example: id: pbk_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: msa positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true isDefault: false sourceFilename: msa-acme-v3.docx createdAt: '2026-08-19T14:32:10Z' updatedAt: '2026-08-19T14:32:10Z' '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '404': description: The resource does not exist, is not this organization's, or is outside this installation's matter allowlist. The three are deliberately indistinguishable, so the status code cannot be used to discover which ids exist in another organization. Each resource has its own `type`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) /v1/playbook-templates: get: tags: - Playbooks summary: List starter playbook templates description: 'Our starter templates. Identical for every organization, read-only. `principal` is unused for filtering and is still required: the route is credential-gated like every other, and taking the principal is what makes that visible at the handler rather than only in the policy.' operationId: playbookTemplates.list parameters: - name: limit in: query required: false schema: type: integer maximum: 200 minimum: 1 description: How many rows to return, 1 to 200. Defaults to 50. default: 50 title: Limit description: How many rows to return, 1 to 200. Defaults to 50. - name: offset in: query required: false schema: type: integer minimum: 0 description: 'How many rows to skip before returning any. Combine with `limit` to page: `offset=0`, then `offset=50`, and so on. Offsets are positional, not stable, so a set that changes while you page can show a row twice or not at all.' default: 0 title: Offset description: 'How many rows to skip before returning any. Combine with `limit` to page: `offset=0`, then `offset=50`, and so on. Offsets are positional, not stable, so a set that changes while you page can show a row twice or not at all.' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Page_PlaybookTemplate_' example: data: - slug: msa-buyer-side name: MSA, buyer side description: Master services agreement with Acme for the 2026 platform rollout. contractType: msa category: commercial userSide: buyer featured: false positionCount: 18 tags: - saas - buyer-side recommendedFor: - Vendor agreements where you are the customer pagination: limit: 50 offset: 0 total: 128 hasMore: false '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) /v1/playbook-extractions: post: tags: - Playbooks summary: Extract starter positions from a contract description: 'Read starter positions out of one of your own signed contracts. Answers `202` with an operation. Poll it, then read the extraction for the positions it found. **Nothing is saved.** The result comes back for you to review, and `playbooks.create` is the separate call that adopts it: an extraction is a model''s reading of a contract, and persisting a misclassified one as the positions your automated reviews run against is a mistake nobody would see until a review cited it. The published position shape is exactly the one `playbooks.create` accepts, so adopting is a copy rather than a translation. Send either a `documentId` you uploaded or `contractText` you already hold, never both. `useTrackedChanges` reads a `.docx`''s Word revision marks and extracts what a reviewer pushed FROM and TO, rather than the final positions.' operationId: playbookExtractions.create parameters: - name: Idempotency-Key in: header required: false schema: anyOf: - type: string - type: 'null' title: Idempotency-Key description: A unique value of your choosing, so a retried launch returns the FIRST operation instead of starting a second billable job. Reusing one with a different body is refused. Retrying with the same key and the same body is free and is the intended way to recover from a timeout. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PlaybookExtractionCreateRequest' example: documentId: doc_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 contractType: msa useTrackedChanges: false responses: '202': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Operation' example: id: op_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 type: matrix.run status: succeeded createdAt: '2026-08-19T14:32:10Z' completedAt: '2026-08-19T14:32:10Z' matterId: mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 resource: kind: matrix id: mtx_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 url: https://storage.vaquill.ai/exports/msa-acme-v3-redline.docx?signature=... progress: done: 24 total: 128 unit: cells requestId: req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) /v1/playbook-extractions/{extractionId}: get: tags: - Playbooks summary: Get a playbook extraction description: 'One extraction, and the positions it found. A running extraction is a `200` with an empty `positions` map and a truthful `status`, never a `404`. Check `truncated` before adopting: a contract over the extractor''s ceiling produces positions that are correct and not complete.' operationId: playbookExtractions.get parameters: - name: extractionId in: path required: true schema: type: string title: Extractionid description: '`pex_` identifier of the playbook extraction. Returned on the operation that launched it. It names the extraction JOB, which is what exists from the moment the work is accepted.' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/PlaybookExtraction' example: id: pex_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 status: queued contractType: msa positions: limitation_of_liability: standardPosition: Liability is capped at the fees paid in the preceding twelve months. acceptableRange: Between one and two times the fees paid in the preceding twelve months. escalationTriggers: - value fallbackLadder: - value dealBreaker: value priority: must_have approvalLevel: none escalationConditions: - attribute: clause_severity operator: eq value: '1000000' escalateTo: manager note: 'Escalated to GC: deal value over $1M.' rationale: Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: 4 enabled: true truncated: false sourceDocumentId: doc_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 createdAt: '2026-08-19T14:32:10Z' completedAt: '2026-08-19T14:32:10Z' '422': description: The request does not match the published schema. `errors` names each rejected field and why. The submitted value is never echoed back. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' '401': description: The credential is missing, malformed, unknown, revoked or expired. `type` is `invalid-credential`, or `wrong-product-credential` when a `vq_key_` Data API key was sent to this API. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '403': description: The credential does not carry a scope this operation requires (`insufficient-scope`), or the organization's installation is suspended (`installation-inactive`). headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 WWW-Authenticate: description: RFC 9110 authentication challenge. schema: type: string content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '404': description: The resource does not exist, is not this organization's, or is outside this installation's matter allowlist. The three are deliberately indistinguishable, so the status code cannot be used to discover which ids exist in another organization. Each resource has its own `type`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '429': description: Too many requests for this credential's tier. Honour `Retry-After`. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 Retry-After: description: Seconds to wait before retrying. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '500': description: An unexpected error on our side. The body carries a stable `type` and the request id and nothing else; the cause is in our logs. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '503': description: A dependency this request needs is unavailable, so nothing was done. Retryable. Authentication fails closed rather than admitting the request, so this is never a statement about your credential. headers: X-Request-ID: description: The id of this request. The same value appears as `requestId` in the body. Quote it when contacting support. schema: type: string examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 content: application/problem+json: schema: $ref: '#/components/schemas/Problem' servers: - url: https://api.vaquill.ai/workspace description: Vaquill Legal Workspace API (production) - url: /workspace description: Vaquill Legal Workspace API (relative to the mount) components: schemas: PlaybookTemplate: properties: slug: type: string title: Slug description: Stable identifier for this template. Pass it as `templateSlug` to adopt the template. examples: - msa-buyer-side name: type: string title: Name description: The template's display name. examples: - MSA, buyer side description: type: string title: Description description: What this template is for and when to pick it. examples: - Master services agreement with Acme for the 2026 platform rollout. contractType: type: string title: Contracttype description: Which contract type the template governs. examples: - msa category: type: string title: Category description: 'Broad grouping for the gallery: `commercial`, `privacy`, `hr`, `ip` or `nda`.' examples: - commercial userSide: anyOf: - type: string - type: 'null' title: Userside description: Which side of the paper this template argues for. Most templates come in a pair, and adopting the wrong one produces reviews that negotiate against your own client. examples: - buyer featured: type: boolean title: Featured description: True for the templates we surface first in the gallery. default: false examples: - false positionCount: type: integer title: Positioncount description: 'How many clause positions the template holds. The positions themselves are not listed here: adopt the template and read the playbook.' default: 0 examples: - 18 tags: items: type: string type: array title: Tags description: Free-text labels for filtering the gallery. examples: - - saas - buyer-side recommendedFor: items: type: string type: array title: Recommendedfor description: Situations this template suits, in plain language. examples: - - Vendor agreements where you are the customer additionalProperties: false type: object required: - slug - name - description - contractType - category title: PlaybookTemplate description: 'A starter template. Ours, read-only, identical for every organization. `positionCount` rather than the positions themselves: the materialized positions of one template run to tens of kilobytes, and a list of twenty eight would be a megabyte of response for a gallery. A caller that wants the content adopts the template and reads the playbook.' PlaybookExtractionCreateRequest: properties: documentId: anyOf: - type: string - type: 'null' title: Documentid description: '`doc_` identifier of a document in this organization to read. Mutually exclusive with `contractText`.' examples: - doc_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 contractText: anyOf: - type: string maxLength: 400000 - type: 'null' title: Contracttext description: The contract as plain text. Mutually exclusive with `documentId`. Use it when you already hold the text and do not need the file kept. examples: - 'MASTER SERVICES AGREEMENT This Master Services Agreement is entered into as of 19 August 2026 between Acme Corporation, a Delaware corporation, and the Supplier identified on the signature page. 8. LIMITATION OF LIABILITY. Supplier''s total liability arising out of this Agreement shall not exceed the fees paid in the preceding twelve months, except for breach of confidentiality and indemnification for third-party intellectual property claims, which are uncapped. 9. INDEMNIFICATION. Supplier shall defend and indemnify Acme Corporation against any third-party claim that the services infringe a United States patent, copyright or trade secret. 11. TERM AND TERMINATION. The initial term is two years, renewing for successive one-year terms unless either party gives ninety days written notice. Acme Corporation may terminate for convenience on thirty days notice. 12. GOVERNING LAW. This Agreement is governed by the laws of the State of Delaware, without regard to its conflict of laws rules.' contractType: anyOf: - type: string maxLength: 64 - type: 'null' title: Contracttype description: 'Pin the contract type instead of detecting it. Omit to have it detected from the opening of the document, which costs nothing extra: it runs concurrently with the extraction.' examples: - msa useTrackedChanges: type: boolean title: Usetrackedchanges description: 'Read the file''s Word revision marks and extract what a reviewer pushed FROM and TO, rather than the final-state positions. Requires a `documentId` whose filename ends in `.docx`: revision marks exist only in a DOCX.' default: false examples: - false additionalProperties: false type: object title: PlaybookExtractionCreateRequest description: 'The contract to read positions out of. Exactly one source. `documentId` or `contractText`, never both and never neither. Text is accepted for the same reason `reviews.create` accepts it: the caller usually has the contract in hand, and requiring an upload first would make the cheapest integration a four-call dance. A `documentId` is the better choice when the file is a DOCX whose structure matters, and it is REQUIRED for tracked-changes extraction.' PlaybookFromTemplateRequest: properties: templateSlug: type: string maxLength: 120 title: Templateslug description: '`slug` of the starter template to adopt, from `GET /v1/playbook-templates`.' examples: - msa-buyer-side name: anyOf: - type: string maxLength: 200 minLength: 1 - type: 'null' title: Name description: Name for the new playbook. Omit to take the template's own name. examples: - Acme Corporation description: anyOf: - type: string maxLength: 1000 - type: 'null' title: Description description: Description for the new playbook. Omit to take the template's own. examples: - Master services agreement with Acme for the 2026 platform rollout. jurisdiction: anyOf: - type: string pattern: ^([A-Z]{2}|INTL)$ - type: 'null' title: Jurisdiction description: Two-letter uppercase jurisdiction code, or `INTL`. Selects which default positions the template resolves. examples: - US additionalProperties: false type: object required: - templateSlug title: PlaybookFromTemplateRequest description: 'Adopt one of our starter templates as an organization playbook. The result is an ordinary playbook, owned by the organization and editable. Nothing links it back to the template afterwards: a template is a starting point, and a live link would imply an update path that does not exist.' ContractType: type: string enum: - saas - professional_services - msa - sow - consulting - license - sale - partnership - procurement - vendor_agreement - reseller_distribution - supply - lease - loan - eula - terms_of_service - baa - order_form - nda - dpa - ip_assignment - employment - executive_employment - independent_contractor - offer_letter - severance_agreement - non_compete - asset_purchase - stock_purchase - merger_agreement - shareholders_agreement - operating_agreement - safe - term_sheet - settlement_agreement - engagement_letter - protective_order - joint_defense - other title: ContractType description: 'Contract types a playbook can encode negotiation positions for. A playbook is a set of clause-level negotiation positions, so this list covers contracts you negotiate clause-by-clause. Documents you only *generate* (litigation pleadings, notices) live in `DraftCategory` (`app/models/drafting_schemas.py`), NOT here. Each value backs a `legal_playbooks.contract_type` row, so adding one requires a DB migration to extend the CHECK constraint (see `20260502160000_expand_playbook_contract_type_dpa_vendor_ip.sql`, `20260612130000_expand_playbook_contract_type_msa_sale_sow_consulting.sql`, and `20260702120000_expand_playbook_contract_type_gc_litigation.sql`). Kept in sync with the FE `ContractType` union + `CONTRACT_TYPE_LABELS` (`frontend/src/types/legal-tools.ts`); the drift-guard in `app/tests/unit/test_contract_type_taxonomy.py` asserts all three layers both ways and fails fast if they diverge.' Problem: type: object title: Problem description: An RFC 9457 problem document. Branch on `type`, which is stable; `title` and `detail` are written for people and may be reworded. Some problems carry extra members (`requiredScopes`, `limit`, `expectedVersion`), which is why this object is open. required: - type - title - status - detail - instance properties: type: type: string format: uri description: The stable identifier for this error, and the one field to branch on. Resolves to a page describing it. examples: - https://vaquill.ai/docs/workspace-api/errors/insufficient-scope title: type: string description: A short human-readable summary. examples: - Insufficient scope status: type: integer description: The HTTP status code, repeated. examples: - 403 detail: type: string description: What went wrong on this specific request. May be reworded at any time. examples: - This credential carries matters:read. This operation needs matters:write. instance: type: string description: The path this problem occurred on. examples: - /workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 requestId: type: string description: The id of this request, identical to the `X-Request-ID` response header. Quote it when contacting support. examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 additionalProperties: true Page_PlaybookTemplate_: properties: data: items: $ref: '#/components/schemas/PlaybookTemplate' type: array title: Data description: The rows in this window, in the collection's default order. pagination: $ref: '#/components/schemas/Pagination' description: Where this window sits in the full result set. additionalProperties: false type: object required: - data - pagination title: Page[PlaybookTemplate] OperationProgress: properties: done: type: integer minimum: 0.0 title: Done description: How many units are finished. examples: - 24 total: type: integer minimum: 0.0 title: Total description: How many units there are in total. Can legitimately be zero for an empty run. examples: - 128 unit: type: string enum: - cells - steps - documents - files - rows - percent title: Unit description: 'What `done` and `total` are counting. Always read it: a workflow run counts `percent` while a matrix run counts `cells`, so `{done: 43, total: 100}` alone is ambiguous.' examples: - cells additionalProperties: false type: object required: - done - total - unit title: OperationProgress description: 'How far along, and in what units. The unit is not decoration. A workflow run stores only a percentage while a matrix run stores cell counts, so `{done: 43, total: 100}` with no unit reads as 43 of 100 documents and a client builds a wrong estimate from it.' OperationResource: properties: kind: type: string title: Kind description: What sort of thing was produced, for example `matrix` or `document`. examples: - matrix id: type: string title: Id description: Public identifier of the produced resource, carrying its own type prefix, for example `mtx_` for a matrix. examples: - mtx_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 url: anyOf: - type: string - type: 'null' title: Url description: Path on this API where the resource can be read, RELATIVE to the API root and never absolute. Absent when the resource has no addressable path, which happens for work started outside a matter. Absent means the id is real and there is nowhere to GET it; it is not an error. examples: - https://storage.vaquill.ai/exports/msa-acme-v3-redline.docx?signature=... additionalProperties: false type: object required: - kind - id title: OperationResource description: 'What the operation produced, or is producing. `url` is a path on this API rather than an absolute URL, because the service is mounted today and gets its own hostname later (docs 07.5). A relative path survives that move; a baked-in host does not.' Page_Playbook_: properties: data: items: $ref: '#/components/schemas/Playbook' type: array title: Data description: The rows in this window, in the collection's default order. pagination: $ref: '#/components/schemas/Pagination' description: Where this window sits in the full result set. additionalProperties: false type: object required: - data - pagination title: Page[Playbook] PlaybookCreateRequest: properties: name: type: string maxLength: 200 minLength: 1 title: Name description: Display name for the playbook. Trimmed; whitespace alone is refused. examples: - MSA, buyer side description: anyOf: - type: string maxLength: 1000 - type: 'null' title: Description description: Free-text description of what this playbook covers. examples: - Master services agreement with Acme for the 2026 platform rollout. contractType: $ref: '#/components/schemas/ContractType' description: Which contract type this playbook governs. Cannot be changed afterwards, because it determines which reviews resolve the playbook. examples: - saas positions: additionalProperties: $ref: '#/components/schemas/PlaybookPosition' propertyNames: maxLength: 80 minLength: 1 type: object maxProperties: 200 title: Positions description: 'Negotiating positions keyed by clause-type slug. May be empty: creating the shell and filling it clause by clause is a supported flow.' additionalProperties: false type: object required: - name - contractType title: PlaybookCreateRequest description: Author a playbook from positions the caller supplies. PlaybookExtraction: properties: id: type: string title: Id description: Public identifier, `pex_` followed by 32 hex characters. examples: - pex_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 status: $ref: '#/components/schemas/OperationStatus' description: Where the extraction got to, in the same five values an operation uses. `positions` is empty until it reads `succeeded`. examples: - queued contractType: anyOf: - type: string - type: 'null' title: Contracttype description: 'The contract type that was pinned or detected. Pass it to `playbooks.create` when you adopt these positions: a playbook''s type decides which reviews resolve it.' examples: - msa positions: additionalProperties: $ref: '#/components/schemas/PlaybookPosition' type: object title: Positions description: The extracted positions, keyed by clause type. Review them, then send the map you want to keep to `playbooks.create`. Nothing here has been saved as a playbook. truncated: type: boolean title: Truncated description: True when the contract exceeded the extractor's block ceiling and some clauses were not read. The positions returned are correct; they are not complete. Split the contract and extract the remainder separately. default: false examples: - false sourceDocumentId: anyOf: - type: string - type: 'null' title: Sourcedocumentid description: '`doc_` identifier of the document this was read from, when one was named. Null for an extraction from `contractText`, which keeps no file.' examples: - doc_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 createdAt: type: string format: date-time title: Createdat description: When the extraction was accepted (RFC 3339). examples: - '2026-08-19T14:32:10Z' completedAt: anyOf: - type: string format: date-time - type: 'null' title: Completedat description: When it reached a terminal status (RFC 3339). examples: - '2026-08-19T14:32:10Z' additionalProperties: false type: object required: - id - status - createdAt title: PlaybookExtraction description: 'What an extraction found, in the shape a playbook takes. A running extraction is a `200` with an EMPTY `positions` map and a truthful status, never a `404`: a 404 would be indistinguishable from an extraction that never existed. Why one FAILED lives on the operation rather than here, so there is exactly one sanitizer for internal error text on this surface.' Operation: properties: id: type: string title: Id description: Public identifier, `op_` followed by 32 hex characters. Poll `GET /v1/operations/{operationId}` with it. examples: - op_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 type: type: string title: Type description: What kind of work this is, for example `matrix.run` or `draft.generate`. examples: - matrix.run status: $ref: '#/components/schemas/OperationStatus' description: 'One of five values: `queued`, `running`, `succeeded`, `failed`, `cancelled`. There is no sixth and there are no synonyms. Stop polling once it is `succeeded`, `failed` or `cancelled`.' examples: - succeeded createdAt: type: string format: date-time title: Createdat description: When the operation was accepted (RFC 3339). examples: - '2026-08-19T14:32:10Z' completedAt: anyOf: - type: string format: date-time - type: 'null' title: Completedat description: When the operation reached a terminal status (RFC 3339). Present if and only if the status is terminal. examples: - '2026-08-19T14:32:10Z' matterId: anyOf: - type: string - type: 'null' title: Matterid description: '`mat_` identifier of the matter this work belongs to, when it belongs to one.' examples: - mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 resource: anyOf: - $ref: '#/components/schemas/OperationResource' - type: 'null' description: What the operation produced. Absent until the underlying job row exists, which an idempotent replay can briefly observe, so treat absence as 'not yet' rather than 'never'. error: anyOf: - $ref: '#/components/schemas/OperationError' - type: 'null' description: Why the work failed. Present only when `status` is `failed`. Partial success is `succeeded` with `progress.done < progress.total`, never an error. progress: anyOf: - $ref: '#/components/schemas/OperationProgress' - type: 'null' description: How far along the work is, when the underlying job reports it. Absent does not mean no progress. requestId: anyOf: - type: string - type: 'null' title: Requestid description: The `X-Request-ID` of the request that created this operation. Quote it in a support ticket. examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 additionalProperties: false type: object required: - id - type - status - createdAt title: Operation description: 'One long-running operation, whatever kind of work it is. Readable for `OPERATION_RETENTION_DAYS` after creation, per AIP-151.' ValidationProblem: type: object title: ValidationProblem description: A problem document for a schema rejection. `errors` lists the fields that were refused. The value you submitted is deliberately not echoed, so a validation failure cannot copy your content into an error response or into either side's logs. required: - type - title - status - detail - instance - errors properties: type: type: string format: uri description: The stable identifier for this error, and the one field to branch on. Resolves to a page describing it. examples: - https://vaquill.ai/docs/workspace-api/errors/insufficient-scope title: type: string description: A short human-readable summary. examples: - Insufficient scope status: type: integer description: The HTTP status code, repeated. examples: - 403 detail: type: string description: What went wrong on this specific request. May be reworded at any time. examples: - This credential carries matters:read. This operation needs matters:write. instance: type: string description: The path this problem occurred on. examples: - /workspace/v1/matters/mat_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 requestId: type: string description: The id of this request, identical to the `X-Request-ID` response header. Quote it when contacting support. examples: - req_5f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 errors: type: array description: One entry per rejected field. items: type: object required: - location - message - type properties: location: type: string description: Dotted path to the rejected field, for example `body.contentMarkdown`. message: type: string description: Why it was rejected. type: type: string description: The validation rule that failed. additionalProperties: true Playbook: properties: id: type: string title: Id description: Public identifier, `pbk_` followed by 32 hex characters. examples: - pbk_9f2c8b1e4a7d43c9b6e0f1a2c3d4e5f6 name: type: string title: Name description: The playbook's display name. examples: - MSA, buyer side description: anyOf: - type: string - type: 'null' title: Description description: Free-text description of what this playbook covers. examples: - Master services agreement with Acme for the 2026 platform rollout. contractType: type: string title: Contracttype description: 'Which contract type this playbook governs. Fixed at creation: changing it would silently redirect which reviews resolve it.' examples: - msa positions: additionalProperties: $ref: '#/components/schemas/PlaybookPosition' type: object title: Positions description: Every negotiating position the playbook holds, keyed by clause-type slug. Returned in full, because a caller that cannot read the positions cannot tell what its reviews are measured against. isDefault: type: boolean title: Isdefault description: 'True when reviews of this contract type resolve to this playbook if none is named. Read-only here: exactly one default per contract type is enforced by the database, and this API cannot set it.' default: false examples: - false sourceFilename: anyOf: - type: string - type: 'null' title: Sourcefilename description: Filename of the exemplar this playbook was extracted from, when it was imported rather than authored by hand. examples: - msa-acme-v3.docx createdAt: anyOf: - type: string format: date-time - type: 'null' title: Createdat description: When the playbook was created (RFC 3339). examples: - '2026-08-19T14:32:10Z' updatedAt: anyOf: - type: string format: date-time - type: 'null' title: Updatedat description: When the playbook was last modified (RFC 3339). examples: - '2026-08-19T14:32:10Z' additionalProperties: false type: object required: - id - name - contractType title: Playbook description: 'One organization playbook, with every position it holds. Positions are returned in full rather than summarized. A playbook is the input to a review, so a caller that cannot read the positions cannot tell what its reviews are being measured against, and a separate positions endpoint would make the common case two calls.' PlaybookPosition: properties: standardPosition: type: string maxLength: 8000 title: Standardposition description: 'The position the organization opens with on this clause type. Required: a position with no standard is not a position.' examples: - Liability is capped at the fees paid in the preceding twelve months. acceptableRange: type: string maxLength: 4000 title: Acceptablerange description: 'Free-text summary of the acceptable zone. Complements `fallbackLadder` rather than duplicating it: this is the summary, the ladder is the ordered retreat.' examples: - Between one and two times the fees paid in the preceding twelve months. escalationTriggers: items: type: string type: array maxItems: 50 title: Escalationtriggers description: Free-text conditions that should raise a human's attention. Descriptive only; the machine-evaluated rules are `escalationConditions`. examples: - - value fallbackLadder: items: type: string type: array maxItems: 10 title: Fallbackladder description: Ordered concrete retreat positions, BEST acceptable first. The reviewer steps down this ladder when the standard position is rejected. examples: - - value dealBreaker: anyOf: - type: string maxLength: 4000 - type: 'null' title: Dealbreaker description: The walk-away floor. A term at or below this is forced to red regardless of what the model reads. Absent means there is no hard floor, which is not the same as a floor of nothing. examples: - Any uncapped liability for indirect or consequential damages. priority: anyOf: - type: string enum: - must_have - should_have - nice_to_have - type: 'null' title: Priority description: How much this clause matters relative to the others in the playbook. examples: - must_have approvalLevel: anyOf: - type: string enum: - none - manager - partner - gc - type: 'null' title: Approvallevel description: The sign-off a deviation from this position needs. Feeds a review's `approvalGate`, which is REPORTED and never enforced. examples: - none escalationConditions: items: $ref: '#/components/schemas/EscalationCondition' type: array maxItems: 20 title: Escalationconditions description: Machine-evaluated rules that raise the required sign-off when they hold. rationale: anyOf: - type: string maxLength: 2000 - type: 'null' title: Rationale description: Why the organization takes this position. Carried into review findings so a reviewer can see the reasoning. examples: - Our standard position caps liability at fees paid in the preceding 12 months. riskWeight: anyOf: - type: integer maximum: 5.0 minimum: 0.0 - type: 'null' title: Riskweight description: 0 to 5, multiplied by severity to weight the compliance score. Absent falls through to the clause-type default rather than to zero. examples: - 4 enabled: type: boolean title: Enabled description: False keeps the position on the playbook but excludes it from review and drafting. This is how an alternative is parked without being deleted. default: true examples: - true additionalProperties: false type: object required: - standardPosition - acceptableRange title: PlaybookPosition description: 'The organization''s negotiating position on one clause type. Both a request and a response shape, which is a deliberate exception to the "read models are looser than write models" rule the resources follow. A position is authored by the customer rather than produced by a model, so there is no dirty-legacy-value problem to be loose about, and one shape means a caller can read a playbook, edit one field and write it straight back.' OperationStatus: type: string enum: - queued - running - succeeded - failed - cancelled title: OperationStatus description: 'The public five. There is no sixth, and there are no synonyms. Internal vocabularies spell terminal success `completed`, `ready`, `extracted`, `succeeded` and `fresh`; terminal failure `failed` and `error`; queued `pending`, `queued` and `draft`. All of that is collapsed here by `app.workspace_api.adapters.status_map`, which refuses to guess.' Pagination: properties: limit: type: integer title: Limit description: The `limit` that was applied to this request. examples: - 50 offset: type: integer title: Offset description: The `offset` that was applied to this request. examples: - 0 total: type: integer title: Total description: Total rows matching the filter, not the number returned in `data`. Use it to size a job before running it. examples: - 128 hasMore: type: boolean title: Hasmore description: True when rows remain beyond this window. Derived from `offset + len(data) < total`, so a full final page correctly reports `false` rather than sending you after an empty page. examples: - false additionalProperties: false type: object required: - limit - offset - total - hasMore title: Pagination description: 'Where the caller is, and whether there is more. `total` is the count of rows matching the filter, not the count returned, so a caller can size a job before running it.' PlaybookUpdateRequest: properties: name: type: string maxLength: 200 minLength: 1 title: Name description: 'Replacement display name. Required: this is a PUT, not a patch.' examples: - MSA, buyer side description: anyOf: - type: string maxLength: 1000 - type: 'null' title: Description description: Replacement description, or null to clear it. examples: - Master services agreement with Acme for the 2026 platform rollout. positions: additionalProperties: $ref: '#/components/schemas/PlaybookPosition' propertyNames: maxLength: 80 minLength: 1 type: object maxProperties: 200 title: Positions description: 'The COMPLETE set of positions after the write. Replacement happens at the map level: a clause type you omit is removed from the playbook. Within a clause type you do send, unpublished authoring fields set in the web app are preserved.' additionalProperties: false type: object required: - name title: PlaybookUpdateRequest description: 'Replace a playbook''s name, description and positions. A PUT, and it replaces at the MAP level: a clause type absent from `positions` is removed from the playbook. Within a clause type that IS present, the five unpublished authoring fields are preserved (see `playbook_positions.PRESERVED_ON_WRITE`), because the alternative is deleting a lawyer''s work with no error and no way to notice. `contractType` is absent on purpose, and so is `isDefault`. Both are explained in the module docstring.' EscalationCondition: properties: attribute: type: string enum: - clause_severity - counterparty_paper - contract_value - governing_law title: Attribute description: What to test. `clause_severity` is the review's own finding and needs no input; the other three come from the review request's `paperSide` and `dealContext`. A rule naming one you did not supply simply does not fire. examples: - clause_severity operator: type: string enum: - eq - neq - gt - gte - lt - lte - in title: Operator description: How to compare `attribute` against `value`. Use `in` with a comma-separated `value`. default: eq examples: - eq value: type: string maxLength: 200 title: Value description: 'What to compare against, always a string and parsed per attribute: `red`, `true`, `1000000`, `CA,NY`.' examples: - '1000000' escalateTo: type: string enum: - manager - partner - gc title: Escalateto description: The sign-off level this rule raises the clause to when it fires. default: partner examples: - manager note: anyOf: - type: string maxLength: 280 - type: 'null' title: Note description: Short explanation of why this escalation exists, shown to whoever reviews the finding. examples: - 'Escalated to GC: deal value over $1M.' additionalProperties: false type: object required: - attribute - value title: EscalationCondition description: 'A rule that RAISES a clause''s required sign-off when it holds. This is what lets a playbook say "partner normally, but GC if the deal is over a million, or if it is on their paper". The value stays a string across every attribute so the stored shape is uniform; it is parsed per attribute when the rule is evaluated.' OperationError: properties: code: type: string title: Code description: Stable, machine-readable failure code. Branch on this, never on `message`. examples: - EXTRACTION_FAILED message: type: string title: Message description: Human-readable explanation, sanitized of internal paths and stack frames. Wording may change; do not parse it. examples: - The upstream extraction did not finish. additionalProperties: false type: object required: - code - message title: OperationError description: 'Why a failed operation failed, in terms a customer can act on. `code` is stable and machine-readable. `message` is sanitized: the internal job tables store stack traces and file paths in their `error_message` columns, and forwarding those verbatim leaks our internals into a customer''s logs.' securitySchemes: WorkspaceAuth: type: http scheme: bearer bearerFormat: vq_ws_* description: 'Workspace credential issued from the automation console at `/automation`. Send it as `Authorization: Bearer vq_ws_...`. This is NOT a Data API key: a `vq_key_` credential is refused here and names the other product in the error.' externalDocs: description: Getting started guide and error reference url: https://vaquill.ai/docs/workspace-api x-refined-from: - vaquill-ai-workspace-openapi.json - vaquill-ai-workspace-openapi.yml