openapi: 3.1.0
info:
  title: AUROS Protocol
  version: "1.0"
  x-logo:
    url: https://getauros.com/auros-logo.svg
    altText: AUROS
  description: |
    The RWA Intelligence Layer — indicative MiCA scoring, RWA catalog, jurisdiction ranking,
    and compliance checklists. Not legal advice.

    **Base URLs (production):** `https://getauros.com` or `https://api.getauros.com` (API subdomain)

    **Authentication:** Bearer token (`auros_pk_live_*` or `auros_pk_test_*`). Demo key: `auros_pk_test_demo`.

    **Free tier:** 100 requests/month per key. Key creation via `POST /api/v1/keys` (no auth).

    **Response headers (every response):** `X-AUROS-Protocol-Version: 1.0`, `X-AUROS-Logo: https://getauros.com/auros-logo.svg`, `X-Response-Time` (request duration in ms). Authenticated routes and IP-limited endpoints also return `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (Unix timestamp — monthly key quota resets on the 1st UTC).

    **SDKs:** `@adrien1212balitrand/auros-protocol` (npm), `auros-protocol` (pip). Docs: `/developers/docs`.

    **Postman:** Import `/auros-postman.json` (collection v2.1 — all v1 endpoints, demo key pre-filled).
  contact:
    name: AUROS
    url: https://getauros.com/developers
    email: contact@getauros.com
  license:
    name: Proprietary
    url: https://getauros.com/trust
externalDocs:
  description: Developer hub, playground & Postman collection (/auros-postman.json)
  url: https://getauros.com/developers
servers:
  - url: https://getauros.com
    description: Production (main domain)
  - url: https://api.getauros.com
    description: Production (API subdomain — same endpoints under /api/v1/*)
  - url: http://localhost:3000
    description: Local development
security:
  - bearerAuth: []
tags:
  - name: Intelligence
    description: MiCA scoring and compliance
  - name: Catalog
    description: RWA product data
  - name: Keys
    description: API key management
  - name: Premium
    description: Monitor, dossier, webhooks — requires live key or paid tier
  - name: Status
    description: Public health checks — no auth
paths:
  /api/v1/status:
    get:
      tags: [Status]
      summary: API health status
      operationId: status
      security: []
      description: |
        Public health check — probes scoring engine, product catalog, jurisdiction ranking,
        and key storage. No authentication required.
      responses:
        "200":
          description: System status
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
            X-Response-Time:
              schema:
                type: string
                example: "12ms"
          content:
            application/json:
              schema:
                type: object
                required: [status, services, version, timestamp]
                properties:
                  status:
                    type: string
                    enum: [operational, degraded, down]
                  services:
                    type: object
                    additionalProperties:
                      type: object
                      properties:
                        status:
                          type: string
                        latency_ms:
                          type: integer
                        message:
                          type: string
                  version:
                    type: string
                  app_version:
                    type: string
                  timestamp:
                    type: string
                    format: date-time
                  deploy:
                    type: object
                    properties:
                      environment:
                        type: string
                      commit:
                        type: string
                        nullable: true
                      ref:
                        type: string
                        nullable: true
  /api/v1/score:
    post:
      tags: [Intelligence]
      summary: MiCA intelligence score
      operationId: score
      description: |
        Compute an indicative MiCA readiness score (0–100) with grade, five-dimension breakdown,
        classification, gaps, recommendations, and jurisdiction/platform suggestions.
        Accepts free-text `description` and/or structured compliance fields.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ScoreRequest"
            examples:
              textOnly:
                summary: Free-text description
                value:
                  description: "Retail warehouse Luxembourg €2.5M SPV professional investors whitepaper draft"
              structured:
                summary: Structured fields
                value:
                  asset_type: real_estate
                  issuer_type: company_spv
                  investor_type: professional
                  whitepaper: draft
                  jurisdiction: luxembourg
                  value_eur: 2500000
                  has_kyc: true
                  has_data_room: false
      responses:
        "200":
          description: Score result
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ScoreResponse"
              example:
                disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
                score: 72
                grade: "B-"
                status: progress
                breakdown:
                  legal_structure: 78
                  kyc_aml: 65
                  mica_compliance: 70
                  data_room: 55
                  investor_protection: 80
                mica_classification: financial_instrument
                critical_gaps:
                  - "Complete whitepaper before retail distribution"
                recommendations:
                  - "Incorporate an EU SPV or regulated fund vehicle before retail distribution."
                recommended_jurisdictions:
                  - id: luxembourg
                    score: 88
                    rationale: "Strong fund/SPV framework for professional real estate RWA."
                recommended_platforms:
                  - id: maple
                    name: Maple
                    category: private_credit
                    apy: 8.2
                meta:
                  version: "1.0"
                  computed_at: "2026-06-11T10:00:00.000Z"
                  full_report_url: "https://getauros.com/wizard"
                  parsed_keywords: ["warehouse", "luxembourg", "spv"]
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/score/batch:
    post:
      tags: [Intelligence]
      summary: Batch MiCA intelligence scores
      operationId: scoreBatch
      description: |
        Score up to 20 assets in a single request for institutional portfolios.
        Each item accepts the same payload as POST /api/v1/score (free-text `description`
        and/or structured compliance fields).

        **Partial success:** invalid items return `{ ok: false, error }` at their index;
        valid items still receive full score results with `score_id`.

        **Quota:** counts as **1 request** against the monthly API key quota (not N items).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ScoreBatchRequest"
            example:
              record_history: true
              items:
                - description: "Retail warehouse Luxembourg €2.5M SPV professional investors"
                - asset_type: bonds
                  issuer_type: company_spv
                  whitepaper: draft
                  has_kyc: true
      responses:
        "200":
          description: Batch score results (may include per-item errors)
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ScoreBatchResponse"
              example:
                disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
                total: 2
                succeeded: 2
                failed: 0
                items:
                  - index: 0
                    ok: true
                    score_id: scr_a1b2c3d4e5f6789012345678
                    history_url: https://getauros.com/api/v1/score/scr_a1b2c3d4e5f6789012345678/history
                    score: 72
                    grade: "B-"
                    status: progress
                    mica_classification: financial_instrument
                    breakdown:
                      legal_structure: 78
                      kyc_aml: 65
                      mica_compliance: 70
                      data_room: 55
                      investor_protection: 80
                    critical_gaps: []
                    recommendations: []
                    recommended_jurisdictions: []
                    recommended_platforms: []
                    meta:
                      version: "1.0"
                      computed_at: "2026-06-12T12:00:00.000Z"
                      full_report_url: https://getauros.com/wizard
                      parsed_keywords: []
                  - index: 1
                    ok: false
                    error:
                      code: validation_error
                      message: "Provide description or structured asset/compliance fields"
                meta:
                  version: "1.0"
                  computed_at: "2026-06-12T12:00:00.000Z"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/score/{id}/history:
    get:
      tags: [Intelligence]
      summary: Score history for a session or monitor
      operationId: scoreHistory
      description: |
        Return chronological score snapshots for a `scr_*` session (from POST /api/v1/score)
        or a premium `mon_*` monitor. Requires Bearer auth; scoped to the API key that created the session.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            pattern: "^(scr|mon)_[a-f0-9]{24}$"
          description: Score session id (`scr_…`) or monitor id (`mon_…`)
      responses:
        "200":
          description: Score history entries
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ScoreHistoryResponse"
              example:
                disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
                score_id: scr_a1b2c3d4e5f6789012345678
                kind: session
                total: 2
                entries:
                  - id: 1
                    score: 68
                    grade: C+
                    status: progress
                    breakdown:
                      legal_structure: 70
                      kyc_aml: 60
                      mica_compliance: 65
                      data_room: 50
                      investor_protection: 75
                    mica_classification: financial_instrument
                    created_at: "2026-06-12T10:00:00.000Z"
                  - id: 2
                    score: 72
                    grade: B-
                    status: progress
                    breakdown:
                      legal_structure: 78
                      kyc_aml: 65
                      mica_compliance: 70
                      data_room: 55
                      investor_protection: 80
                    mica_classification: financial_instrument
                    created_at: "2026-06-12T11:00:00.000Z"
                meta:
                  version: "1.0"
                  computed_at: "2026-06-12T11:05:00.000Z"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/products:
    get:
      tags: [Catalog]
      summary: RWA product catalog
      operationId: products
      description: Paginated catalog of 120+ tokenized RWA products with APY, TVL, chains, and jurisdiction.
      parameters:
        - name: category
          in: query
          schema:
            type: string
            enum: [stablecoins, real_estate, bonds, commodities, private_credit, all]
            default: all
        - name: jurisdiction
          in: query
          schema:
            type: string
            maxLength: 64
        - name: chain
          in: query
          schema:
            type: string
            maxLength: 64
        - name: yield_min
          in: query
          schema:
            type: number
            minimum: 0
        - name: yield_max
          in: query
          schema:
            type: number
            minimum: 0
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: sort
          in: query
          schema:
            type: string
            enum: [apy, tvl, name]
            default: apy
      responses:
        "200":
          description: Paginated products
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductsResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/benchmarks:
    get:
      tags: [Catalog]
      summary: Sector RWA benchmarks
      operationId: benchmarks
      description: |
        Sector benchmarks (median APY, P25/P75 quartiles, product count) computed from the `/compare` hub.
        Optional `jurisdiction` filter. Falls back to curated static benchmarks when live yield data is sparse (< 3 products).
      security:
        - bearerAuth: []
      parameters:
        - name: category
          in: query
          required: true
          schema:
            type: string
            enum: [bonds, stablecoins, real_estate, private_credit, commodities]
        - name: jurisdiction
          in: query
          schema:
            type: string
            maxLength: 64
          description: Partial match on product jurisdiction (e.g. EU, US, CH, Luxembourg)
      responses:
        "200":
          description: Sector benchmark metrics
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
            X-Response-Time:
              schema:
                type: string
                example: "18ms"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BenchmarksResponse"
              example:
                category: bonds
                jurisdiction: EU
                metrics:
                  median_apy: 4.45
                  p25_apy: 4.2
                  p75_apy: 4.7
                  product_count: 9
                as_of: "2026-06-30"
                disclaimer: Indicative intelligence only — not legal, tax, or investment advice.
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/compare:
    post:
      tags: [Catalog]
      summary: Side-by-side RWA product comparison
      operationId: compare
      description: |
        Compare 2–4 tokenized RWA products side-by-side — mirrors the `/compare` hub.
        Pass explicit `product_ids` or filter criteria (`category`, `yield_min`, `risk_tier`, `jurisdiction`, `limit`).
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompareRequest"
            examples:
              byIds:
                summary: Compare by product IDs
                value:
                  product_ids: ["maple-usdc", "realt-portfolio", "backed-bib01"]
              byFilter:
                summary: Compare top matches by filter
                value:
                  category: bonds
                  yield_min: 4
                  risk_tier: core
                  limit: 3
      responses:
        "200":
          description: Structured comparison payload
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
            X-Response-Time:
              schema:
                type: string
                example: "42ms"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompareResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: Unknown product ID in product_ids mode
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProtocolError"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/jurisdictions:
    get:
      tags: [Intelligence]
      summary: Jurisdiction ranking
      operationId: jurisdictions
      description: Rank regulatory jurisdictions by asset type, investor profile, timeline, and budget.
      parameters:
        - name: asset_type
          in: query
          schema:
            type: string
            enum: [real_estate, bonds, private_credit, funds, all]
            default: all
        - name: investor_type
          in: query
          schema:
            type: string
            enum: [professional, retail, mixed, all]
            default: all
        - name: timeline_months
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 36
        - name: budget
          in: query
          schema:
            type: integer
            minimum: 0
      responses:
        "200":
          description: Ranked jurisdictions
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JurisdictionsResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/checklist:
    post:
      tags: [Intelligence]
      summary: Compliance checklist
      operationId: checklist
      description: Generate 20+ compliance items for an asset type, jurisdiction, and legal structure.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ChecklistRequest"
            example:
              asset_type: real_estate
              jurisdiction: luxembourg
              structure: spv
      responses:
        "200":
          description: Checklist items
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChecklistResponse"
        "400":
          $ref: "#/components/responses/ValidationError"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/keys:
    post:
      tags: [Keys]
      summary: Create API key
      operationId: createKey
      security: []
      description: |
        Request a free-tier API key (100 requests/month). No authentication required.
        Rate-limited by IP (5 requests/hour). The raw key is returned once — store securely.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateKeyRequest"
            example:
              email: developer@company.com
      responses:
        "200":
          description: Key created
          headers:
            X-AUROS-Protocol-Version:
              schema:
                type: string
                example: "1.0"
            X-AUROS-Logo:
              schema:
                type: string
                format: uri
                example: https://getauros.com/auros-logo.svg
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateKeyResponse"
              example:
                disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
                ok: true
                api_key: auros_pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                tier: free
                monthly_limit: 100
                message: "Store this key securely — it will not be shown again."
        "400":
          $ref: "#/components/responses/ValidationError"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/monitor:
    post:
      tags: [Premium]
      summary: Register asset monitor
      operationId: monitor
      description: |
        Premium endpoint. Register an asset profile for regulatory monitoring.
        Requires `auros_pk_live_*` or premium tier. Pricing: 49€/mo (5 assets), 199€/mo (25 assets).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MonitorRequest"
      responses:
        "201":
          description: Monitor created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MonitorResponse"
        "403":
          $ref: "#/components/responses/PremiumRequired"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "400":
          $ref: "#/components/responses/ValidationError"
  /api/v1/monitor/{id}:
    get:
      tags: [Premium]
      summary: Get monitor status
      operationId: getMonitor
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Monitor status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MonitorResponse"
        "403":
          $ref: "#/components/responses/PremiumRequired"
        "404":
          description: Not found
    delete:
      tags: [Premium]
      summary: Delete monitor
      operationId: deleteMonitor
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Deleted
        "403":
          $ref: "#/components/responses/PremiumRequired"
        "404":
          description: Not found
  /api/v1/dossier:
    post:
      tags: [Premium]
      summary: Generate institutional dossier
      operationId: dossier
      description: |
        Premium endpoint. Generate PDF or JSON institutional MiCA readiness report.
        PDF returns HMAC-signed download_url valid 24h.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DossierRequest"
      responses:
        "200":
          description: Dossier generated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DossierResponse"
        "403":
          $ref: "#/components/responses/PremiumRequired"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /api/v1/webhooks:
    post:
      tags: [Premium]
      summary: Register webhook
      operationId: registerWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookRegisterRequest"
      responses:
        "201":
          description: Webhook registered
        "403":
          $ref: "#/components/responses/PremiumRequired"
    get:
      tags: [Premium]
      summary: List webhooks
      operationId: listWebhooks
      responses:
        "200":
          description: Webhook list
        "403":
          $ref: "#/components/responses/PremiumRequired"
  /api/v1/webhooks/{id}:
    delete:
      tags: [Premium]
      summary: Delete webhook
      operationId: deleteWebhook
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Deleted
        "403":
          $ref: "#/components/responses/PremiumRequired"
  /api/v1/webhooks/{id}/deliveries:
    get:
      tags: [Premium]
      summary: List webhook delivery log
      operationId: listWebhookDeliveries
      description: |
        Paginated delivery log for a registered webhook — pending, delivered, failed, dead_letter.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
        - name: offset
          in: query
          schema: { type: integer, minimum: 0, default: 0 }
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, delivered, failed, dead_letter]
      responses:
        "200":
          description: Delivery log page
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveriesResponse"
        "404":
          description: Webhook not found
        "403":
          $ref: "#/components/responses/PremiumRequired"
  /api/v1/webhooks/{id}/replay:
    post:
      tags: [Premium]
      summary: Replay webhook deliveries
      operationId: replayWebhookDeliveries
      description: |
        Replay dead-letter deliveries for a webhook. Optional body `{ "delivery_id": "whd_..." }`
        replays a single delivery instead of all dead_letter rows.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookReplayRequest"
      responses:
        "200":
          description: Replay result
        "404":
          description: Webhook or delivery not found
        "403":
          $ref: "#/components/responses/PremiumRequired"
  /api/v1/webhooks/deliveries/{delivery_id}/replay:
    post:
      tags: [Premium]
      summary: Replay a single delivery
      operationId: replayWebhookDelivery
      parameters:
        - name: delivery_id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Delivery replayed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookReplayResponse"
        "404":
          description: Delivery not found
        "403":
          $ref: "#/components/responses/PremiumRequired"
  /api/v1/regulatory/feed:
    get:
      tags: [Premium]
      summary: Curated regulatory intelligence feed
      operationId: regulatoryFeed
      description: |
        Premium endpoint. Returns curated ESMA/AMF/BaFin MiCA references (v1 static seed).
        v2 will add live polling. Filter by jurisdiction, tag, since date.
      parameters:
        - name: jurisdiction
          in: query
          schema: { type: string, example: france }
        - name: tag
          in: query
          schema:
            type: string
            enum: [mica, esma, amf, bafin]
        - name: since
          in: query
          schema: { type: string, format: date, example: "2025-01-01" }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 100, default: 50 }
      responses:
        "200":
          description: Regulatory feed items
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegulatoryFeedResponse"
        "403":
          $ref: "#/components/responses/PremiumRequired"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /api/v1/regulatory/subscribe:
    post:
      tags: [Premium]
      summary: Subscribe to regulatory feed alerts
      operationId: regulatorySubscribe
      description: |
        Premium endpoint. Subscribe to `regulatory.update` webhook events filtered by
        jurisdiction and optional tags. Complements POST /api/v1/webhooks.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegulatorySubscribeRequest"
      responses:
        "201":
          description: Subscription created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegulatorySubscribeResponse"
        "403":
          $ref: "#/components/responses/PremiumRequired"
        "429":
          $ref: "#/components/responses/RateLimit"
  /api/v1/regulatory/subscribe/{id}:
    get:
      tags: [Premium]
      summary: Get regulatory subscription
      operationId: getRegulatorySubscription
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Subscription status
        "404":
          description: Not found
        "403":
          $ref: "#/components/responses/PremiumRequired"
    delete:
      tags: [Premium]
      summary: Delete regulatory subscription
      operationId: deleteRegulatorySubscription
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Deleted
        "404":
          description: Not found
        "403":
          $ref: "#/components/responses/PremiumRequired"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: "API key: auros_pk_live_* or auros_pk_test_* (demo: auros_pk_test_demo)"
  schemas:
    ProtocolError:
      type: object
      required: [disclaimer, error]
      properties:
        disclaimer:
          type: string
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              enum: [unauthorized, validation_error, invalid_json, rate_limit, quota_exceeded]
            message:
              type: string
    ScoreRequest:
      type: object
      properties:
        description:
          type: string
          minLength: 10
          maxLength: 4000
        asset_type:
          type: string
          enum: [real_estate, private_fund, bonds, private_credit, commodities, stablecoins, other]
        issuer_type:
          type: string
          enum: [company_spv, existing_fund, individual, unsure]
        asset_class:
          type: string
          enum: [financial_instrument, art_utility, e_money, unsure]
        eu_nexus:
          type: string
          enum: [issuer_eu, asset_eu, investors_eu, no_eu, unsure]
        whitepaper:
          type: string
          enum: [ready, draft, none, unsure]
        investor_type:
          type: string
          enum: [professional, retail, mixed, unsure]
        value_eur:
          type: number
          exclusiveMinimum: 0
        jurisdiction:
          type: string
          maxLength: 64
        has_kyc:
          type: boolean
        has_data_room:
          type: boolean
        documents_count:
          type: integer
          minimum: 0
          maximum: 100
        score_id:
          type: string
          pattern: "^scr_[a-f0-9]{24}$"
          description: Continue an existing score session (returned by a prior POST /score)
        monitor_id:
          type: string
          pattern: "^mon_[a-f0-9]{24}$"
          description: Link this score to a premium monitor (`mon_…`)
        record_history:
          type: boolean
          default: true
          description: Persist snapshot for authenticated keys (demo key skips storage)
    ScoreResponse:
      type: object
      required: [disclaimer, score, grade, status, breakdown, mica_classification, critical_gaps, recommendations, recommended_jurisdictions, recommended_platforms, meta]
      properties:
        disclaimer:
          type: string
        score_id:
          type: string
          description: Session id for history lookups (`scr_…`)
        history_url:
          type: string
          format: uri
          description: GET URL for this session's score history
        score:
          type: number
          minimum: 0
          maximum: 100
        grade:
          type: string
        status:
          type: string
          enum: [ready, progress, early]
        breakdown:
          type: object
          properties:
            legal_structure: { type: number }
            kyc_aml: { type: number }
            mica_compliance: { type: number }
            data_room: { type: number }
            investor_protection: { type: number }
        mica_classification:
          type: string
          enum: [utility_token, asset_referenced_token, e_money_token, other_crypto_asset, financial_instrument, out_of_scope, uncertain]
        critical_gaps:
          type: array
          items: { type: string }
        recommendations:
          type: array
          items: { type: string }
        recommended_jurisdictions:
          type: array
          items:
            type: object
            properties:
              id: { type: string }
              score: { type: number }
              rationale: { type: string }
        recommended_platforms:
          type: array
          items:
            type: object
            properties:
              id: { type: string }
              name: { type: string }
              category: { type: string }
              apy: { type: number }
        meta:
          type: object
          properties:
            version: { type: string, const: "1.0" }
            computed_at: { type: string, format: date-time }
            request_id: { type: string }
            full_report_url: { type: string, format: uri }
            parsed_keywords:
              type: array
              items: { type: string }
    ScoreBatchRequest:
      type: object
      required: [items]
      properties:
        items:
          type: array
          minItems: 1
          maxItems: 20
          description: Score payloads (same schema as POST /score). Max 20 items.
          items:
            $ref: "#/components/schemas/ScoreRequest"
        record_history:
          type: boolean
          default: true
          description: Default for all items unless overridden per item
    ScoreBatchResponse:
      type: object
      required: [disclaimer, total, succeeded, failed, items, meta]
      properties:
        disclaimer:
          type: string
        total:
          type: integer
          minimum: 0
        succeeded:
          type: integer
          minimum: 0
        failed:
          type: integer
          minimum: 0
        items:
          type: array
          items:
            oneOf:
              - allOf:
                  - type: object
                    required: [index, ok]
                    properties:
                      index:
                        type: integer
                        minimum: 0
                      ok:
                        type: boolean
                        enum: [true]
                  - $ref: "#/components/schemas/ScoreResponse"
              - type: object
                required: [index, ok, error]
                properties:
                  index:
                    type: integer
                    minimum: 0
                  ok:
                    type: boolean
                    enum: [false]
                  error:
                    type: object
                    required: [code, message]
                    properties:
                      code:
                        type: string
                      message:
                        type: string
        meta:
          type: object
          properties:
            version: { type: string, const: "1.0" }
            computed_at: { type: string, format: date-time }
            request_id: { type: string }
    ScoreHistoryResponse:
      type: object
      required: [disclaimer, score_id, kind, total, entries, meta]
      properties:
        disclaimer: { type: string }
        score_id: { type: string }
        kind:
          type: string
          enum: [session, monitor]
        total: { type: integer, minimum: 0 }
        entries:
          type: array
          items:
            $ref: "#/components/schemas/ScoreHistoryEntry"
        meta:
          type: object
          required: [version, computed_at]
          properties:
            version: { type: string, const: "1.0" }
            computed_at: { type: string, format: date-time }
    ScoreHistoryEntry:
      type: object
      required: [id, score, grade, status, breakdown, mica_classification, created_at]
      properties:
        id: { type: integer }
        score: { type: number, minimum: 0, maximum: 100 }
        grade: { type: string }
        status:
          type: string
          enum: [ready, progress, early]
        breakdown:
          type: object
          properties:
            legal_structure: { type: number }
            kyc_aml: { type: number }
            mica_compliance: { type: number }
            data_room: { type: number }
            investor_protection: { type: number }
        mica_classification:
          type: string
          enum: [utility_token, asset_referenced_token, e_money_token, other_crypto_asset, financial_instrument, out_of_scope, uncertain]
        request:
          type: object
          additionalProperties: true
        created_at:
          type: string
          format: date-time
    ProductsResponse:
      type: object
      required: [disclaimer, products, pagination, fetched_at]
      properties:
        disclaimer:
          type: string
        products:
          type: array
          items:
            $ref: "#/components/schemas/ProductItem"
        pagination:
          type: object
          properties:
            page: { type: integer }
            limit: { type: integer }
            total: { type: integer }
            total_pages: { type: integer }
        fetched_at:
          type: string
          format: date-time
    ProductItem:
      type: object
      properties:
        id: { type: string }
        name: { type: string }
        platform: { type: string }
        category: { type: string }
        apy: { type: number }
        tvl_usd: { type: number }
        chains:
          type: array
          items: { type: string }
        jurisdiction: { type: string, nullable: true }
        affiliate_url: { type: string }
        min_investment_usd: { type: number, nullable: true }
        live: { type: boolean }
    BenchmarksResponse:
      type: object
      required: [disclaimer, category, metrics, as_of]
      properties:
        disclaimer:
          type: string
        category:
          type: string
          enum: [bonds, stablecoins, real_estate, private_credit, commodities]
        jurisdiction:
          type: string
          description: Present when filtered by jurisdiction query param
        metrics:
          type: object
          required: [median_apy, p25_apy, p75_apy, product_count]
          properties:
            median_apy: { type: number, description: Median APY (%), live hub or static fallback }
            p25_apy: { type: number, description: 25th percentile APY (%) }
            p75_apy: { type: number, description: 75th percentile APY (%) }
            product_count: { type: integer, minimum: 0 }
        as_of:
          type: string
          description: ISO timestamp (live hub) or edition date (static fallback)
    CompareRequest:
      type: object
      description: |
        Either pass `product_ids` (2–4 IDs) for an explicit comparison, or omit IDs and use filter fields
        to select the top matches (sorted by APY).
      properties:
        product_ids:
          type: array
          minItems: 2
          maxItems: 4
          items:
            type: string
            minLength: 1
        category:
          type: string
          enum: [stablecoins, real_estate, bonds, commodities, private_credit, all]
          default: all
        yield_min:
          type: number
          minimum: 0
        risk_tier:
          type: string
          enum: [conservative, core, advanced]
        jurisdiction:
          type: string
          maxLength: 64
        limit:
          type: integer
          minimum: 2
          maximum: 4
          default: 4
          description: Max products to return in filter mode
    CompareProduct:
      allOf:
        - $ref: "#/components/schemas/ProductItem"
        - type: object
          properties:
            asset_class:
              type: string
              description: API category (stablecoins, real_estate, bonds, etc.)
            sub_category:
              type: string
              description: Comparator sub-category (treasury, sovereign, prime, etc.)
            risk_tier:
              type: string
              enum: [conservative, core, advanced]
            liquidity_days:
              type: integer
            fees:
              type: string
            accredited_only:
              type: boolean
    CompareResponse:
      type: object
      required: [disclaimer, mode, products, comparison, fetched_at, meta]
      properties:
        disclaimer:
          type: string
        mode:
          type: string
          enum: [product_ids, filter]
        products:
          type: array
          minItems: 2
          maxItems: 4
          items:
            $ref: "#/components/schemas/CompareProduct"
        comparison:
          type: object
          required: [product_count, share_url, highlights]
          properties:
            product_count:
              type: integer
            share_url:
              type: string
              format: uri
            product_ids:
              type: array
              items:
                type: string
            filters:
              type: object
              properties:
                category:
                  type: string
                yield_min:
                  type: number
                risk_tier:
                  type: string
                jurisdiction:
                  type: string
                limit:
                  type: integer
            highlights:
              type: object
              properties:
                apy:
                  type: array
                  items:
                    type: string
                    nullable: true
                    enum: [best, worst, null]
                tvl_usd:
                  type: array
                  items:
                    type: string
                    nullable: true
                    enum: [best, worst, null]
                min_investment_usd:
                  type: array
                  items:
                    type: string
                    nullable: true
                    enum: [best, worst, null]
                liquidity_days:
                  type: array
                  items:
                    type: string
                    nullable: true
                    enum: [best, worst, null]
        fetched_at:
          type: string
          format: date-time
        meta:
          type: object
          properties:
            version:
              type: string
              const: "1.0"
            computed_at:
              type: string
              format: date-time
            request_id:
              type: string
    JurisdictionsResponse:
      type: object
      required: [disclaimer, jurisdictions, query]
      properties:
        disclaimer:
          type: string
        jurisdictions:
          type: array
          items:
            $ref: "#/components/schemas/JurisdictionItem"
        query:
          type: object
    JurisdictionItem:
      type: object
      properties:
        id: { type: string }
        score: { type: number }
        rationale: { type: string }
        fee_min_eur: { type: number }
        fee_max_eur: { type: number }
        license_max_months: { type: number }
        asset_types:
          type: array
          items: { type: string }
        kyc_level: { type: string }
    ChecklistRequest:
      type: object
      required: [asset_type, jurisdiction]
      properties:
        asset_type:
          type: string
          enum: [real_estate, private_fund, bonds, private_credit]
        jurisdiction:
          type: string
          minLength: 2
          maxLength: 64
        structure:
          type: string
          enum: [spv, fund, trust, other]
          default: spv
    ChecklistResponse:
      type: object
      required: [disclaimer, asset_type, jurisdiction, structure, items, total_items, estimated_total_days, estimated_total_cost_eur]
      properties:
        disclaimer: { type: string }
        asset_type: { type: string }
        jurisdiction: { type: string }
        structure: { type: string }
        items:
          type: array
          items:
            $ref: "#/components/schemas/ChecklistItem"
        total_items: { type: integer }
        estimated_total_days: { type: integer }
        estimated_total_cost_eur: { type: number }
    ChecklistItem:
      type: object
      properties:
        id: { type: string }
        category: { type: string }
        title: { type: string }
        regulatory_reference: { type: string }
        required: { type: boolean }
        estimated_time_days: { type: integer }
        estimated_cost_eur: { type: number }
        dependencies:
          type: array
          items: { type: string }
        auros_tip: { type: string }
    CreateKeyRequest:
      type: object
      required: [email]
      properties:
        email:
          type: string
          format: email
          maxLength: 254
    CreateKeyResponse:
      type: object
      required: [disclaimer, ok]
      properties:
        disclaimer: { type: string }
        ok: { type: boolean }
        api_key: { type: string }
        tier:
          type: string
          enum: [free]
        monthly_limit: { type: integer }
        message: { type: string }
    MonitorRequest:
      type: object
      required: [asset_type, jurisdiction]
      properties:
        asset_type:
          type: string
          enum: [real_estate, private_fund, bonds, private_credit, commodities, stablecoins, other]
        jurisdiction: { type: string }
        structure:
          type: string
          enum: [spv, fund, trust, other]
          default: spv
        webhook_url: { type: string, format: uri }
        email: { type: string, format: email }
        alert_on:
          type: array
          items:
            type: string
            enum: [score_change, regulation_update, new_requirement, deadline_approaching]
        baseline_score: { type: integer, minimum: 0, maximum: 100 }
    MonitorResponse:
      type: object
      properties:
        disclaimer: { type: string }
        id: { type: string }
        status: { type: string, enum: [active, paused] }
        asset_type: { type: string }
        jurisdiction: { type: string }
        structure: { type: string }
        alert_on:
          type: array
          items: { type: string }
        webhook_url: { type: string, nullable: true }
        created_at: { type: string, format: date-time }
        pricing: { type: object }
    DossierRequest:
      type: object
      properties:
        score_id: { type: string }
        score:
          $ref: "#/components/schemas/ScoreRequest"
        format:
          type: string
          enum: [pdf, json, zip]
          default: pdf
        sections:
          type: array
          items: { type: string }
        branding:
          type: object
          properties:
            company_name: { type: string }
            logo_url: { type: string, format: uri }
        locale:
          type: string
          enum: [fr, en, es]
    DossierResponse:
      type: object
      properties:
        disclaimer: { type: string }
        dossier_id: { type: string }
        format: { type: string }
        download_url: { type: string, format: uri }
        expires_in_hours: { type: integer }
        full_report_url: { type: string, format: uri }
    WebhookRegisterRequest:
      type: object
      required: [url]
      properties:
        url: { type: string, format: uri }
        events:
          type: array
          items:
            type: string
            enum:
              - score_change
              - regulation_update
              - new_requirement
              - deadline_approaching
              - regulatory.update
    WebhookDelivery:
      type: object
      properties:
        id: { type: string }
        webhook_id: { type: string, nullable: true }
        event: { type: string }
        status:
          type: string
          enum: [pending, delivered, failed, dead_letter]
        attempts: { type: integer }
        last_error: { type: string, nullable: true }
        created_at: { type: string, format: date-time }
        next_retry_at: { type: string, format: date-time, nullable: true }
        delivered_at: { type: string, format: date-time, nullable: true }
        url: { type: string, format: uri }
    WebhookDeliveriesResponse:
      type: object
      properties:
        webhook_id: { type: string }
        deliveries:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDelivery"
        total: { type: integer }
        limit: { type: integer }
        offset: { type: integer }
    WebhookReplayRequest:
      type: object
      properties:
        delivery_id: { type: string }
    WebhookReplayResponse:
      type: object
      properties:
        delivery:
          $ref: "#/components/schemas/WebhookDelivery"
        ok: { type: boolean }
    RegulatoryFeedItem:
      type: object
      required: [id, title, source, jurisdiction, published_at, url, summary, tags]
      properties:
        id: { type: string }
        title: { type: string }
        source:
          type: string
          enum: [ESMA, AMF, BaFin, EC, EBA]
        jurisdiction: { type: string }
        published_at: { type: string, format: date }
        url: { type: string, format: uri }
        summary: { type: string }
        tags:
          type: array
          items:
            type: string
            enum: [mica, esma, amf, bafin]
        severity:
          type: string
          enum: [low, medium, high]
        event_type:
          type: string
          enum: [regulation_update, new_requirement, deadline_approaching]
        deadline: { type: string, nullable: true }
    RegulatoryFeedResponse:
      type: object
      properties:
        disclaimer: { type: string }
        last_updated: { type: string, format: date }
        total: { type: integer }
        items:
          type: array
          items:
            $ref: "#/components/schemas/RegulatoryFeedItem"
        meta:
          type: object
          properties:
            version: { type: string }
            source: { type: string, example: curated }
            note: { type: string }
    RegulatorySubscribeRequest:
      type: object
      properties:
        jurisdictions:
          type: array
          items: { type: string }
          minItems: 1
          default: [eu]
        tags:
          type: array
          items:
            type: string
            enum: [mica, esma, amf, bafin]
        webhook_url: { type: string, format: uri }
        email: { type: string, format: email }
    RegulatorySubscribeResponse:
      type: object
      properties:
        disclaimer: { type: string }
        id: { type: string }
        jurisdictions:
          type: array
          items: { type: string }
        tags:
          type: array
          items: { type: string }
        webhook_url: { type: string, nullable: true }
        events:
          type: array
          items:
            type: string
            enum: [regulatory.update]
        status: { type: string, enum: [active] }
        created_at: { type: string, format: date-time }
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ProtocolError"
          example:
            disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
            error:
              code: unauthorized
              message: "Invalid API key"
    ValidationError:
      description: Invalid request parameters or body
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ProtocolError"
    RateLimit:
      description: Rate limit or monthly quota exceeded
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
            example: 100
        X-RateLimit-Remaining:
          schema:
            type: integer
            example: 0
        X-RateLimit-Reset:
          schema:
            type: integer
            description: Unix timestamp when the limit window resets
            example: 1751328000
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ProtocolError"
          example:
            disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
            error:
              code: quota_exceeded
              message: "Monthly quota exceeded (100 requests/month on free tier)"
    PremiumRequired:
      description: Premium tier required (live key or paid plan)
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ProtocolError"
          example:
            disclaimer: "Indicative intelligence only — not legal, tax, or investment advice."
            error:
              code: premium_required
              message: "Endpoint réservé au tier premium. Utilisez une clé auros_pk_live_*."
