{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "Invoice.json",
  "title": "Invoice",
  "description": "An invoice raised into the organization's approval workflow.",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "format": "int32",
      "description": "Flux's id for the invoice."
    },
    "number": {
      "type": "string",
      "description": "The invoice number. Its format depends on the organization's settings: treat it as an opaque string."
    },
    "externalRef": {
      "type": [
        "string",
        "null"
      ],
      "description": "Your reference, if you sent one."
    },
    "customerId": {
      "type": "integer",
      "format": "int32",
      "description": "The customer billed."
    },
    "currency": {
      "type": "string",
      "enum": [
        "NGN",
        "USD",
        "CAD",
        "EUR",
        "GBP"
      ],
      "description": "ISO currency code."
    },
    "status": {
      "type": "string",
      "enum": [
        "awaiting_approval",
        "awaiting_final_approval",
        "returned",
        "approved",
        "paid",
        "voided"
      ],
      "description": "Where the invoice is in its lifecycle."
    },
    "overdue": {
      "type": "boolean",
      "description": "Derived: approved, unpaid, not voided and past dueDate."
    },
    "paymentStatus": {
      "type": [
        "string",
        "null"
      ],
      "description": "A note set by payment processing, such as successful or refunded: NGN 1,000.00. Display it; don't branch on it."
    },
    "invoiceType": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "setup",
        "build",
        "subscription",
        "usage",
        "performance",
        "mixed",
        "other",
        null
      ],
      "description": "The kind of invoice."
    },
    "periodStart": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T00:00:00$",
      "description": "Start of the billing period."
    },
    "periodEnd": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T00:00:00$",
      "description": "End of the billing period."
    },
    "nextDueDate": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T00:00:00$",
      "description": "When the next cycle's invoice is due. Informational."
    },
    "createdAt": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$",
      "description": "When the invoice was raised. Server time, no offset."
    },
    "approvedAt": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$",
      "description": "When it was fully approved."
    },
    "dueDate": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T00:00:00$",
      "description": "When payment is due."
    },
    "paidAt": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$",
      "description": "When it was paid."
    },
    "subtotal": {
      "type": "number",
      "format": "decimal",
      "description": "Sum of the lines."
    },
    "discount": {
      "type": "number",
      "format": "decimal",
      "description": "Discount on the subtotal."
    },
    "taxableNet": {
      "type": "number",
      "format": "decimal",
      "description": "Amount VAT is charged on."
    },
    "vatAmount": {
      "type": "number",
      "format": "decimal",
      "description": "VAT charged, from the organization's VAT setting."
    },
    "vatLabel": {
      "type": [
        "string",
        "null"
      ],
      "description": "How the VAT line is labelled, such as VAT (7.5%). Comes from the organization's VAT setting."
    },
    "total": {
      "type": "number",
      "format": "decimal",
      "description": "Amount the customer pays."
    },
    "lines": {
      "type": "array",
      "items": {
        "$ref": "InvoiceLine.json"
      },
      "description": "The invoice lines."
    },
    "payments": {
      "type": [
        "array",
        "null"
      ],
      "items": {
        "$ref": "Payment.json"
      },
      "description": "Online payment attempts. Set only by GET /invoices/{id} when the key has payments:read; null everywhere else."
    }
  },
  "required": [
    "id",
    "number",
    "externalRef",
    "customerId",
    "currency",
    "status",
    "overdue",
    "paymentStatus",
    "invoiceType",
    "periodStart",
    "periodEnd",
    "nextDueDate",
    "createdAt",
    "approvedAt",
    "dueDate",
    "paidAt",
    "subtotal",
    "discount",
    "taxableNet",
    "vatAmount",
    "vatLabel",
    "total",
    "lines",
    "payments"
  ],
  "examples": [
    {
      "id": 5012,
      "number": "MAX-2026-0042",
      "externalRef": "ws_42-2026-11",
      "customerId": 812,
      "currency": "NGN",
      "status": "approved",
      "overdue": false,
      "paymentStatus": null,
      "invoiceType": "subscription",
      "periodStart": "2026-11-01T00:00:00",
      "periodEnd": "2026-11-30T00:00:00",
      "nextDueDate": "2026-12-01T00:00:00",
      "createdAt": "2026-11-01T09:00:00",
      "approvedAt": "2026-11-01T11:30:00",
      "dueDate": "2026-11-15T00:00:00",
      "paidAt": null,
      "subtotal": 800000,
      "discount": 0,
      "taxableNet": 800000,
      "vatAmount": 60000,
      "vatLabel": "VAT (7.5%)",
      "total": 860000,
      "lines": [
        {
          "serviceId": 7,
          "description": "Subscription — 3 entities (3 × 250,000.00)",
          "detail": "3 entities",
          "quantity": 3,
          "unitPrice": 250000,
          "amount": 750000
        },
        {
          "serviceId": 9,
          "description": "Onboarding",
          "detail": null,
          "quantity": 1,
          "unitPrice": 50000,
          "amount": 50000
        }
      ],
      "payments": [
        {
          "reference": "T12-MAX-2026-0042-K3P9QZ_1",
          "channel": "paystack",
          "succeeded": false,
          "attemptedAt": "2026-11-02T08:15:00"
        }
      ]
    }
  ]
}
