openapi: 3.1.0
info:
  title: Geelab fp_query Server API
  version: 1.0.0
  summary: Query fingerprint Data with a device_token from the client SDK.
  description: |
    Canonical machine-readable contract for `POST /api/v2/fp_query/{public_key}`.
    Human-readable documentation: /zh/docs/device-fingerprint/v2/start/server-api

    Obtain `public_key` and Bearer `secret` from the backend.
    Obtain `device_token` from the client SDK.
  contact:
    name: Geelab
servers:
  - url: https://{host}
    variables:
      host:
        default: localhost
        description: Host of the app's region (GLB / NA / EU). Wrong region returns 404.
paths:
  /api/v2/fp_query/{public_key}:
    post:
      operationId: queryFp
      tags: [fp_query]
      summary: Query fingerprint Data with a device_token
      description: Query device fingerprint for iOS, Android, or Web/H5. Returns request_id, event_id, fp_detail, signals, detail. Send the request to the app's region (GLB / NA / EU).
      security:
        - bearerSecret: []
      parameters:
        - $ref: "#/components/parameters/PublicKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/FpQueryRequest"
            examples:
              minimal:
                summary: Query with token only
                value:
                  device_token: from-client-sdk
              withContext:
                summary: Token plus metadata and event
                value:
                  device_token: from-client-sdk
                  metadata:
                    account_id: account-001
                    phone_num: "+8613800000000"
                    email: user@example.com
                  event_type: login
                  event_time: "2026-08-20T10:30:00+08:00"
      responses:
        "200":
          description: Success. HTTP status equals body.code.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FpQuerySuccessEnvelope"
              examples:
                android:
                  $ref: "#/components/examples/SuccessAndroid"
        "400":
          description: Invalid request or invalid device_token.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
              examples:
                missingField:
                  value:
                    code: 400
                    data:
                      errors:
                        - field: device_token
                          reason: Field required
                          type: missing
                    message: Invalid request
                invalidToken:
                  value:
                    code: 400
                    data:
                      errors:
                        - field: device_token
                          reason: Invalid token
                          type: value_error
                    message: Invalid request
        "401":
          description: Authentication failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
              example:
                code: 401
                data: {}
                message: Invalid bearer token
        "403":
          description: Resource disabled/deleted, or IP allowlist failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
              example:
                code: 403
                data: {}
                message: Forbidden
        "404":
          description: Unknown public_key, or request sent to a host in the wrong region.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
              example:
                code: 404
                data: {}
                message: integration not found
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorEnvelope"
              example:
                code: 500
                data: {}
                message: Internal server error
components:
  securitySchemes:
    bearerSecret:
      type: http
      scheme: bearer
      bearerFormat: secret
      description: Secret issued in the backend. public_key is not the secret.
  parameters:
    PublicKey:
      name: public_key
      in: path
      required: true
      schema:
        type: string
        minLength: 1
      description: Application public identifier issued in the backend. Not the Bearer secret.
  schemas:
    FpQueryRequest:
      type: object
      additionalProperties: false
      required: [device_token]
      properties:
        device_token:
          type: string
          minLength: 1
          description: Token from the client SDK.
        metadata:
          $ref: "#/components/schemas/FpQueryMetadata"
          default: {}
        event_type:
          type: string
          description: Opaque business event type. No enum.
        event_time:
          type: string
          format: date-time
          description: RFC 3339 with timezone or Z.
    FpQueryMetadata:
      type: object
      additionalProperties: true
      description: Optional business context. All known keys are strings.
      properties:
        account_id: { type: string }
        phone_num: { type: string }
        phone_sha256: { type: string }
        phone_country_code: { type: string }
        phone_prefix: { type: string }
        email: { type: string }
        email_sha256: { type: string }
        email_domain: { type: string }
        ip_addr_v4: { type: string }
        ip_addr_v6: { type: string }
        user_agent: { type: string }
        ja3: { type: string }
        ja4: { type: string }
        mac_prefix: { type: string }
        wifi_bssid_prefix: { type: string }
        tls_cipher: { type: string }
    FpQuerySuccessEnvelope:
      type: object
      additionalProperties: false
      required: [code, data, message]
      properties:
        code:
          type: integer
          const: 200
        message:
          type: string
          const: Success
        data:
          $ref: "#/components/schemas/FpQueryData"
    FpQueryData:
      type: object
      additionalProperties: false
      required: [request_id, event_id, fp_detail, signals, detail]
      properties:
        request_id:
          type: string
          pattern: "^req_.+"
          description: Analysis id. Stable across repeat queries of the same device_token.
        event_id:
          type: string
          pattern: "^evt_.+"
          description: Per-query id. Same device_token yields a new event_id on each call.
        fp_detail:
          $ref: "#/components/schemas/FpDetail"
        signals:
          type: array
          items:
            $ref: "#/components/schemas/Signal"
        detail:
          $ref: "#/components/schemas/Detail"
    FpDetail:
      type: object
      additionalProperties: false
      required: [device_id, version]
      properties:
        device_id:
          type: string
        version:
          type: string
          description: Fingerprint version. Literal "1.0"
    Signal:
      type: object
      additionalProperties: false
      required: [signal, level, confidence]
      properties:
        signal:
          type: string
          description: Signal identifier. See docs/api/signals.md.
        level:
          type: string
          enum: [LOW, MEDIUM, HIGH]
          description: Per-signal intensity. LOW, MEDIUM, or HIGH.
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Per-signal confidence in 0.0-1.0.
    Detail:
      type: object
      required: [client_type, ip_info]
      properties:
        client_type:
          type: string
          enum: [Android, iOS, Web/H5]
          description: Android | iOS | Web/H5
        device_basic:
          description: Present for Android, iOS, and Web/H5.
          oneOf:
            - $ref: "#/components/schemas/NativeDeviceBasic"
            - $ref: "#/components/schemas/WebDeviceBasic"
        ip_info:
          $ref: "#/components/schemas/IpInfo"
    NativeDeviceBasic:
      type: object
      additionalProperties: false
      required: [os, pla, mod, osv]
      properties:
        os: { type: string }
        pla: { type: string }
        mod: { type: string }
        osv: { type: string }
    WebDeviceBasic:
      type: object
      additionalProperties: false
      required: [browser, device, os]
      properties:
        browser: { type: object, additionalProperties: true }
        device: { type: object, additionalProperties: true }
        os: { type: object, additionalProperties: true }
    IpInfo:
      type: object
      additionalProperties: false
      required: [ip]
      properties:
        ip: { type: string }
    ErrorEnvelope:
      type: object
      additionalProperties: false
      required: [code, data, message]
      properties:
        code:
          type: integer
          enum: [400, 401, 403, 404, 500]
        message:
          type: string
          enum:
            - Invalid request
            - Invalid bearer token
            - Forbidden
            - integration not found
            - Internal server error
        data:
          oneOf:
            - type: object
              additionalProperties: false
            - $ref: "#/components/schemas/ValidationErrorData"
    ValidationErrorData:
      type: object
      additionalProperties: false
      required: [errors]
      properties:
        errors:
          type: array
          items:
            $ref: "#/components/schemas/FieldError"
    FieldError:
      type: object
      additionalProperties: false
      required: [field, reason, type]
      properties:
        field: { type: string }
        reason: { type: string }
        type: { type: string }
  examples:
    SuccessAndroid:
      summary: Android Data
      value:
        code: 200
        message: Success
        data:
          request_id: req_0198c7a1-5b2e-7c10-8d44-1234567890ab
          event_id: evt_0198c7a1-5b2e-7c10-8d44-1234567890ab
          fp_detail:
            device_id: GEE4-xxxxxx
            version: "1.0"
          signals:
            - signal: CLOUD_PHONE
              level: HIGH
              confidence: 0.8
          detail:
            client_type: Android
            device_basic:
              os: Android
              pla: arm64-v8a
              mod: Pixel 8
              osv: "14"
            ip_info:
              ip: 1.1.1.1
tags:
  - name: fp_query
    description: Server-side fingerprint query
