openapi: 3.1.0
info:
  title: Tango Project Invoice Inbound (Payment Confirmation) API
  version: "0.9"
  description: |
    Async REST API for updating invoice **payment confirmation** details in Tango.
    Client posts payment records; Tango updates the Payments tab under Projects →
    Costs → Payments. Either `inv_id` (Tango ID) or `inv_number` must identify
    the invoice. Status polled via the shared `/v1/batch/status` endpoint.
  x-direction: inbound
  x-source: Client System
  x-destination: Tango
servers:
  - url: https://api.tangoanalytics.com
    description: Production
  - url: https://testapi.tangoanalytics.com
    description: Test (SIT/UAT)
tags:
  - name: Invoice Payments
  - name: Status
paths:
  /v1/projectmgmt/batch/invoicepayments:
    put:
      summary: Submit invoice payment confirmations (async)
      operationId: putInvoicePaymentsBatch
      tags: [Invoice Payments]
      parameters:
        - $ref: "#/components/parameters/XClient"
        - $ref: "#/components/parameters/XApiKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvoicePaymentBatchRequest"
            examples:
              default:
                value:
                  records:
                    - inv_number: "INV-1234"
                      inv_id: "78968"
                      payment_number: "PAY-2344"
                      invoice_amount: 3000.34
                      status: "PAID"
                      payment_method: "CHECK"
                      payment_reference: "23456775443"
                      payment_date: "03/14/2021"
                      payment_amount: 3000.34
                      comments: "good"
      responses:
        "200":
          description: Accepted for async processing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AcceptedResponse"
  /v1/batch/status:
    get:
      summary: Poll processing status by gu_id
      operationId: getBatchStatus
      tags: [Status]
      parameters:
        - $ref: "#/components/parameters/XClient"
        - $ref: "#/components/parameters/XApiKey"
        - in: query
          name: gu_id
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Status payload.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StatusResponse"
components:
  securitySchemes:
    xClientHeader:
      type: apiKey
      in: header
      name: x-client
    xApiKeyHeader:
      type: apiKey
      in: header
      name: x-api-key
  parameters:
    XClient:
      name: x-client
      in: header
      required: true
      schema:
        type: string
    XApiKey:
      name: x-api-key
      in: header
      required: true
      schema:
        type: string
  schemas:
    InvoicePaymentBatchRequest:
      type: object
      required: [records]
      properties:
        records:
          type: array
          items:
            $ref: "#/components/schemas/InvoicePaymentRecord"
    InvoicePaymentRecord:
      type: object
      description: |
        Either `inv_id` OR `inv_number` must be supplied to identify the invoice.
        OAS 3.1 cannot natively express XOR-required fields; both are listed as
        optional, and the runtime validation rule appears in the source doc and
        Open Questions.
      required:
        - payment_number
        - status
        - payment_date
        - payment_amount
      properties:
        inv_number:
          type: string
          description: Client's invoice number (one of inv_id / inv_number required).
        inv_id:
          type: number
          description: Tango's unique Invoice ID (one of inv_id / inv_number required).
        payment_number:
          type: string
        invoice_amount:
          type: number
        status:
          type: string
          enum: [PAID, VOID]
          description: Default value `PAID`/`VOID`.
        payment_method:
          type: string
          description: Source lists as optional but validation #4 requires it; flagged in Open Questions.
        payment_reference:
          type: string
        payment_date:
          type: string
          description: "Format MM/DD/YYYY."
          example: "03/14/2021"
        payment_amount:
          type: number
        comments:
          type: string
    AcceptedResponse:
      type: object
      required: [status, gu_id]
      properties:
        status:
          type: string
          enum: [OK, Error]
        status_message:
          type: string
        gu_id:
          type: string
          format: uuid
    StatusResponse:
      oneOf:
        - type: object
          properties:
            status: { type: string, const: PROCESSING }
        - type: object
          required: [status, total_records]
          properties:
            status: { type: string, const: COMPLETED }
            total_records: { type: integer }
            errors: { type: 'null' }
        - type: object
          required: [status, total_records, errors]
          properties:
            status: { type: string, const: ERROR }
            total_records: { type: integer }
            errors:
              type: array
              items:
                type: object
                required: [record_index, error]
                properties:
                  record_index: { type: integer }
                  record_key:
                    oneOf:
                      - { type: string }
                      - { type: integer }
                  error: { type: string }
security:
  - xClientHeader: []
    xApiKeyHeader: []
