openapi: 3.1.0
info:
  title: OrgX Public API
  version: 1.2.0
  description: |
    Public, machine-readable endpoints for OrgX receipt conformance, workload
    boundary diagnosis, and Content Studio creation flows.

    ## Quick Start
    - Validate a portable receipt with POST /api/v1/agent-work-receipts/validate
    - Import a validated receipt with POST /api/v1/agent-work-receipts
    - Diagnose whether a workload needs OrgX with POST /api/v1/doctor/workload
    - Estimate Content Studio work with POST /api/v1/studio/estimate

    ## Authentication
    - Receipt validation and workload diagnosis are public and do not persist submissions
    - Receipt import requires an OrgX bearer or session credential plus workspace ownership
    - Estimate and Showcase endpoints are public
    - Checkout endpoint requires authentication (redirects anonymous users to sign up)
    - Webhook endpoint is secured with Stripe signature verification
  contact:
    name: OrgX Support
    url: https://useorgx.com/support
    email: support@useorgx.com
  license:
    name: Proprietary
    url: https://useorgx.com/terms

servers:
  - url: https://useorgx.com/api/v1
    description: Production
  - url: http://localhost:3000/api/v1
    description: Development

tags:
  - name: receipt-validation
    description: Account-free Agent Work Receipt schema discovery and conformance
  - name: receipt-import
    description: Authenticated, workspace-scoped import into the hosted receipt ledger
  - name: workload-diagnosis
    description: Account-free evaluation of time, agents, systems, authority, and accountability boundaries
  - name: estimate
    description: Cost estimation for content generation
  - name: showcase
    description: Example content gallery
  - name: checkout
    description: Payment processing

paths:
  /agent-work-receipts:
    post:
      operationId: importAgentWorkReceipt
      summary: Import an Agent Work Receipt into a workspace
      description: |
        Preserves a conforming portable receipt in the authenticated workspace's
        existing execution receipt ledger. Producer-declared verification,
        acceptance, costs, and outcomes remain unverified claims until reviewed
        inside OrgX. Pilot membership is derived only from signed workspace
        enrollment metadata; callers cannot declare a cohort.

        The optional idempotency_key is scoped to the workspace. Retrying the
        same key with the same canonical receipt returns 200 and the existing
        hosted receipt. Reusing it with different content returns 409.
      tags:
        - receipt-import
      security:
        - bearerAuth: []
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReceiptImportRequest'
      responses:
        '201':
          description: Receipt imported into the workspace ledger
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportSuccess'
        '200':
          description: Idempotent retry returned the existing hosted receipt
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportSuccess'
        '400':
          description: Invalid import envelope or missing workspace identifier
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '404':
          description: Workspace is unavailable to the caller
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '409':
          description: Idempotency key is bound to different content, the workspace hard import quota is exhausted, or signed pilot metadata is present but unverifiable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '413':
          description: Import envelope exceeds the 278,528-byte limit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '415':
          description: Content-Type is not application/json
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '422':
          description: Portable receipt does not conform to v0.1 or contains values the hosted PostgreSQL ledger cannot represent
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '429':
          description: Per-user/workspace write rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '500':
          description: Receipt persistence failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'
        '503':
          description: Workspace authorization, ledger database, pilot signing, enrollment lookup, or distributed production rate limiting is unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptImportError'

  /agent-work-receipts/validate:
    get:
      operationId: getAgentWorkReceiptValidator
      summary: Get Agent Work Receipt validation metadata
      description: |
        Returns the current portable receipt schema, version, payload limit, and
        validation endpoint. This endpoint requires no account and stores nothing.
      tags:
        - receipt-validation
      responses:
        '200':
          description: Validator metadata and canonical JSON Schema
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptValidatorMetadata'
        '429':
          description: Public validator metadata rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '503':
          description: Distributed production rate limiting is unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
    post:
      operationId: validateAgentWorkReceipt
      summary: Validate an Agent Work Receipt
      description: |
        Performs an account-free conformance check against Agent Work Receipt
        v0.1. The submitted document is not stored. Authenticated import is a
        separate operation and is not exposed by this public endpoint.
      tags:
        - receipt-validation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: 'https://useorgx.com/schemas/agent-work-receipt/v0.1/schema.json'
      responses:
        '200':
          description: Receipt conforms to the current schema
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptValidationSuccess'
        '400':
          description: Request body is not valid JSON
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '413':
          description: Receipt exceeds the 262,144-byte public limit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '415':
          description: Content-Type is not application/json
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '422':
          description: Receipt is valid JSON but does not conform to the schema
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptValidationFailure'
        '429':
          description: Public validation rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '503':
          description: Distributed production rate limiting is unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'

  /doctor/workload:
    get:
      operationId: getWorkloadDoctorMetadata
      summary: Get the Workload Doctor request contract and runnable example
      description: |
        Returns account-free discovery metadata, request limits, a bounded
        example payload, and a curl command. It accepts no workload input and
        persists nothing.
      tags:
        - workload-diagnosis
      responses:
        '200':
          description: Workload Doctor request metadata
          content:
            application/json:
              schema:
                type: object
                required:
                  - name
                  - schema_version
                  - endpoint
                  - method
                  - content_type
                  - account_required
                  - accepts_credentials
                  - persists_submissions
                  - max_bytes
                  - request_example
                  - curl_example
                  - browser_handoff
                properties:
                  name:
                    type: string
                    const: OrgX Workload Doctor
                  schema_version:
                    type: string
                    const: workload-diagnosis/0.1
                  endpoint:
                    type: string
                    format: uri
                  method:
                    type: string
                    const: POST
                  content_type:
                    type: string
                    const: application/json
                  account_required:
                    type: boolean
                    const: false
                  accepts_credentials:
                    type: boolean
                    const: false
                  persists_submissions:
                    type: boolean
                    const: false
                  max_bytes:
                    type: integer
                    const: 16384
                  request_example:
                    $ref: '#/components/schemas/WorkloadDiagnosisRequest'
                  curl_example:
                    type: string
                  browser_handoff:
                    type: string
        '429':
          description: Public Workload Doctor metadata rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '503':
          description: Distributed production rate limiting is unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
    post:
      operationId: diagnoseWorkloadBoundaries
      summary: Diagnose whether a workload needs OrgX
      description: |
        Evaluates five boundaries: time, multiple agents, multiple systems,
        authority, and accountability. The request accepts bounded workload
        metadata only, rejects credential-shaped input, persists nothing, and
        returns a non-mutating installation or receipt recommendation.
      tags:
        - workload-diagnosis
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkloadDiagnosisRequest'
      responses:
        '200':
          description: Deterministic workload diagnosis
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkloadDiagnosisResponse'
        '400':
          description: Invalid JSON or workload metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '413':
          description: Request exceeds the 16,384-byte public limit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '415':
          description: Content-Type is not application/json
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '429':
          description: Public diagnosis rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'
        '503':
          description: Secure workload handoff signing or distributed production rate limiting is unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiError'

  /studio/estimate:
    post:
      operationId: createEstimate
      summary: Create a cost estimate
      description: |
        Analyze a content creation prompt and return a detailed cost breakdown.
        Uses Claude Haiku for fast, accurate complexity analysis (~$0.0001/request).

        The estimate includes:
        - Brand ingestion costs (if URL provided)
        - Calibration rounds needed
        - Creative exploration rounds
        - Per-output composition costs
        - Total credits and price in USD

        Estimates expire after 24 hours.
      tags:
        - estimate
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EstimateRequest'
            examples:
              simple:
                summary: Simple carousel request
                value:
                  prompt: 'Create a LinkedIn carousel about 5 AI productivity tips'
                  contentTypes: ['carousel']
                  variantCount: 1
              branded:
                summary: With brand URL
                value:
                  prompt: 'Create an Instagram post announcing our new feature'
                  contentTypes: ['post', 'story']
                  variantCount: 2
                  brandUrl: 'https://example.com'
                  platform: 'instagram'
      responses:
        '200':
          description: Estimate created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EstimateResponse'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'

  /studio/showcase:
    get:
      operationId: getShowcase
      summary: Browse showcase examples
      description: |
        Query featured content examples. Use for inspiration or to show
        users what the system can produce.

        Supports filtering by content type, industry, and style.
        Text search matches against titles, descriptions, and tags.
      tags:
        - showcase
      parameters:
        - name: query
          in: query
          description: Text search query
          schema:
            type: string
            maxLength: 500
        - name: contentType
          in: query
          description: Filter by content type
          schema:
            $ref: '#/components/schemas/ContentType'
        - name: industry
          in: query
          description: Filter by industry
          schema:
            type: string
            enum: [tech, finance, health, retail, education, other]
        - name: style
          in: query
          description: Filter by visual style
          schema:
            type: string
            enum: [minimal, corporate, playful, elegant, bold, artistic]
        - name: featured
          in: query
          description: Show only featured examples
          schema:
            type: boolean
        - name: limit
          in: query
          description: Number of results (1-20)
          schema:
            type: integer
            minimum: 1
            maximum: 20
            default: 6
        - name: offset
          in: query
          description: Pagination offset
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        '200':
          description: Showcase examples
          content:
            application/json:
              schema:
                type: object
                properties:
                  examples:
                    type: array
                    items:
                      $ref: '#/components/schemas/ShowcaseExample'
                  total:
                    type: integer
                  hasMore:
                    type: boolean

  /studio/checkout:
    post:
      operationId: createCheckout
      summary: Create payment session
      description: |
        Create a Stripe checkout session for an estimate.

        **Requires authentication.** If the user is not authenticated,
        returns a 401 with a redirect URL to the sign-up page.
        The estimateId is preserved through the auth flow.

        If the estimate was created anonymously, it will be claimed
        for the authenticated user before checkout.
      tags:
        - checkout
      security:
        - bearerAuth: []
        - cookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - estimateId
              properties:
                estimateId:
                  type: string
                  format: uuid
                  description: ID of the estimate to pay for
      responses:
        '200':
          description: Checkout session created
          content:
            application/json:
              schema:
                type: object
                properties:
                  checkoutUrl:
                    type: string
                    format: uri
                    description: Stripe checkout URL
                  sessionId:
                    type: string
                    description: Stripe session ID
                  amount:
                    type: integer
                    description: Amount in cents
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                type: object
                properties:
                  requiresAuth:
                    type: boolean
                    const: true
                  redirectUrl:
                    type: string
                    format: uri
        '404':
          description: Estimate not found
        '409':
          description: Estimate already paid

  /studio/callback:
    post:
      operationId: stripeWebhook
      summary: Stripe webhook handler
      description: |
        Receives Stripe webhook events for payment processing.
        **Do not call this endpoint directly.**

        Handled events:
        - checkout.session.completed: Marks estimate as paid, queues fulfillment
        - checkout.session.expired: Logs expiration
        - payment_intent.payment_failed: Logs failure for monitoring
      tags:
        - checkout
      security:
        - stripeSignature: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Webhook processed
          content:
            application/json:
              schema:
                type: object
                properties:
                  received:
                    type: boolean
                    const: true

components:
  schemas:
    ReceiptImportRequest:
      type: object
      additionalProperties: false
      required: [workspace_id, receipt]
      properties:
        workspace_id:
          type: string
          format: uuid
          description: Existing OrgX workspace the authenticated caller can access
        receipt:
          $ref: 'https://useorgx.com/schemas/agent-work-receipt/v0.1/schema.json'
        idempotency_key:
          type: string
          minLength: 1
          maxLength: 160
          pattern: '^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$'
          description: |
            Optional workspace-scoped retry key. By default OrgX derives a
            SHA-256 key from the complete canonical receipt, so producer-owned
            receipt IDs cannot collide across runtimes.

    ReceiptImportSuccess:
      type: object
      additionalProperties: false
      required:
        - ok
        - receipt_id
        - external_receipt_id
        - schema_version
        - idempotent
      properties:
        ok:
          type: boolean
          const: true
        receipt_id:
          type: string
          format: uuid
          description: OrgX-hosted receipt identifier
        external_receipt_id:
          type: string
          description: Producer-owned portable receipt identifier
        schema_version:
          type: string
          const: agent-work-receipt/v0.1
        idempotent:
          type: boolean
        imported_at:
          type: string
          format: date-time
        pilot:
          oneOf:
            - type: 'null'
            - type: object
              additionalProperties: false
              required: [cohort_id, partner_ref]
              properties:
                cohort_id:
                  type: string
                partner_ref:
                  type: string

    ReceiptImportError:
      type: object
      properties:
        ok:
          type: boolean
          const: false
        error:
          oneOf:
            - type: string
            - type: object
              required: [code, message]
              properties:
                code:
                  type: string
                message:
                  type: string
                details:
                  type: object
                issues:
                  type: array
                  maxItems: 100
                  items:
                    $ref: '#/components/schemas/ReceiptValidationIssue'
                issue_count:
                  type: integer
                  minimum: 0
                issues_truncated:
                  type: boolean

    ReceiptValidatorMetadata:
      type: object
      required:
        - name
        - schema_version
        - schema_url
        - account_required
        - persists_submissions
        - max_bytes
        - validation_limits
        - validation_endpoint
        - import_endpoint
        - schema
      properties:
        name:
          type: string
          const: Agent Work Receipt
        schema_version:
          type: string
          const: agent-work-receipt/v0.1
        schema_url:
          type: string
          format: uri
        account_required:
          type: boolean
          const: false
        persists_submissions:
          type: boolean
          const: false
        max_bytes:
          type: integer
          const: 262144
        validation_limits:
          type: object
          additionalProperties: false
          description: Bounded traversal runs before JSON Schema evaluation, so a schema-valid document can still fail with input.structure_limit.
          required: [max_depth, max_nodes, max_issues, apply_before_schema]
          properties:
            max_depth:
              type: integer
              const: 64
            max_nodes:
              type: integer
              const: 50000
            max_issues:
              type: integer
              const: 100
            apply_before_schema:
              type: boolean
              const: true
        validation_endpoint:
          type: string
          format: uri
        import_endpoint:
          type: string
          format: uri
          description: Authenticated, workspace-scoped hosted import endpoint
        schema:
          type: object
          description: Canonical Agent Work Receipt v0.1 JSON Schema

    ReceiptValidationSuccess:
      type: object
      required:
        - ok
        - valid
        - schema_version
        - schema_url
        - receipt
        - persistence
      properties:
        ok:
          type: boolean
          const: true
        valid:
          type: boolean
          const: true
        schema_version:
          type: string
          const: agent-work-receipt/v0.1
        schema_url:
          type: string
          format: uri
        receipt:
          type: object
          required:
            - receipt_id
            - actor_id
            - runtime
            - producer_reported_outcome_status
            - producer_reported_verification_status
            - evidence_count
            - human_intervention_count
          properties:
            receipt_id:
              type: string
            actor_id:
              type: string
            runtime:
              type: [string, 'null']
            producer_reported_outcome_status:
              type: string
              description: Producer-declared outcome; not independently verified by conformance validation
            producer_reported_verification_status:
              type: string
              description: Producer-declared verification; not an OrgX hosted review
            evidence_count:
              type: integer
              minimum: 0
            human_intervention_count:
              type: integer
              minimum: 0
        persistence:
          type: object
          required:
            - stored
            - import_requires_authentication
          properties:
            stored:
              type: boolean
              const: false
            import_requires_authentication:
              type: boolean
              const: true

    ReceiptValidationFailure:
      type: object
      required:
        - ok
        - valid
        - schema_version
        - schema_url
        - issues
        - issue_count
        - issues_truncated
      properties:
        ok:
          type: boolean
          const: false
        valid:
          type: boolean
          const: false
        schema_version:
          type: string
          const: agent-work-receipt/v0.1
        schema_url:
          type: string
          format: uri
        issues:
          type: array
          maxItems: 100
          items:
            type: object
            required: [path, code, message]
            properties:
              path:
                type: string
              code:
                type: string
              message:
                type: string
        issue_count:
          type: integer
          minimum: 1
        issues_truncated:
          type: boolean

    WorkloadDiagnosisRequest:
      type: object
      additionalProperties: false
      required: [schema_version, workload]
      properties:
        schema_version:
          type: string
          const: workload-diagnosis/0.1
        workload:
          type: object
          additionalProperties: false
          required:
            - name
            - outcome
            - time_horizon
            - agent_count
            - coordination
            - systems
            - authority
            - accountability
          allOf:
            - if:
                required: [agent_count]
                properties:
                  agent_count:
                    const: 1
              then:
                properties:
                  coordination:
                    const: none
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: write_internal_records
              then:
                properties:
                  systems:
                    contains:
                      required: [access]
                      properties:
                        access:
                          enum: [write, admin]
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: modify_code
              then:
                properties:
                  systems:
                    contains:
                      required: [category, access]
                      properties:
                        category:
                          enum: [code_repository, local_files]
                        access:
                          enum: [write, admin]
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: merge_or_deploy
              then:
                properties:
                  systems:
                    contains:
                      required: [category, access]
                      properties:
                        category:
                          enum: [code_repository, cloud_runtime]
                        access:
                          enum: [write, admin]
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: send_external_message
              then:
                properties:
                  systems:
                    contains:
                      required: [category, access]
                      properties:
                        category:
                          enum: [messaging, crm, browser, other]
                        access:
                          enum: [write, admin]
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: spend_funds
              then:
                properties:
                  systems:
                    contains:
                      required: [category, access]
                      properties:
                        category:
                          enum: [finance, browser]
                        access:
                          enum: [write, admin]
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: create_account
              then:
                properties:
                  systems:
                    contains:
                      required: [category, access]
                      properties:
                        category:
                          enum: [identity, browser, other]
                        access:
                          enum: [write, admin]
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: change_permissions
              then:
                properties:
                  systems:
                    contains:
                      required: [access]
                      properties:
                        access:
                          const: admin
            - if:
                required: [authority]
                properties:
                  authority:
                    required: [actions]
                    properties:
                      actions:
                        contains:
                          const: delete_data
              then:
                properties:
                  systems:
                    contains:
                      required: [category, access]
                      properties:
                        category:
                          enum:
                            - code_repository
                            - document_store
                            - crm
                            - database
                            - cloud_runtime
                            - local_files
                            - other
                        access:
                          enum: [write, admin]
          properties:
            name:
              type: string
              description: Trimmed before the 1-to-120-character length check; whitespace-only, control-character, and credential-shaped values are rejected with 400.
              minLength: 1
              allOf:
                - pattern: '\S'
                - pattern: '^\s*(?:\S|\S[\s\S]{0,118}\S)\s*$'
                - not:
                    pattern: '[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]'
                - not:
                    pattern: '(?:\b(?:[Aa][Pp][Ii][_-]?[Kk][Ee][Yy]|[Aa][Cc][Cc][Ee][Ss][Ss][_-]?[Tt][Oo][Kk][Ee][Nn]|[Rr][Ee][Ff][Rr][Ee][Ss][Hh][_-]?[Tt][Oo][Kk][Ee][Nn]|[Cc][Ll][Ii][Ee][Nn][Tt][_-]?[Ss][Ee][Cc][Rr][Ee][Tt]|[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd])\s*[:=]\s*\S+|\b[Bb][Ee][Aa][Rr][Ee][Rr]\s+[A-Za-z0-9._~+/=-]{8,}|\b(?:(?:[Oo][Xx][Kk]_|[Ss][Kk]-|[Gg][Hh][PpOoUuSsRr]_)[A-Za-z0-9_-]{8,}|[Aa][Kk][Ii][Aa][A-Za-z0-9]{16})\b|-----[Bb][Ee][Gg][Ii][Nn] [A-Za-z ]*[Pp][Rr][Ii][Vv][Aa][Tt][Ee] [Kk][Ee][Yy]-----|:\/\/[^\/\s:@]+:[^\/\s@]+@)'
                - not:
                    pattern: '(?:\b[Gg][Ii][Tt][Hh][Uu][Bb]_[Pp][Aa][Tt]_[A-Za-z0-9_]{8,}|\b[Gg][Ll][Pp][Aa][Tt]-[A-Za-z0-9_-]{16,}|\b[Xx][Oo][Xx][BbAaPpRrSs]-[A-Za-z0-9-]{8,}|\b[Ss][Kk]_[Ll][Ii][Vv][Ee]_[A-Za-z0-9_-]{8,}|\b[Rr][Kk]_[Ll][Ii][Vv][Ee]_[A-Za-z0-9_-]{8,}|\b[Nn][Pp][Mm]_[A-Za-z0-9]{8,}|\b[Aa][Ss][Ii][Aa][A-Z0-9]{16}|\b[Dd][Oo][Pp]_[Vv]1_[A-Fa-f0-9]{16,}|\b[Hh][Ff]_[A-Za-z0-9]{20,}|\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,})'
            outcome:
              type: string
              description: Trimmed before the 1-to-500-character length check; whitespace-only, control-character, and credential-shaped values are rejected with 400.
              minLength: 1
              allOf:
                - pattern: '\S'
                - pattern: '^\s*(?:\S|\S[\s\S]{0,498}\S)\s*$'
                - not:
                    pattern: '[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]'
                - not:
                    pattern: '(?:\b(?:[Aa][Pp][Ii][_-]?[Kk][Ee][Yy]|[Aa][Cc][Cc][Ee][Ss][Ss][_-]?[Tt][Oo][Kk][Ee][Nn]|[Rr][Ee][Ff][Rr][Ee][Ss][Hh][_-]?[Tt][Oo][Kk][Ee][Nn]|[Cc][Ll][Ii][Ee][Nn][Tt][_-]?[Ss][Ee][Cc][Rr][Ee][Tt]|[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd])\s*[:=]\s*\S+|\b[Bb][Ee][Aa][Rr][Ee][Rr]\s+[A-Za-z0-9._~+/=-]{8,}|\b(?:(?:[Oo][Xx][Kk]_|[Ss][Kk]-|[Gg][Hh][PpOoUuSsRr]_)[A-Za-z0-9_-]{8,}|[Aa][Kk][Ii][Aa][A-Za-z0-9]{16})\b|-----[Bb][Ee][Gg][Ii][Nn] [A-Za-z ]*[Pp][Rr][Ii][Vv][Aa][Tt][Ee] [Kk][Ee][Yy]-----|:\/\/[^\/\s:@]+:[^\/\s@]+@)'
                - not:
                    pattern: '(?:\b[Gg][Ii][Tt][Hh][Uu][Bb]_[Pp][Aa][Tt]_[A-Za-z0-9_]{8,}|\b[Gg][Ll][Pp][Aa][Tt]-[A-Za-z0-9_-]{16,}|\b[Xx][Oo][Xx][BbAaPpRrSs]-[A-Za-z0-9-]{8,}|\b[Ss][Kk]_[Ll][Ii][Vv][Ee]_[A-Za-z0-9_-]{8,}|\b[Rr][Kk]_[Ll][Ii][Vv][Ee]_[A-Za-z0-9_-]{8,}|\b[Nn][Pp][Mm]_[A-Za-z0-9]{8,}|\b[Aa][Ss][Ii][Aa][A-Z0-9]{16}|\b[Dd][Oo][Pp]_[Vv]1_[A-Fa-f0-9]{16,}|\b[Hh][Ff]_[A-Za-z0-9]{20,}|\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,})'
            time_horizon:
              type: string
              enum:
                [single_turn, single_session, multi_day, recurring, continuous]
            agent_count:
              type: integer
              minimum: 1
              maximum: 64
            coordination:
              type: string
              enum: [none, handoff, parallel, hierarchical]
            systems:
              type: array
              maxItems: 12
              uniqueItems: true
              description: Each category may appear at most once; report its highest access and consequence.
              allOf:
                - contains:
                    required: [category]
                    properties:
                      category: { const: code_repository }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: issue_tracker }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: document_store }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: messaging }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: crm }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: database }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: cloud_runtime }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: finance }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: browser }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: local_files }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: identity }
                  minContains: 0
                  maxContains: 1
                - contains:
                    required: [category]
                    properties:
                      category: { const: other }
                  minContains: 0
                  maxContains: 1
              items:
                type: object
                additionalProperties: false
                required: [category, access, side_effect, data_class]
                properties:
                  category:
                    type: string
                    enum:
                      - code_repository
                      - issue_tracker
                      - document_store
                      - messaging
                      - crm
                      - database
                      - cloud_runtime
                      - finance
                      - browser
                      - local_files
                      - identity
                      - other
                  access:
                    type: string
                    enum: [read, write, admin]
                  side_effect:
                    type: string
                    enum: [none, reversible, external, irreversible]
                  data_class:
                    type: string
                    enum: [public, internal, confidential, regulated]
            authority:
              type: object
              additionalProperties: false
              required: [actions, approval_policy, budget_control]
              allOf:
                - if:
                    properties:
                      actions:
                        contains:
                          enum:
                            - write_internal_records
                            - modify_code
                            - merge_or_deploy
                            - send_external_message
                            - spend_funds
                            - create_account
                            - change_permissions
                            - delete_data
                  then:
                    properties:
                      approval_policy:
                        enum:
                          - per_action
                          - sensitive_actions
                          - exceptions_only
                          - undefined
                - if:
                    properties:
                      actions:
                        contains:
                          const: spend_funds
                  then:
                    properties:
                      budget_control:
                        enum: [fixed_limit, dynamic_limit, unbounded, undefined]
                  else:
                    properties:
                      budget_control:
                        enum: [not_applicable, undefined]
              properties:
                actions:
                  type: array
                  uniqueItems: true
                  maxItems: 11
                  items:
                    type: string
                    enum:
                      - research
                      - draft
                      - read_internal_data
                      - write_internal_records
                      - modify_code
                      - merge_or_deploy
                      - send_external_message
                      - spend_funds
                      - create_account
                      - change_permissions
                      - delete_data
                approval_policy:
                  type: string
                  enum:
                    [
                      not_applicable,
                      per_action,
                      sensitive_actions,
                      exceptions_only,
                      undefined,
                    ]
                budget_control:
                  type: string
                  enum:
                    [
                      not_applicable,
                      fixed_limit,
                      dynamic_limit,
                      unbounded,
                      undefined,
                    ]
            accountability:
              type: object
              additionalProperties: false
              required: [evidence, acceptance, consequence, retention]
              properties:
                evidence:
                  type: string
                  enum: [none, activity_log, artifact, verified_outcome]
                acceptance:
                  type: string
                  enum: [none, agent, human, downstream_system]
                consequence:
                  type: string
                  enum: [low, moderate, high, regulated]
                retention:
                  type: string
                  enum: [none, short_term, long_term, regulated]

    BoundaryFinding:
      type: object
      additionalProperties: false
      required: [state, score, reason]
      properties:
        state:
          type: string
          enum: [absent, present, critical]
        score:
          type: integer
          minimum: 0
          maximum: 2
        reason:
          type: string
          minLength: 1
          maxLength: 300

    MissingCapability:
      type: object
      additionalProperties: false
      required: [id, boundary, reason]
      properties:
        id:
          type: string
          pattern: '^[a-z0-9_]{1,60}$'
        boundary:
          type: string
          enum: [time, agents, systems, authority, accountability]
        reason:
          type: string
          minLength: 1
          maxLength: 300

    ProposedResource:
      type: object
      additionalProperties: false
      required:
        - resource
        - requested_access
        - scope_intents
        - purpose
        - credential_input_required
      properties:
        resource:
          type: string
          minLength: 1
          maxLength: 80
        requested_access:
          type: string
          enum: [read, write, admin]
        scope_intents:
          type: array
          minItems: 1
          maxItems: 12
          items:
            type: string
            minLength: 1
            maxLength: 80
        purpose:
          type: string
          minLength: 1
          maxLength: 300
        credential_input_required:
          type: boolean
          const: false

    LocalWorkItem:
      type: object
      additionalProperties: false
      required: [item, reason]
      properties:
        item:
          type: string
          minLength: 1
          maxLength: 100
        reason:
          type: string
          minLength: 1
          maxLength: 300

    WorkloadRisk:
      type: object
      additionalProperties: false
      required: [id, severity, boundary, description, mitigation]
      properties:
        id:
          type: string
          pattern: '^[a-z0-9_]{1,60}$'
        severity:
          type: string
          enum: [low, medium, high, critical]
        boundary:
          type: string
          enum: [time, agents, systems, authority, accountability]
        description:
          type: string
          minLength: 1
          maxLength: 300
        mitigation:
          type: string
          minLength: 1
          maxLength: 300

    HumanApproval:
      type: object
      additionalProperties: false
      required: [id, owner_role, timing, decision, scope]
      properties:
        id:
          type: string
          pattern: '^[a-z0-9_-]{1,80}$'
        owner_role:
          type: string
          enum:
            - workload_owner
            - system_owner
            - code_owner
            - communications_owner
            - budget_owner
            - identity_admin
            - data_owner
        timing:
          type: string
          enum:
            - before_installation
            - before_first_use
            - per_action
            - when_threshold_exceeded
        decision:
          type: string
          minLength: 1
          maxLength: 300
        scope:
          type: array
          minItems: 1
          maxItems: 16
          items:
            type: string
            minLength: 1
            maxLength: 100

    WorkloadDiagnosisResponse:
      type: object
      additionalProperties: false
      required:
        - schema_version
        - diagnosis_id
        - recommendation
        - boundaries
        - missing_capabilities
        - proposed_resources
        - what_remains_local
        - risks
        - capabilities_after_installation
        - human_approvals
        - approval_handoff
      properties:
        schema_version:
          type: string
          const: workload-diagnosis/0.1
        diagnosis_id:
          type: string
          pattern: '^wdg_[a-f0-9]{24}$'
        recommendation:
          type: object
          additionalProperties: false
          required: [verdict, mode, summary, rationale, active_boundary_count]
          properties:
            verdict:
              type: string
              enum: [needed, conditional, not_needed]
            mode:
              type: string
              enum: [none, receipt_only, governed_workspace]
            summary:
              type: string
            rationale:
              type: array
              items:
                type: string
            active_boundary_count:
              type: integer
              minimum: 0
              maximum: 5
        boundaries:
          type: object
          additionalProperties: false
          required: [time, agents, systems, authority, accountability]
          properties:
            time:
              $ref: '#/components/schemas/BoundaryFinding'
            agents:
              $ref: '#/components/schemas/BoundaryFinding'
            systems:
              $ref: '#/components/schemas/BoundaryFinding'
            authority:
              $ref: '#/components/schemas/BoundaryFinding'
            accountability:
              $ref: '#/components/schemas/BoundaryFinding'
        missing_capabilities:
          type: array
          maxItems: 15
          items:
            $ref: '#/components/schemas/MissingCapability'
        proposed_resources:
          type: array
          maxItems: 13
          items:
            $ref: '#/components/schemas/ProposedResource'
        what_remains_local:
          type: array
          minItems: 1
          maxItems: 6
          items:
            $ref: '#/components/schemas/LocalWorkItem'
        risks:
          type: array
          maxItems: 15
          items:
            $ref: '#/components/schemas/WorkloadRisk'
        capabilities_after_installation:
          type: array
          maxItems: 10
          items:
            type: string
            minLength: 1
            maxLength: 300
        human_approvals:
          type: array
          maxItems: 32
          items:
            $ref: '#/components/schemas/HumanApproval'
        approval_handoff:
          type: object
          additionalProperties: false
          required:
            - kind
            - url
            - mutates_state
            - carries_sensitive_data
            - approval_ids
          properties:
            kind:
              type: string
              enum: [none, browser_review]
            url:
              type: [string, 'null']
              format: uri
            mutates_state:
              type: boolean
              const: false
            carries_sensitive_data:
              type: boolean
              description: True when an authenticated-encryption protected, short-lived browser handoff URL is present; false when no token is emitted.
            approval_ids:
              type: array
              items:
                type: string

    PublicApiError:
      type: object
      required: [error]
      properties:
        ok:
          type: boolean
        valid:
          type: boolean
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
            message:
              type: string
            issues:
              type: array
              items:
                type: object

    EstimateRequest:
      type: object
      required:
        - prompt
        - contentTypes
      properties:
        prompt:
          type: string
          minLength: 1
          maxLength: 5000
          description: Description of the content you want to create
          example: 'Create a LinkedIn carousel about 5 AI productivity tips'
        contentTypes:
          type: array
          items:
            $ref: '#/components/schemas/ContentType'
          minItems: 1
          maxItems: 5
          description: Types of content to generate
        variantCount:
          type: integer
          minimum: 1
          maximum: 10
          default: 1
          description: Number of variants per content type
        brandUrl:
          type: string
          format: uri
          description: URL to ingest brand assets from
        brandId:
          type: string
          format: uuid
          description: ID of existing brand to use
        platform:
          type: string
          enum:
            [linkedin, instagram, twitter, facebook, youtube, tiktok, generic]
          description: Target platform for optimization

    EstimateResponse:
      type: object
      properties:
        estimateId:
          type: string
          format: uuid
        breakdown:
          $ref: '#/components/schemas/CostBreakdown'
        totalCredits:
          type: integer
          description: Total credits required
        estimatedPrice:
          type: object
          properties:
            amount:
              type: number
              description: Price in dollars
            currency:
              type: string
              const: usd
        expiresAt:
          type: string
          format: date-time
        showcase:
          type: array
          items:
            $ref: '#/components/schemas/ShowcaseExample'
          description: Related showcase examples
        requiresAuth:
          type: boolean
          description: True if authentication needed for checkout
        authRedirectUrl:
          type: string
          format: uri
          description: URL to redirect for authentication

    CostBreakdown:
      type: object
      properties:
        brandIngestion:
          type: object
          properties:
            required:
              type: boolean
            credits:
              type: integer
            complexity:
              type: string
              enum: [simple, moderate, complex]
        calibration:
          type: object
          properties:
            rounds:
              type: integer
            credits:
              type: integer
        exploration:
          type: object
          properties:
            rounds:
              type: integer
            credits:
              type: integer
        composition:
          type: object
          properties:
            complexity:
              type: string
              enum: [basic, standard, premium]
            credits:
              type: integer
            multiplier:
              type: number
        outputs:
          type: array
          items:
            type: object
            properties:
              type:
                $ref: '#/components/schemas/ContentType'
              count:
                type: integer
              creditsEach:
                type: integer
              subtotal:
                type: integer

    ShowcaseExample:
      type: object
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
        description:
          type: string
        contentType:
          $ref: '#/components/schemas/ContentType'
        industry:
          type: string
        style:
          type: string
        thumbnailUrl:
          type: string
          format: uri
        previewUrls:
          type: array
          items:
            type: string
            format: uri
        qaScores:
          type: object
          properties:
            overall:
              type: number
            brandAlignment:
              type: number
            visualQuality:
              type: number

    ContentType:
      type: string
      enum: [carousel, post, story, video, banner, thumbnail]

    ApiError:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            details:
              type: object
            requestId:
              type: string
            timestamp:
              type: string
              format: date-time
            docsUrl:
              type: string
              format: uri
            retryAfter:
              type: integer
              description: Seconds until rate limit resets

  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT bearer token from OrgX authentication
    cookieAuth:
      type: apiKey
      in: cookie
      name: __session
      description: Session cookie from web authentication
    stripeSignature:
      type: apiKey
      in: header
      name: stripe-signature
      description: Stripe webhook signature
