openapi: 3.0.3
info:
  title: Pristo Public API
  version: "1.0.0"
  description: >
    Pristo Public API (V1).
    All external integrations are based on client-owned identifiers.
    Internal Pristo identifiers are never exposed.
servers:
  - url: https://api.pristo.io
    description: Production

tags:
  - name: Contacts
    description: Contacts management
  - name: Events
    description: Events ingestion

security:
  - ApiKeyAuth: []

paths:
  /v1/populations/{populationId}/contacts:
    post:
      tags: [Contacts]
      summary: Create or update a contact
      description: >
        Creates or updates a contact using a **client-owned identifier**.

        The `contact.id` field is mandatory and represents the identifier
        used by the client system.

        Optional fields (email, phone, language, name, etc.)
        will update the existing contact if provided.

        Additional properties are treated as dynamic fields.
      operationId: upsertContact
      parameters:
        - $ref: "#/components/parameters/populationId"
        - $ref: "#/components/parameters/requestIdHeader"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ContactUpsertRequest"
            examples:
              example:
                value:
                  contact:
                    id: "3fa85f64-5717-4562-b3fc-2c963f66afa6"
                    email: "dana@example.com"
                    phone: "+972501234567"
                    language: "he"
                    name: "Dana Cohen"
                    age: "34"
      responses:
        "200":
          description: Contact updated
          headers:
            X-Request-Id:
              $ref: "#/components/headers/requestId"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactResponse"
        "201":
          description: Contact created
          headers:
            X-Request-Id:
              $ref: "#/components/headers/requestId"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContactResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
        "500":
          $ref: "#/components/responses/ServerError"

  /v1/sendEvent/{populationId}:
    post:
      tags: [Events]
      summary: Send an event
      description: >
        Sends an event associated with a contact.

        The request must include `contact.id`, which is the client-owned
        contact identifier.

        Optional contact fields may be provided to enrich or update
        the contact data.

        The event requires a `type` and may optionally include `occurredAt`.

        Additional properties at the root level are treated as
        event dynamic fields.
      operationId: sendEvent
      parameters:
        - $ref: "#/components/parameters/populationId"
        - $ref: "#/components/parameters/requestIdHeader"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SendEventRequest"
            examples:
              example:
                value:
                  contact:
                    id: "3fa85f64-5717-4562-b3fc-2c963f66afa6"
                    email: "dana@example.com"
                    phone: "0545898777"
                    language: "en"
                  type: "purchase_completed"
                  occurredAt: "2026-02-04T13:25:00Z"
                  channel: "website"
                  amount: "135"
      responses:
        "201":
          description: Event stored
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SendEventResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
        "500":
          $ref: "#/components/responses/ServerError"

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key (UUID)

  parameters:
    populationId:
      name: populationId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Population identifier (UUID)

    requestIdHeader:
      name: X-Request-Id
      in: header
      required: false
      schema:
        type: string
        format: uuid
      description: Optional request correlation ID

  headers:
    requestId:
      schema:
        type: string
        format: uuid
      description: Request correlation ID

  responses:
    BadRequest:
      description: Validation error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

    RateLimited:
      description: Too many requests
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

    ServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

  schemas:
    IsoDateTime:
      type: string
      format: date-time

    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string

    Contact:
      type: object
      required: [id]
      properties:
        id:
          type: string
          format: uuid
          description: Client-owned contact identifier
        email:
          type: string
          format: email
        phone:
          type: string
        language:
          type: string
          description: ISO 639-1 language code (e.g. en, he)
        name:
          type: string
      additionalProperties:
        type: string
        maxLength: 255

    ContactUpsertRequest:
      type: object
      required: [contact]
      properties:
        contact:
          $ref: "#/components/schemas/Contact"

    ContactResponse:
      type: object
      properties:
        contact:
          $ref: "#/components/schemas/Contact"

    SendEventRequest:
      type: object
      required: [contact, type]
      properties:
        contact:
          $ref: "#/components/schemas/Contact"
        type:
          type: string
          description: Event type identifier
        occurredAt:
          $ref: "#/components/schemas/IsoDateTime"
      additionalProperties:
        type: string
        maxLength: 255

    SendEventResponse:
      type: object
      properties:
        eventId:
          type: string
          format: uuid
        receivedAt:
          $ref: "#/components/schemas/IsoDateTime"
