Spendesk · Schema

invoice

Full representation of an invoice, returned by the detail endpoint. A superset of `invoiceSummary`, adding line items, the tax breakdown, currency conversion (FX), the payment history, the approval chain, accounting links, attachments and custom fields.

Spend ManagementCorporate CardsExpense ManagementInvoicesProcurementFintechAccountingPayments

Properties

Name Type Description
id object
invoiceNumber stringnull Supplier's invoice/credit-note number. Null if not captured.
type object
description stringnull Free-text description/purpose of the invoice.
stage object
paymentStatus object
exportStatus object Null until the invoice has an accounting payable (see `payableId`) — an invoice pending approval has nothing to export yet, which is distinct from `pending` (a payable exists but hasn't been exported)
dispute object Always null today, even if disputed (`stage` then shows `disputed`).
cancelledAt object When the invoice was cancelled/voided, or null if it is still active.
supplier object Null only on a draft (`stage` `pendingApproval`) with no supplier set yet.
purchaseOrders array Purchase orders this invoice is matched against (two/three-way match). Empty when the invoice references no PO. May hold several when one invoice consolidates multiple POs.
buyer object The internal member the invoice is assigned to (the buyer), or null.
costCenter object Cost center the invoice is coded to, or null when none is set. Set independently of `analyticalSplits`: the two are not reconciled and can disagree.
analyticalSplits array Allocation of the invoice total across cost centers and analytical-field values. Empty when the invoice is not split. Set independently of `costCenter`, so a split can name a different cost center.
expenseCategories array Expense categories the invoice is coded to, sorted by name. Empty when none is set. A split invoice can carry several, one per split. These ids are the ones the `expenseCategoryId` filter matches. Onl
lineItems array The invoice's line items — always at least one. A non-itemised invoice is represented as a single line covering the whole amount. Lines carry no accounting coding (see `costCenter` and `analyticalSpli
netAmount object Total before tax, in `currency`'s smallest unit. Can be null in any state, not only draft/incomplete: always for credit notes, and for older invoices whose net amount was never recorded.
taxAmount object Total tax, in `currency`'s smallest unit, derived as `grossAmount - netAmount` (not summed from `lineItems`). For the tax-by-rate breakdown (VAT-return view), group the line items by `taxRate`. Null w
grossAmount object Total amount including tax (`netAmount` + `taxAmount`), in `currency`'s smallest unit. Positive for invoices (owed to the supplier); negative for credit notes (owed to the company). Null when the invo
amountPaid object Amount settled so far, in `currency`'s smallest unit: the sum of `payments` with status `paid` in the invoice `currency` (returned payments and payments in another currency are excluded). When `paymen
amountDue object Outstanding balance still to be settled (`grossAmount` minus `amountPaid`), in `currency`'s smallest unit. Zero when fully paid. Null when `grossAmount` is not known yet (draft/incomplete).
currency object Null only on a draft (`stage` `pendingApproval`) with no currency set yet. Every amount on the invoice is then null too, because an amount can't be stated without its currency.
functionalAmount object `grossAmount` converted into the company entity's functional currency, in that currency's smallest unit. For accounting/reporting only — the supplier is paid `grossAmount` in `currency`, not this. Equ
functionalCurrency object The company entity's functional currency — its primary currency for accounting and reporting. Equals `currency` when no conversion is needed. Null until the invoice has an accounting payable (see `pay
functionalExchangeRate numbernull Rate used to convert `currency` into `functionalCurrency`, applied as `functionalAmount` is approximately `grossAmount x functionalExchangeRate`. 1 when both currencies match. Null until the invoice h
issueDate object Date the supplier issued the invoice, as printed on the document (emission date). Null only on a draft (`stage` `pendingApproval`) with no issue date set yet.
dueDate object Date by which the invoice must be paid, per the supplier's payment terms. Null when no due date is known.
accountingDate object Posting date — the date the invoice is booked in the accounting ledger, which fixes the fiscal period it falls into. May differ from `issueDate`. Null until the invoice has an accounting payable (see
payments array The payment history/plan. Empty until payments exist, and for older invoices not yet backfilled. `paymentStatus`, `amountPaid` and `amountDue` aggregate these entries, except when this array is empty,
approval object
review object Finance/controller review, or null if none has been recorded.
exportedAt object When the invoice was exported to the accounting system, or null if not exported.
documentaryEvidenceStatus object Null until the invoice has an accounting payable (see `payableId`) — there is nothing to attach evidence to yet for an invoice pending approval.
payableId stringnull Id of the accounting payable this invoice produced, resolvable via the payables API. Null until the invoice has passed approval/controller validation and a payable has been created — not merely "not y
attachments array Supporting files. Any without a download link is omitted, so may be partial.
createdAt object When the invoice record was created in Spendesk (ingest/submission time, not the issue date).
updatedAt object When any field on the invoice record last changed.
View JSON Schema on GitHub

JSON Schema

spendesk-invoice-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/api-evangelist/spendesk/main/json-schema/spendesk-invoice-schema.json",
  "title": "invoice",
  "description": "Full representation of an invoice, returned by the detail endpoint. A superset of `invoiceSummary`, adding line items, the tax breakdown, currency conversion (FX), the payment history, the approval chain, accounting links, attachments and custom fields.",
  "x-generated": "2026-10-14",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/spendesk-public-api-openapi.yml#/components/schemas/invoice",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "id": {
      "$ref": "#/$defs/invoiceId"
    },
    "invoiceNumber": {
      "type": [
        "string",
        "null"
      ],
      "description": "Supplier's invoice/credit-note number. Null if not captured."
    },
    "type": {
      "$ref": "#/$defs/invoiceType"
    },
    "description": {
      "type": [
        "string",
        "null"
      ],
      "description": "Free-text description/purpose of the invoice."
    },
    "stage": {
      "$ref": "#/$defs/invoiceStage"
    },
    "paymentStatus": {
      "$ref": "#/$defs/paymentStatus"
    },
    "exportStatus": {
      "oneOf": [
        {
          "$ref": "#/$defs/exportStatus"
        },
        {
          "type": "null"
        }
      ],
      "description": "Null until the invoice has an accounting payable (see `payableId`) — an invoice pending approval has nothing to export yet, which is distinct from `pending` (a payable exists but hasn't been exported)."
    },
    "dispute": {
      "oneOf": [
        {
          "$ref": "#/$defs/invoiceDispute"
        },
        {
          "type": "null"
        }
      ],
      "description": "Always null today, even if disputed (`stage` then shows `disputed`)."
    },
    "cancelledAt": {
      "oneOf": [
        {
          "$ref": "#/$defs/dateTime"
        },
        {
          "type": "null"
        }
      ],
      "description": "When the invoice was cancelled/voided, or null if it is still active."
    },
    "supplier": {
      "oneOf": [
        {
          "$ref": "#/$defs/supplierRef"
        },
        {
          "type": "null"
        }
      ],
      "description": "Null only on a draft (`stage` `pendingApproval`) with no supplier set yet."
    },
    "purchaseOrders": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/purchaseOrderRef"
      },
      "description": "Purchase orders this invoice is matched against (two/three-way match). Empty when the invoice references no PO. May hold several when one invoice consolidates multiple POs."
    },
    "buyer": {
      "oneOf": [
        {
          "$ref": "#/$defs/buyerRef"
        },
        {
          "type": "null"
        }
      ],
      "description": "The internal member the invoice is assigned to (the buyer), or null."
    },
    "costCenter": {
      "oneOf": [
        {
          "$ref": "#/$defs/costCenterRef"
        },
        {
          "type": "null"
        }
      ],
      "description": "Cost center the invoice is coded to, or null when none is set. Set independently of `analyticalSplits`: the two are not reconciled and can disagree."
    },
    "analyticalSplits": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/invoiceAnalyticalSplit"
      },
      "description": "Allocation of the invoice total across cost centers and analytical-field values. Empty when the invoice is not split. Set independently of `costCenter`, so a split can name a different cost center."
    },
    "expenseCategories": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/expenseCategoryRef"
      },
      "description": "Expense categories the invoice is coded to, sorted by name. Empty when none is set. A split invoice can carry several, one per split. These ids are the ones the `expenseCategoryId` filter matches. Only the company's current expense-category field counts: if it is changed or removed, past invoices follow the new setting. A deleted category still shows on the invoices coded to it."
    },
    "lineItems": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/lineItem"
      },
      "description": "The invoice's line items — always at least one. A non-itemised invoice is represented as a single line covering the whole amount. Lines carry no accounting coding (see `costCenter` and `analyticalSplits`); line `netAmount`/`taxAmount` sum to the header totals, except when the header total itself is null (draft/incomplete) while real captured line items exist."
    },
    "netAmount": {
      "oneOf": [
        {
          "$ref": "#/$defs/priceAmount"
        },
        {
          "type": "null"
        }
      ],
      "description": "Total before tax, in `currency`'s smallest unit. Can be null in any state, not only draft/incomplete: always for credit notes, and for older invoices whose net amount was never recorded."
    },
    "taxAmount": {
      "oneOf": [
        {
          "$ref": "#/$defs/priceAmount"
        },
        {
          "type": "null"
        }
      ],
      "description": "Total tax, in `currency`'s smallest unit, derived as `grossAmount - netAmount` (not summed from `lineItems`). For the tax-by-rate breakdown (VAT-return view), group the line items by `taxRate`. Null whenever `netAmount` or `grossAmount` is null, so in any state for credit notes and older invoices with no recorded net amount."
    },
    "grossAmount": {
      "oneOf": [
        {
          "$ref": "#/$defs/priceAmount"
        },
        {
          "type": "null"
        }
      ],
      "description": "Total amount including tax (`netAmount` + `taxAmount`), in `currency`'s smallest unit. Positive for invoices (owed to the supplier); negative for credit notes (owed to the company). Null when the invoice has no gross amount yet (draft/incomplete)."
    },
    "amountPaid": {
      "oneOf": [
        {
          "$ref": "#/$defs/priceAmount"
        },
        {
          "type": "null"
        }
      ],
      "description": "Amount settled so far, in `currency`'s smallest unit: the sum of `payments` with status `paid` in the invoice `currency` (returned payments and payments in another currency are excluded). When `payments` is empty, it comes from the stored payment status instead: `grossAmount` if `paid`, otherwise 0 (even when `partiallyPaid`). Always 0 on credit notes, which have no stored payment status and never aggregate `payments`. When `grossAmount` is not known yet, it is null if it comes from the stored status (empty `payments`, or a credit note), but is still summed from `payments` when they are recorded."
    },
    "amountDue": {
      "oneOf": [
        {
          "$ref": "#/$defs/priceAmount"
        },
        {
          "type": "null"
        }
      ],
      "description": "Outstanding balance still to be settled (`grossAmount` minus `amountPaid`), in `currency`'s smallest unit. Zero when fully paid. Null when `grossAmount` is not known yet (draft/incomplete)."
    },
    "currency": {
      "oneOf": [
        {
          "$ref": "#/$defs/currency"
        },
        {
          "type": "null"
        }
      ],
      "description": "Null only on a draft (`stage` `pendingApproval`) with no currency set yet. Every amount on the invoice is then null too, because an amount can't be stated without its currency."
    },
    "functionalAmount": {
      "oneOf": [
        {
          "$ref": "#/$defs/priceAmount"
        },
        {
          "type": "null"
        }
      ],
      "description": "`grossAmount` converted into the company entity's functional currency, in that currency's smallest unit. For accounting/reporting only — the supplier is paid `grossAmount` in `currency`, not this. Equal to `grossAmount` when the invoice is already in the functional currency. Null until the invoice has an accounting payable (see `payableId`) — this is not known before then, regardless of currency."
    },
    "functionalCurrency": {
      "oneOf": [
        {
          "$ref": "#/$defs/currency"
        },
        {
          "type": "null"
        }
      ],
      "description": "The company entity's functional currency — its primary currency for accounting and reporting. Equals `currency` when no conversion is needed. Null until the invoice has an accounting payable (see `payableId`)."
    },
    "functionalExchangeRate": {
      "type": [
        "number",
        "null"
      ],
      "description": "Rate used to convert `currency` into `functionalCurrency`, applied as `functionalAmount` is approximately `grossAmount x functionalExchangeRate`. 1 when both currencies match. Null until the invoice has an accounting payable (see `payableId`)."
    },
    "issueDate": {
      "oneOf": [
        {
          "$ref": "#/$defs/date"
        },
        {
          "type": "null"
        }
      ],
      "description": "Date the supplier issued the invoice, as printed on the document (emission date). Null only on a draft (`stage` `pendingApproval`) with no issue date set yet."
    },
    "dueDate": {
      "oneOf": [
        {
          "$ref": "#/$defs/date"
        },
        {
          "type": "null"
        }
      ],
      "description": "Date by which the invoice must be paid, per the supplier's payment terms. Null when no due date is known."
    },
    "accountingDate": {
      "oneOf": [
        {
          "$ref": "#/$defs/date"
        },
        {
          "type": "null"
        }
      ],
      "description": "Posting date — the date the invoice is booked in the accounting ledger, which fixes the fiscal period it falls into. May differ from `issueDate`. Null until the invoice has an accounting payable (see `payableId`). Not the export date; see `exportedAt`."
    },
    "payments": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/payment"
      },
      "description": "The payment history/plan. Empty until payments exist, and for older invoices not yet backfilled. `paymentStatus`, `amountPaid` and `amountDue` aggregate these entries, except when this array is empty, where they come from the stored payment status, and on credit notes, which have no stored payment status and always report `unpaid`."
    },
    "approval": {
      "$ref": "#/$defs/approval"
    },
    "review": {
      "oneOf": [
        {
          "$ref": "#/$defs/review"
        },
        {
          "type": "null"
        }
      ],
      "description": "Finance/controller review, or null if none has been recorded."
    },
    "exportedAt": {
      "oneOf": [
        {
          "$ref": "#/$defs/dateTime"
        },
        {
          "type": "null"
        }
      ],
      "description": "When the invoice was exported to the accounting system, or null if not exported."
    },
    "documentaryEvidenceStatus": {
      "oneOf": [
        {
          "$ref": "#/$defs/documentaryEvidenceStatus"
        },
        {
          "type": "null"
        }
      ],
      "description": "Null until the invoice has an accounting payable (see `payableId`) — there is nothing to attach evidence to yet for an invoice pending approval."
    },
    "payableId": {
      "type": [
        "string",
        "null"
      ],
      "format": "uuid",
      "description": "Id of the accounting payable this invoice produced, resolvable via the payables API. Null until the invoice has passed approval/controller validation and a payable has been created — not merely \"not yet booked\" in the accounting sense. One invoice maps to exactly one payable — line items and cost/analytical splits are allocations within that payable, not separate payables; a credit note is a separate document with its own payable.",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
    },
    "attachments": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/invoiceAttachment"
      },
      "description": "Supporting files. Any without a download link is omitted, so may be partial."
    },
    "createdAt": {
      "allOf": [
        {
          "$ref": "#/$defs/dateTime"
        }
      ],
      "description": "When the invoice record was created in Spendesk (ingest/submission time, not the issue date)."
    },
    "updatedAt": {
      "allOf": [
        {
          "$ref": "#/$defs/dateTime"
        }
      ],
      "description": "When any field on the invoice record last changed."
    }
  },
  "required": [
    "id",
    "invoiceNumber",
    "type",
    "description",
    "stage",
    "paymentStatus",
    "exportStatus",
    "dispute",
    "cancelledAt",
    "supplier",
    "purchaseOrders",
    "buyer",
    "costCenter",
    "analyticalSplits",
    "expenseCategories",
    "lineItems",
    "netAmount",
    "taxAmount",
    "grossAmount",
    "amountPaid",
    "amountDue",
    "currency",
    "functionalAmount",
    "functionalCurrency",
    "functionalExchangeRate",
    "issueDate",
    "dueDate",
    "accountingDate",
    "payments",
    "approval",
    "review",
    "exportedAt",
    "documentaryEvidenceStatus",
    "payableId",
    "attachments",
    "createdAt",
    "updatedAt"
  ],
  "$defs": {
    "analyticalProperty": {
      "type": "object",
      "additionalProperties": false,
      "description": "A value set for one analytical field. Analytical fields are the customer's own bookkeeping dimensions (custom fields) — e.g. project, team — used to classify and report spend. `valueId`/`valueName` are null when the field applies but no value is selected.",
      "properties": {
        "fieldId": {
          "type": "string"
        },
        "fieldName": {
          "type": "string"
        },
        "valueId": {
          "type": [
            "string",
            "null"
          ]
        },
        "valueName": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "fieldId",
        "fieldName",
        "valueId",
        "valueName"
      ],
      "title": "analyticalProperty"
    },
    "approval": {
      "type": "object",
      "additionalProperties": false,
      "description": "Detail of the approval workflow — the effective approval chain for this invoice's amount, with its completed, current and upcoming steps. The overall outcome shows in the invoice's `stage`; this object is the breakdown. Only the applicable chain is returned (amount-bracket internals are not exposed).",
      "properties": {
        "isAutoApproved": {
          "type": "boolean",
          "description": "Whether the invoice was approved automatically by a rule rather than by approvers. When true, `steps` is empty."
        },
        "autoApprovalReason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Why the invoice was auto-approved, or null when it was not."
        },
        "steps": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/approvalStep"
          },
          "description": "The approval steps in execution order. Empty when the invoice was auto-approved."
        }
      },
      "required": [
        "isAutoApproved",
        "autoApprovalReason",
        "steps"
      ],
      "title": "approval"
    },
    "approvalDecision": {
      "type": "object",
      "additionalProperties": false,
      "description": "Who acted on a step, when, and why. Null on a step until it has been acted on. The outcome (approved vs rejected) is given by the step's `state`.",
      "properties": {
        "byUserId": {
          "type": "string",
          "description": "Member who took the decision (the acting approver, i.e. the delegate when delegated)."
        },
        "at": {
          "allOf": [
            {
              "$ref": "#/$defs/dateTime"
            }
          ],
          "description": "When the decision was taken."
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Optional note left with the decision (e.g. a denial reason). Null when none."
        }
      },
      "required": [
        "byUserId",
        "at",
        "reason"
      ],
      "title": "approvalDecision"
    },
    "approvalStep": {
      "type": "object",
      "additionalProperties": false,
      "description": "One step in the approval chain. Steps are returned in execution order (the array index is the position); each must be approved for the invoice to advance to the next.",
      "properties": {
        "state": {
          "$ref": "#/$defs/approvalStepState"
        },
        "approvers": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/approver"
          },
          "description": "Members who may act on this step. Usually one; when several are listed, any one of them acting resolves the step."
        },
        "decision": {
          "oneOf": [
            {
              "$ref": "#/$defs/approvalDecision"
            },
            {
              "type": "null"
            }
          ],
          "description": "The decision recorded on this step, or null while it is `upcoming`/`current`."
        }
      },
      "required": [
        "state",
        "approvers",
        "decision"
      ],
      "title": "approvalStep"
    },
    "approvalStepState": {
      "type": "string",
      "enum": [
        "approved",
        "current",
        "upcoming",
        "rejected"
      ],
      "description": "State of a single step within the approval chain. \n\n| State | Description |\n| --- | --- |\n| `approved` | This step was approved. |\n| `current` | This step is the one awaiting a decision now. |\n| `upcoming` | A later step, not yet reached. |\n| `rejected` | This step was declined (stops the chain). |",
      "title": "approvalStepState"
    },
    "approver": {
      "type": "object",
      "additionalProperties": false,
      "description": "A person entitled to act on an approval step.",
      "properties": {
        "type": {
          "$ref": "#/$defs/approverType"
        },
        "userId": {
          "type": "string",
          "description": "Member who nominally owns this approval slot (e.g. the reporting manager or cost-center owner). For `type: user` this is the directly-assigned approver."
        },
        "actingUserId": {
          "type": [
            "string",
            "null"
          ],
          "description": "Member acting on the nominal approver's behalf via a delegation. Null when the approval is not delegated (then the acting approver is `userId`)."
        },
        "isDelegated": {
          "type": "boolean",
          "description": "Whether this approval is delegated (`actingUserId` differs from `userId`)."
        }
      },
      "required": [
        "type",
        "userId",
        "actingUserId",
        "isDelegated"
      ],
      "title": "approver"
    },
    "approverType": {
      "type": "string",
      "enum": [
        "reportingManager",
        "costCenterOwner",
        "accountOwner",
        "user"
      ],
      "description": "The role by which a person is entitled to approve a step. \n\n| Type | Description |\n| --- | --- |\n| `reportingManager` | The buyer's reporting manager. |\n| `costCenterOwner` | The owner of the invoice's cost center. |\n| `accountOwner` | The company's account owner. |\n| `user` | A specific named user, assigned directly by an approval rule. |",
      "title": "approverType"
    },
    "buyerRef": {
      "type": "object",
      "additionalProperties": false,
      "description": "The internal Spendesk member the invoice is assigned to — the \"buyer\", i.e. the person the spend is for and who is accountable for it. Distinct from the supplier (the external counterparty). This holds however the invoice was created: a member who submitted it, or the member an automatically-ingested invoice (shared mailbox, API) was assigned to. Name and email may be null for service accounts.",
      "properties": {
        "id": {
          "type": "string"
        },
        "firstName": {
          "type": [
            "string",
            "null"
          ]
        },
        "lastName": {
          "type": [
            "string",
            "null"
          ]
        },
        "email": {
          "type": [
            "string",
            "null"
          ],
          "format": "email"
        }
      },
      "required": [
        "id",
        "firstName",
        "lastName",
        "email"
      ],
      "title": "buyerRef"
    },
    "costCenterRef": {
      "type": "object",
      "additionalProperties": false,
      "description": "Reference to a cost center (the internal unit that bears the cost).",
      "properties": {
        "id": {
          "type": "string",
          "description": "Cost-center id. Use `GET /v1/cost-centers` to resolve full details."
        },
        "name": {
          "type": "string",
          "description": "Cost-center display name."
        }
      },
      "required": [
        "id",
        "name"
      ],
      "title": "costCenterRef"
    },
    "currency": {
      "type": "string",
      "pattern": "^[A-Z]{3}$",
      "description": "If the payment was made in a foreign currency, this amount will be the one in the payment currency. Three-letter [ISO currency codes](https://www.iso.org/iso-4217-currency-codes.html).",
      "title": "currency"
    },
    "date": {
      "type": "string",
      "format": "date",
      "description": "String containing a date expressed in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format like `2023-05-12`.",
      "title": "date"
    },
    "dateTime": {
      "type": "string",
      "format": "date-time",
      "description": "String containing a UTC datetime expressed in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format like `2023-05-12T14:06:40Z`.",
      "title": "dateTime"
    },
    "documentaryEvidenceStatus": {
      "type": "string",
      "enum": [
        "provided",
        "missing",
        "cannotBeProvided",
        "declaredAsInvalid"
      ],
      "description": "Status of the supporting document — the supplier's invoice or credit-note file — that justifies the payable for audit and tax purposes. Only meaningful once the invoice has an accounting payable — the invoice's `documentaryEvidenceStatus` field itself is null for invoices that don't have one yet. \n\n| Status | Description |\n| --- | --- |\n| `provided` | A document is attached. |\n| `missing` | No document is attached yet. |\n| `cannotBeProvided` | The buyer declared that no document can be provided; a signed affidavit stands in its place. |\n| `declaredAsInvalid` | An attached document was reviewed and marked invalid (e.g. wrong file or unreadable). |\n\nCertification/compliance details (e.g. the Spanish \"Digitised Paper Receipt\") are intentionally out of scope of this field and will be exposed via a dedicated compliance field once its format is finalised.",
      "title": "documentaryEvidenceStatus"
    },
    "expenseCategoryRef": {
      "type": "object",
      "additionalProperties": false,
      "description": "Reference to an expense category — the customer's spend taxonomy (e.g. Software, Travel, Meals) used for accounting and analytics. Distinct from the cost center (which bears the cost) and from analytical fields (free custom dimensions).",
      "properties": {
        "id": {
          "type": "string",
          "description": "Expense-category id. Use `GET /v1/expense-categories` to resolve full details."
        },
        "name": {
          "type": "string",
          "description": "Expense-category display name."
        }
      },
      "required": [
        "id",
        "name"
      ],
      "title": "expenseCategoryRef"
    },
    "exportStatus": {
      "type": "string",
      "enum": [
        "pending",
        "exported",
        "failed"
      ],
      "description": "Accounting-export state — whether the invoice has been exported to the customer's accounting system or ERP. Independent of `stage` and `paymentStatus`. The ledger posting date is `accountingDate`; the export timestamp is `exportedAt`. Only meaningful once the invoice has an accounting payable — the invoice's `exportStatus` field itself is null for invoices that don't have one yet. \n\n| Status | Description |\n| --- | --- |\n| `pending` | Not yet exported. |\n| `exported` | Successfully exported to the accounting system. |\n| `failed` | An export attempt failed and needs attention. |",
      "title": "exportStatus"
    },
    "invoiceAnalyticalSplit": {
      "type": "object",
      "additionalProperties": false,
      "description": "One allocation of the whole invoice to a cost center and/or analytical-field values, as a share of its total. Splits apply to the invoice as a whole, not to individual line items.",
      "properties": {
        "costCenter": {
          "oneOf": [
            {
              "$ref": "#/$defs/costCenterRef"
            },
            {
              "type": "null"
            }
          ],
          "description": "Cost center this share is allocated to, or null when the split only sets analytical-field values."
        },
        "percentage": {
          "type": "number",
          "description": "Percentage of the invoice allocated to this split, from 0 to 100 (e.g. `25` means 25%). The splits of an invoice add up to 100."
        },
        "analyticalProperties": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/analyticalProperty"
          },
          "description": "Analytical-field values set on this split."
        }
      },
      "required": [
        "costCenter",
        "percentage",
        "analyticalProperties"
      ],
      "title": "invoiceAnalyticalSplit"
    },
    "invoiceAttachment": {
      "type": "object",
      "additionalProperties": false,
      "description": "A file supporting the invoice (documentary evidence). An invoice may have several.",
      "properties": {
        "id": {
          "type": "string"
        },
        "fileName": {
          "type": "string"
        },
        "mimeType": {
          "type": "string",
          "description": "MIME type of the file (e.g. `application/pdf`, `application/xml` for e-invoices)."
        },
        "downloadUrl": {
          "type": "string",
          "format": "uri",
          "description": "Pre-signed URL to download the file, valid for at most 3 hours from when it was generated. Invoice responses are cached, so a re-fetch shortly after may return the same URL — download promptly and do not persist it."
        }
      },
      "required": [
        "id",
        "fileName",
        "mimeType",
        "downloadUrl"
      ],
      "title": "invoiceAttachment"
    },
    "invoiceDispute": {
      "type": "object",
      "additionalProperties": false,
      "description": "Details of a dispute on the invoice (contested amount, duplicate, goods/services not received, quality issue…), overlaying whatever approval/payment state the invoice holds. Not populated yet: the invoice `dispute` field is always null for now, even on an invoice in dispute with the supplier (which reports `stage` `disputed`).",
      "properties": {
        "reasonCode": {
          "type": [
            "string",
            "null"
          ],
          "description": "Machine-readable reason the invoice is disputed (e.g. a standard dispute-reason code). Not enumerated — treat as an opaque, extensible code. Null when only a free-text reason exists."
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Human-readable reason/comment for the dispute, if recorded."
        },
        "disputedBy": {
          "type": "string",
          "description": "Member who raised the dispute."
        },
        "disputedAt": {
          "allOf": [
            {
              "$ref": "#/$defs/dateTime"
            }
          ],
          "description": "When the dispute was raised."
        }
      },
      "required": [
        "reasonCode",
        "reason",
        "disputedBy",
        "disputedAt"
      ],
      "title": "invoiceDispute"
    },
    "invoiceId": {
      "type": "string",
      "description": "Opaque unique identifier of an invoice.",
      "title": "invoiceId"
    },
    "invoiceStage": {
      "type": "string",
      "enum": [
        "pendingApproval",
        "inReview",
        "disputed",
        "toSettle",
        "settled",
        "rejected",
        "cancelled"
      ],
      "description": "Where the invoice or credit note is in its lifecycle; exactly one value at a time. `paymentStatus` and `exportStatus` move in parallel. \n\n| Stage | Description |\n| --- | --- |\n| `pendingApproval` | Awaiting a decision in the approval workflow. |\n| `inReview` | Approved, waiting for the controller review. |\n| `disputed` | Approved, then put in dispute with the supplier. Invoices only. |\n| `toSettle` | Reviewed. An invoice is waiting for payment, fully or in part (`paymentStatus` tells which); a credit note is partially allocated. |\n| `settled` | An invoice is fully paid; a credit note is fully allocated or reimbursed. |\n| `rejected` | Declined by an approver, rejected in controller review, or expired. |\n| `cancelled` | Withdrawn by the company: archived after a supplier dispute, or replaced by a corrective invoice. Invoices withdrawn by their submitter are never returned. |",
      "title": "invoiceStage"
    },
    "invoiceType": {
      "type": "string",
      "enum": [
        "invoice",
        "creditNote"
      ],
      "description": "Kind of document the record represents. \n\n| Type | Description |\n| --- | --- |\n| `invoice` | A supplier invoice: an amount the company owes the supplier for goods or services. Amounts are positive. |\n| `creditNote` | A supplier credit note: a document from the same supplier that reduces an amount owed (a refund, cancellation, or correction of a prior invoice). Amounts are negative. |",
      "title": "invoiceType"
    },
    "lineItem": {
      "type": "object",
      "additionalProperties": false,
      "description": "A single line of the invoice, with its amounts and tax. Accounting coding is set on the whole invoice (see the invoice `costCenter`, `analyticalSplits` and `expenseCategories`), not per line.",
      "properties": {
        "description": {
          "type": "string",
          "description": "What the line is for."
        },
        "quantity": {
          "type": "number",
          "description": "Quantity billed (may be fractional)."
        },
        "unitPrice": {
          "oneOf": [
            {
              "$ref": "#/$defs/priceAmount"
            },
            {
              "type": "null"
            }
          ],
          "description": "Price per unit before tax, in `currency`'s smallest unit. Null when no net amount was captured, which can happen in any state (e.g. the single header-derived line of a credit note or of an older invoice whose net was never recorded)."
        },
        "netAmount": {
          "oneOf": [
            {
              "$ref": "#/$defs/priceAmount"
            },
            {
              "type": "null"
            }
          ],
          "description": "Line amount before tax (`quantity` x `unitPrice`), in `currency`'s smallest unit. Null when no net amount was captured, which can happen in any state (e.g. the single header-derived line of a credit note or of an older invoice whose net was never recorded)."
        },
        "taxRate": {
          "$ref": "#/$defs/taxRate"
        },
        "taxAmount": {
          "oneOf": [
            {
              "$ref": "#/$defs/priceAmount"
            },
            {
              "type": "null"
            }
          ],
          "description": "Tax charged on this line, in `currency`'s smallest unit. Null when no net amount was captured, which can happen in any state (e.g. the single header-derived line of a credit note or of an older invoice whose net was never recorded), or when the gross amount is not known yet."
        },
        "grossAmount": {
          "oneOf": [
            {
              "$ref": "#/$defs/priceAmount"
            },
            {
              "type": "null"
            }
          ],
          "description": "Line amount including tax (`netAmount` + `taxAmount`), in `currency`'s smalle

# --- truncated at 32 KB (45 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/spendesk/refs/heads/main/json-schema/spendesk-invoice-schema.json

Work with this as data

Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for schemas

4 MCP tools reach this
  • find_json_schemasBrowse and filter every JSON Schema in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/spendesk-invoice"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.