openapi: "3.1.0"
info:
  title: Dike Legal Search
  description: |
    Verified MENA legal search, grounded Q&A, citation resolution, and legal
    citation-graph traversal over Saudi, Egyptian, and Emirati primary legal
    sources. Every citation returned by /reason resolves against the actual
    corpus, unresolved references are dropped rather than shown, so answers
    never include a fabricated case number or statute.
  version: "1.0.0"

servers:
  - url: https://api.dike.it.com
    description: Production

security:
  - bearerAuth: []

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: Dike API key. Get one at https://dike.it.com/developers/

  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
    NotFound:
      description: Resource not found
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
    UnprocessableEntity:
      description: Validation error
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
    UpstreamUnavailable:
      description: Upstream dependency unavailable
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"

  schemas:
    Problem:
      type: object
      description: RFC 7807 problem+json error
      required: [type, title, status, code]
      properties:
        type:
          type: string
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        code:
          type: string
          description: Stable machine-readable error code

    SearchFilters:
      type: object
      properties:
        doc_type:
          type: array
          items:
            type: string
            enum: [legislation, case_law, fatwa, regulation, decree]
        jurisdiction:
          type: string
          enum: [EG, SA]
        year_from:
          type: integer
          minimum: 1800
        year_to:
          type: integer
          maximum: 2100
        status:
          type: array
          items:
            type: string
            enum: [in_force, amended, repealed, unknown]

    SearchRequest:
      type: object
      required: [query]
      properties:
        query:
          type: string
          minLength: 1
          example: "مسؤولية الناقل الجوي عن تأخير الرحلات"
        top_k:
          type: integer
          default: 10
          minimum: 1
          maximum: 50
        filters:
          $ref: "#/components/schemas/SearchFilters"

    SearchResult:
      type: object
      properties:
        canonical_id:
          type: string
        score:
          type: number
        doc_type:
          type: string
        title:
          type: string
        article_no:
          type: string
        snippet:
          type: string
          maxLength: 800
        year:
          type: integer
        status:
          type: string
        citation_string:
          type: string

    SearchResponse:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: "#/components/schemas/SearchResult"
        took_ms:
          type: integer

    ReasonRequest:
      type: object
      required: [question]
      properties:
        question:
          type: string
          minLength: 1
          example: "هل يجوز فسخ عقد الإيجار لتأخر المستأجر عن السداد؟"
        filters:
          $ref: "#/components/schemas/SearchFilters"
        top_k:
          type: integer
          default: 12
          minimum: 1
          maximum: 50
        language:
          type: string
          default: ar
          enum: [ar, en]

    CitationMarker:
      type: object
      properties:
        marker:
          type: integer
        canonical_id:
          type: string
        article_no:
          type: string
        citation_string:
          type: string
        snippet:
          type: string
        verified:
          type: boolean

    ReasonGrounding:
      type: object
      properties:
        retrieved:
          type: integer
        used:
          type: integer
        dropped_unverified_refs:
          type: integer
          description: References the model attempted to cite that did not resolve against the retrieved documents, and were removed before this answer was returned.

    ReasonResponse:
      type: object
      properties:
        answer:
          type: string
        citations:
          type: array
          items:
            $ref: "#/components/schemas/CitationMarker"
        grounding:
          $ref: "#/components/schemas/ReasonGrounding"

    CiteRequest:
      type: object
      required: [citation]
      properties:
        citation:
          type: string
          minLength: 1
          example: "القانون رقم 131 لسنة 1948"

    ParsedCitation:
      type: object
      properties:
        doc_type:
          type: string
        number:
          type: string
        year:
          type: integer
        article_no:
          type: string
        chamber:
          type: string
        canonical_id:
          type: string

    ResolvedDocument:
      type: object
      properties:
        canonical_id:
          type: string
        doc_type:
          type: string
        jurisdiction:
          type: string
        title:
          type: string
        official_number:
          type: string
        year_gregorian:
          type: integer
        status:
          type: string
        issuing_body:
          type: string
        full_text:
          type: string

    CiteResponse:
      type: object
      properties:
        parsed:
          $ref: "#/components/schemas/ParsedCitation"
        document:
          $ref: "#/components/schemas/ResolvedDocument"
          description: Present when the citation resolves to a known document

    GraphTraverseRequest:
      type: object
      required: [canonical_id, direction]
      properties:
        canonical_id:
          type: string
          example: "eg-leg-1948-131"
        direction:
          type: string
          enum: [in, out, both]
        edge_types:
          type: array
          items:
            type: string
            enum: [cites, amends, repeals, implements, interprets]
        depth:
          type: integer
          default: 1
          minimum: 1
          maximum: 3
        limit:
          type: integer
          default: 100
          minimum: 1
          maximum: 100

    GraphNode:
      type: object
      properties:
        canonical_id:
          type: string
        title:
          type: string
        doc_type:
          type: string
        year:
          type: integer
        status:
          type: string

    GraphEdge:
      type: object
      properties:
        from_id:
          type: string
        to_id:
          type: string
        edge_type:
          type: string
        article_ref:
          type: string
        confidence:
          type: number

    GraphTraverseResponse:
      type: object
      properties:
        nodes:
          type: array
          items:
            $ref: "#/components/schemas/GraphNode"
        edges:
          type: array
          items:
            $ref: "#/components/schemas/GraphEdge"

paths:
  /v1/jurisdictions:
    get:
      operationId: listJurisdictions
      summary: List the legal corpora this instance serves
      responses:
        "200":
          description: Available jurisdictions
          content:
            application/json:
              schema:
                type: object
                properties:
                  jurisdictions:
                    type: array
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                        name:
                          type: string
                        default:
                          type: boolean
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/document/{canonical_id}:
    get:
      operationId: getDocument
      summary: Fetch a single legal document by its canonical ID
      description: Use after search, reason, or cite to hydrate a canonical_id into the complete document text.
      parameters:
        - name: canonical_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: The document
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResolvedDocument"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "503":
          $ref: "#/components/responses/UpstreamUnavailable"

  /v1/search:
    post:
      operationId: searchLegalCorpus
      summary: Hybrid semantic and lexical search over MENA legal sources
      description: Returns ranked statutes, regulations, and case law matching a natural-language query, with citation strings for every result.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchRequest"
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SearchResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "503":
          $ref: "#/components/responses/UpstreamUnavailable"

  /v1/reason:
    post:
      operationId: reasonOverLegalCorpus
      summary: Answer a legal question with verified citations
      description: |
        Retrieves relevant legal text, then answers using only that retrieved
        context. Every citation in the answer has already been checked against
        the retrieved documents, unverified references are dropped before the
        answer is returned, never shown as a guess. Always returns a single
        JSON response (never a streaming response).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReasonRequest"
      responses:
        "200":
          description: Grounded answer with verified citations
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReasonResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "503":
          $ref: "#/components/responses/UpstreamUnavailable"

  /v1/cite:
    post:
      operationId: resolveCitation
      summary: Parse and resolve an Arabic legal citation string
      description: Supports legislation, ministerial/presidential decrees, cassation rulings, and fatawa citation formats.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CiteRequest"
      responses:
        "200":
          description: Parsed citation with resolved document, when found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CiteResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"

  /v1/graph/traverse:
    post:
      operationId: traverseLegalGraph
      summary: Traverse the legal citation graph from a document
      description: Finds documents that cite, amend, repeal, implement, or interpret a given document, up to 3 levels deep.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GraphTraverseRequest"
      responses:
        "200":
          description: Graph nodes and edges
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GraphTraverseResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
        "503":
          $ref: "#/components/responses/UpstreamUnavailable"
