# Romeo15 2026-08-26 -- static OpenAPI 3.0 spec for the v1 API surface.
# Companion to /api/openapi.json (v0 v3.1 spec). This yaml is Postman-
# import-friendly and intentionally scoped to the three v1 enterprise
# endpoints so procurement can review a small, stable contract without
# wading through the full v0 web surface.
openapi: 3.0.3
info:
  title: Digital Empire portfolio v1 API
  version: 1.0.0-beta
  description: |
    v1 API for PixelProof, EntryProof, and TariffWatch.

    All endpoints require `Authorization: Bearer de_<key>`. Contact
    support@enforceintel.com to request a beta key. Rate limits: 100
    requests/minute and 10,000 requests/day per key.

    Beta status: valid keys currently return 403 with
    `{ "error": "beta" }` unless enrolled in delegate mode. The
    contract shapes below are stable and safe to build against.
  contact:
    name: Digital Empire Holdings LLC
    email: support@enforceintel.com
    url: https://enforceintel.com/
  license:
    name: Proprietary
    url: https://enforceintel.com/meta-monitor/terms
servers:
  - url: https://enforceintel.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: TariffWatch
    description: >-
      Section 232 HTS lookup and duty-impact estimates, plus DIY comment-letter
      drafting on the web surface. TariffWatch does not file comments, entries
      or any submission with BIS or CBP, and is not a customs broker. The
      BIS-14 / FR 2026-15961 comment window closed Aug 27 2026.
  - name: PixelProof
    description: Shopify + Meta Pixel drift monitoring.
  - name: EntryProof
    description: CPSC eFile GCC generation.
paths:
  /api/v1/tariffwatch/hts/lookup:
    post:
      tags: [TariffWatch]
      summary: Look up one or more HTS codes against the BIS-14 derivative list.
      operationId: htsLookup
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [codes]
              properties:
                codes:
                  type: array
                  minItems: 1
                  maxItems: 50
                  items:
                    type: string
                  example: ["7601.10.6000", "7603.10.0000"]
      responses:
        '200':
          description: Lookup results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/HtsLookupResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Beta'
  /api/v1/pixelproof/scan:
    post:
      tags: [PixelProof]
      summary: Scan a Shopify storefront for legacy Meta Pixel / GA4 / GTM code.
      operationId: pixelproofScan
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
                  example: https://your-store.myshopify.com
      responses:
        '200':
          description: Scan report
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScanReport'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Beta'
  /api/mcp/pixelproof/scan_storefront:
    post:
      tags: [PixelProof]
      summary: Public MCP scan_storefront — wraps POST /api/pixelproof/free-scan
      operationId: scan_storefront
      security: []
      description: |
        Auth-light tool for cold MCP / Custom GPT callers. Wraps the existing
        `runFreeScan` pipeline behind POST /api/pixelproof/free-scan.

        Not /api/v1/pixelproof/scan (closed-beta bearer).
        Not /api/meta-monitor/scan (auth-required paid scanner).

        HTML-visible only. Not clearance. Not a fix pack. Not checkout proof.
        Echo `citation` verbatim. Support: support@enforceintel.com.

        Monitor CTA:
        https://pixeluptime.com/meta-monitor/pricing?checkout=monitor_only&utm_source=mcp&utm_medium=mcp&utm_campaign=pp_monitor&utm_content=mcp_scan_storefront

        Full public contract also lives at /api/openapi.json.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  example: https://your-store.myshopify.com
                email:
                  type: string
                  format: email
                  description: Optional. Accepted but not persisted.
      responses:
        '200':
          description: Findings + cream citation + Monitor CTA
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScanStorefrontSuccess'
        '429':
          description: Soft rate limit (not a hard lock)
  /api/mcp/entryproof/readiness_check:
    post:
      tags: [EntryProof]
      summary: Public MCP readiness_check — wraps POST /api/cpsc/scan
      operationId: readiness_check
      security: []
      description: |
        Auth-light tool for cold MCP / Custom GPT callers. Wraps the existing
        `computeReadinessScore` pipeline behind POST /api/cpsc/scan.

        Not /api/v1/entryproof/gcc/generate (closed-beta bearer).
        Not computePlaceholderReadinessScore (deprecated sync fake).

        Public HTML + optional HTS only. Not clearance. Not a filing service. Not legal advice.
        Echo `citation` verbatim. Support: support@enforceintel.com.

        EntryProof is free right now: no paid tier, no automated SKU monitoring,
        no recall alerts. Do not quote a price.

        CTA:
        https://enforceintel.com/cpsc-efile/checker?utm_source=mcp&utm_medium=mcp&utm_campaign=ep_free_checker&utm_content=mcp_readiness_check

        Full public contract also lives at /api/openapi.json.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [storeUrl]
              properties:
                storeUrl:
                  type: string
                  example: https://your-store.com/products/sku
                url:
                  type: string
                  description: Alias for storeUrl.
                htsCode:
                  type: string
                  example: "9503.00.0073"
                email:
                  type: string
                  format: email
                  description: Optional. Accepted but not persisted.
      responses:
        '200':
          description: Readiness result + cream citation + Solo CTA
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReadinessCheckSuccess'
        '429':
          description: Soft rate limit (not a hard lock)
  /api/mcp/tariffwatch/duty_impact:
    post:
      tags: [TariffWatch]
      summary: Public MCP duty_impact — wraps calculateDutyImpact
      operationId: duty_impact
      security: []
      description: |
        Auth-light tool for cold MCP / Custom GPT callers. Wraps the existing
        `calculateDutyImpact` pipeline in lib/tariffwatch/duty-impact
        (same engine as /tariffwatch/duty-impact-calculator).

        Not /api/v1/tariffwatch/hts/lookup (closed-beta bearer).

        Order-of-magnitude Section 232 + country-of-origin load factor.
        Not clearance. Not legal advice. Not a customs broker substitute.
        Echo `citation` verbatim. Support: support@tariffwatch.app.

        Watchlist CTA:
        https://tariffwatch.app/tariffwatch/watchlist?checkout=watchlist-year&utm_source=mcp&utm_medium=mcp&utm_campaign=tw_watchlist&utm_content=mcp_duty_impact

        Full public contract also lives at /api/openapi.json.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [htsCodes, annualImportValueUsd, countryOfOrigin]
              properties:
                htsCodes:
                  type: array
                  items: { type: string }
                  example: ["7603.10", "7310.29"]
                annualImportValueUsd:
                  type: number
                  example: 500000
                countryOfOrigin:
                  type: string
                  enum: [canada, mexico, eu, china, japan, south_korea, other]
                  example: china
                email:
                  type: string
                  format: email
                  description: Optional. Accepted but not persisted.
      responses:
        '200':
          description: Estimate + cream citation + Watchlist CTA
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DutyImpactSuccess'
        '429':
          description: Soft rate limit (not a hard lock)
  /api/v1/entryproof/gcc/generate:
    post:
      tags: [EntryProof]
      summary: Locked contract stub. Always returns 403; EntryProof does not issue or sign a GCC.
      description: >-
        This path exists as a frozen contract shape only. It returns 403 on every
        call. Under 16 CFR 1110 the certifier must be the manufacturer or the
        importer of record, so EntryProof cannot issue, sign, certify or file a
        GCC or CPC, and no EntryProof feature turns a lab report into a
        certificate. EntryProof scores public product-listing readiness.
      operationId: entryproofGccGenerate
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [product_info, manufacturer, testing_lab]
              properties:
                product_info:
                  type: object
                  properties:
                    name: { type: string }
                    model: { type: string }
                    sku: { type: string }
                    date_of_manufacture: { type: string, format: date }
                    place_of_manufacture: { type: string }
                manufacturer:
                  type: object
                  properties:
                    name: { type: string }
                    address: { type: string }
                    contact_email: { type: string, format: email }
                testing_lab:
                  type: object
                  properties:
                    name: { type: string }
                    accreditation_id: { type: string }
                    test_date: { type: string, format: date }
                cpsc_rules_cited:
                  type: array
                  items: { type: string }
      responses:
        # No 2xx is documented on purpose. app/api/v1/entryproof/gcc/generate
        # returns 403 unconditionally. A documented "200 Certificate generated"
        # with a gcc_pdf_url advertised a capability that cannot occur and that
        # 16 CFR 1110 forbids EntryProof from having.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Beta'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: de_<24 chars>
  responses:
    Unauthorized:
      description: Missing / malformed / unknown key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Beta:
      description: >-
        Beta -- the key is valid but not entitled for live-response mode.
        Contact the support address returned in the response body to be added
        to the delegate allowlist.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  schemas:
    ErrorEnvelope:
      type: object
      properties:
        error: { type: string, example: beta }
        message: { type: string }
        contact: { type: string, example: support@enforceintel.com }
    HtsLookupResult:
      type: object
      properties:
        code: { type: string, example: "7601.10.6000" }
        hit: { type: boolean }
        in_scope: { type: boolean }
        status:
          type: string
          enum: [hit, adjacent, in_scope_no_bis14, clear, invalid]
        adjacent_hits:
          type: array
          items:
            type: object
            properties:
              code_heading: { type: string }
              article_slug: { type: string }
              article_name: { type: string }
              proposed_rate: { type: number }
    ScanStorefrontSuccess:
      type: object
      properties:
        ok: { type: boolean, example: true }
        tool: { type: string, example: scan_storefront }
        source: { type: string, example: runFreeScan }
        wraps: { type: string, example: /api/pixelproof/free-scan }
        citation: { type: string }
        monitorCta:
          type: object
          properties:
            href:
              type: string
              example: https://pixeluptime.com/meta-monitor/pricing?checkout=monitor_only&utm_source=mcp&utm_medium=mcp&utm_campaign=pp_monitor&utm_content=mcp_scan_storefront
            label: { type: string }
            honesty: { type: string }
        honesty:
          type: object
          properties:
            not_clearance: { type: boolean, example: true }
            not_fix_pack: { type: boolean, example: true }
            not_checkout_proof: { type: boolean, example: true }
            support: { type: string, example: support@enforceintel.com }
    ReadinessCheckSuccess:
      type: object
      properties:
        ok: { type: boolean, example: true }
        tool: { type: string, example: readiness_check }
        source: { type: string, example: computeReadinessScore }
        wraps: { type: string, example: /api/cpsc/scan }
        citation: { type: string }
        soloCta:
          type: object
          properties:
            href:
              type: string
              # Field name `soloCta` is a published wire field; the CONTENT is
              # the free checker while ENTRYPROOF_PAID_ENABLED is unset.
              example: https://enforceintel.com/cpsc-efile/checker?utm_source=mcp&utm_medium=mcp&utm_campaign=ep_free_checker&utm_content=mcp_readiness_check
            label: { type: string }
            honesty: { type: string }
        honesty:
          type: object
          properties:
            not_clearance: { type: boolean, example: true }
            not_filing_service: { type: boolean, example: true }
            not_legal_advice: { type: boolean, example: true }
            support: { type: string, example: support@enforceintel.com }
    DutyImpactSuccess:
      type: object
      properties:
        ok: { type: boolean, example: true }
        tool: { type: string, example: duty_impact }
        source: { type: string, example: calculateDutyImpact }
        wraps: { type: string, example: lib/tariffwatch/duty-impact }
        citation: { type: string }
        watchlistCta:
          type: object
          properties:
            href:
              type: string
              example: https://tariffwatch.app/tariffwatch/watchlist?checkout=watchlist-year&utm_source=mcp&utm_medium=mcp&utm_campaign=tw_watchlist&utm_content=mcp_duty_impact
            label: { type: string }
            honesty: { type: string }
        honesty:
          type: object
          properties:
            not_clearance: { type: boolean, example: true }
            not_legal_advice: { type: boolean, example: true }
            not_customs_broker: { type: boolean, example: true }
            email_required_trial: { type: boolean, example: true }
            support: { type: string, example: support@tariffwatch.app }
    ScanReport:
      type: object
      properties:
        score: { type: integer, minimum: 0, maximum: 100 }
        findings:
          type: array
          items:
            type: object
            properties:
              rule_id: { type: string }
              severity: { type: string, enum: [info, warn, error] }
              message: { type: string }
        severity_counts:
          type: object
          properties:
            info: { type: integer }
            warn: { type: integer }
            error: { type: integer }
