Skip to content

Expenses

The Expense object

object

Attributes

idstring
Other attributes
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
Examplejson
{
  "id": "exp_6595a27b5d35015c3ef0c3fd",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
  "type": "invoice",
  "is_draft": false,
  "voided_at": null,
  "supplier": {
    "name": "Orbital Power Systems GmbH",
    "address": "Energieweg 8",
    "address_2": null,
    "post_code": "10115",
    "city": "Berlin",
    "state": null,
    "country": "Germany",
    "country_code": "DE",
    "tax_number": "DE987654321",
    "company_number": "HRB 98765",
    "email": "accounts@orbital-power.example",
    "phone": "+493012345678",
    "peppol_id": "0088:9876543210982",
    "is_tax_subject": true
  },
  "supplier_document_number": "OPS-2025-001",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": "2025-11-02",
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": "Ground facility maintenance — March billing period",
  "summary_classification": null,
  "items": [
    {
      "name": "Ground facility maintenance",
      "description": "Monthly ground facility maintenance",
      "quantity": 1,
      "unit": "service",
      "classification": "service",
      "price": 100,
      "gross_price": 119,
      "discounts": [],
      "taxes": [
        {
          "rate": 19,
          "amount": 19,
          "is_deductible": true,
          "deductible_percentage": 100
        }
      ],
      "total": 100,
      "total_with_tax": 119,
      "total_tax": 19
    }
  ],
  "taxes": [
    {
      "rate": 19,
      "base": 100,
      "amount": 19,
      "is_deductible": true,
      "deductible_percentage": 100,
      "reverse_charge": false
    }
  ],
  "total": 100,
  "total_with_tax": 119,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 119,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 1,
  "has_attachment": true,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-03T08:00:00.000Z"
}

Create expense

POST/expenses

This is the recommended endpoint for normal expense creation. Use it when Space Invoices should validate the supplied totals, tax summaries, and line items, then apply supplier handling, payment tracking initialization, and lifecycle rules.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Body parameters

supplier_idstringoptionalnullable
datestring<date>optionalnullable
date_receivedstring<date>optionalnullable
date_duestring<date>optionalnullable
date_servicestring<date>optionalnullable
date_service_tostring<date>optionalnullable
currency_codestringoptionalnullable
referencestringoptionalnullable
notestringoptionalnullable
totalnumberoptionalnullable
total_with_taxnumberoptionalnullable
total_discountnumberoptionalnullable
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.create({
  supplier: {
    name: "Office Supplies Ltd",
    tax_number: "SI12345678",
    country_code: "SI"
  },
  supplier_document_number: "2025-0417",
  date: "2025-10-03",
  total: 100,
  total_with_tax: 122,
  taxes: [
    {
      rate: 22,
      base: 100,
      amount: 22
    }
  ]
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);
Example:

Returns

idstring
Other parameters
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
json
{
  "id": "exp_9595a27b5d35015c3ef0c400",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": null,
  "type": "invoice",
  "is_draft": false,
  "voided_at": null,
  "supplier": {
    "name": "Office Supplies Ltd",
    "tax_number": "SI12345678",
    "country_code": "SI"
  },
  "supplier_document_number": "2025-0417",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": null,
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": null,
  "summary_classification": null,
  "items": [],
  "taxes": [
    {
      "rate": 22,
      "base": 100,
      "amount": 22,
      "is_deductible": true,
      "deductible_percentage": 100
    }
  ],
  "total": 100,
  "total_with_tax": 122,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 122,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 0,
  "has_attachment": false,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-04T08:00:00.000Z"
}
Example:

Create expense with pre-calculated totals

POST/expenses/custom

Advanced endpoint for importing expenses that already have authoritative pre-calculated totals. Do not use this for normal expense creation. Prefer the standard create endpoint unless your integration must preserve exact external totals from an ERP, OCR, migration, or accounting system.
The caller provides document totals, item totals, and tax summaries directly.
The persistence, supplier handling, payment tracking initialization, and lifecycle rules are identical to the standard create endpoint.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Body parameters

supplier_idstringoptionalnullable
datestring<date>optionalnullable
date_receivedstring<date>optionalnullable
date_duestring<date>optionalnullable
date_servicestring<date>optionalnullable
date_service_tostring<date>optionalnullable
currency_codestringoptionalnullable
referencestringoptionalnullable
notestringoptionalnullable
totalnumberoptionalnullable
total_with_taxnumberoptionalnullable
total_discountnumberoptionalnullable
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.createCustom({
  supplier: {
    name: "Office Supplies Ltd",
    tax_number: "SI12345678",
    country_code: "SI"
  },
  supplier_document_number: "2025-0417",
  date: "2025-10-03",
  total: 100,
  total_with_tax: 122,
  taxes: [
    {
      rate: 22,
      base: 100,
      amount: 22
    }
  ]
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);
Example:

Returns

idstring
Other parameters
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
json
{
  "id": "exp_9595a27b5d35015c3ef0c400",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": null,
  "type": "invoice",
  "is_draft": false,
  "voided_at": null,
  "supplier": {
    "name": "Office Supplies Ltd",
    "tax_number": "SI12345678",
    "country_code": "SI"
  },
  "supplier_document_number": "2025-0417",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": null,
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": null,
  "summary_classification": null,
  "items": [],
  "taxes": [
    {
      "rate": 22,
      "base": 100,
      "amount": 22,
      "is_deductible": true,
      "deductible_percentage": 100
    }
  ],
  "total": 100,
  "total_with_tax": 122,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 122,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 0,
  "has_attachment": false,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-04T08:00:00.000Z"
}
Example:

Backfill expense recognition entries

POST/expenses/recognition/backfill

Backfill expense recognition entries

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Body parameters

date_fromstring<date>optionalnullable
date_tostring<date>optionalnullable
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.backfillExpenseRecognition({
  date_from: "2026-01-01",
  date_to: "2026-03-31",
  dry_run: true,
  limit: 100
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);
Example:

Returns

processed_expensesinteger
generated_entriesinteger
dry_runboolean
next_cursorstringnullable
json
{
  "processed_expenses": 0,
  "generated_entries": 0,
  "dry_run": true,
  "next_cursor": "next-cursor"
}

Start expense recognition from a document file

POST/expenses/recognitions

Automatic expense recognition supports PDFs up to 8 pages. Split a larger PDF into smaller documents before trying again.

Accepts one supplier invoice (PDF, JPEG, PNG, or WebP), creates an invoice-only draft expense with creation_source=ocr, and enqueues an async recognition job. For sandbox entities, no provider is called and no usage is charged: the submitted file is not stored and is replaced by a clearly marked deterministic demo invoice; the response exposes simulation_mode=sandbox_demo.

Returns 202 Accepted with the job, expense, and file identifiers. Recognition is asynchronous in live mode; poll GET /expenses/recognitions/{id} for status. Terminal success is ready_for_review or needs_attention; terminal failure is failed, with safe error_code and error_message fields.

Parsed document and line amounts are checked against the standard expense calculation before applying extraction. A disagreement keeps the draft unchanged and stores the extraction with needs_attention for review. Critical identity, required-field, confidence, document-type, and questionable financial warnings also require review and prevent unsafe automatic application.

Payment suggestions from OCR are advisory only and never mark the expense paid or create payments. Failed provider attempts record zero customer usage. Automatic provider attempts and a permitted customer retry share the same job; billable customer usage is recorded once only after a successful terminal result.

X-Request-Id provides account/entity-scoped replay and fails closed with 409 Conflict when reused for different file content.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

x-request-idstringoptional

Optional idempotency key. Reusing it with the same entity and identical file replays the original result; reusing it with different file content fails with 409 Conflict.

Body parameters

filestring<binary>required

Supplier invoice PDF or image

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';
import fs from 'fs';

const sdk = new SpaceInvoices('YOUR_API_KEY');

// Read file as Buffer
const fileBuffer = fs.readFileSync('/path/to/image.png');
const file = new File([fileBuffer], 'image.png', { type: 'image/png' });

const response = await sdk.expenses.createRecognition({
  file
}, { entity_id: 'YOUR_ENTITY_ID' });

console.log(response);

Returns

expense_idstring
file_metadata_idstring
json
{
  "job": {
    "id": "erj_6595a27b5d35015c3ef0c3fd",
    "entity_id": "entity-id",
    "expense_id": "expense-id",
    "file_metadata_id": "file-metadata-id",
    "status": "queued",
    "provider": "provider",
    "model": "model",
    "parser_version": "parser-version",
    "attempts": 0,
    "max_attempts": 0,
    "pages_processed": 0,
    "page_count": 0,
    "warnings": [
      {
        "code": "missing_required_field",
        "field": "field",
        "message": "message"
      }
    ],
    "provenance": {
      "provider": "mistral",
      "model": "model",
      "parser_version": "parser-version",
      "pages_processed": 0,
      "doc_size_bytes": 0,
      "fields": [
        {
          "field": "field",
          "page": 0,
          "confidence": 0,
          "source": "annotation",
          "note": "note"
        }
      ]
    },
    "reconciliation": {
      "is_reconciled": true,
      "expected_total": 0,
      "expected_total_with_tax": 0,
      "expected_tax": 0,
      "reported_total": 0,
      "reported_total_with_tax": 0,
      "reported_tax": 0,
      "differences": [
        {
          "field": "field",
          "expected": 0,
          "reported": 0,
          "delta": 0
        }
      ]
    },
    "payment_suggestion": {
      "status": "paid",
      "amount": 0,
      "date": "date",
      "method": "method",
      "evidence": [
        "evidence"
      ],
      "confidence": 0,
      "is_partial": true
    },
    "extracted_draft": {
      "type": "invoice",
      "supplier": {
        "name": "name",
        "email": "user@example.com",
        "address": "address",
        "address_2": "address-2",
        "post_code": "post-code",
        "city": "city",
        "state": "state",
        "country": "country",
        "country_code": "country-code",
        "tax_number": "tax-number",
        "company_number": "company-number",
        "phone": "phone",
        "peppol_id": "peppol-id",
        "bank_accounts": [
          {
            "iban": "iban",
            "bic": "bic",
            "bank_name": "bank-name",
            "account_number": "account-number",
            "currency_code": "currency-code"
          }
        ],
        "is_tax_subject": true
      },
      "supplier_document_number": "supplier-document-number",
      "date": "date",
      "date_received": "date-received",
      "date_due": "date-due",
      "date_service": "date-service",
      "date_service_to": "date-service-to",
      "currency_code": "currency-code",
      "transaction_type": "domestic",
      "reference": "reference",
      "note": "note",
      "items": [
        {
          "name": "name",
          "description": "description",
          "quantity": 0,
          "unit": "unit",
          "classification": "product",
          "price": 0,
          "gross_price": 0,
          "discounts": [
            {
              "value": 0,
              "type": "percent"
            }
          ],
          "taxes": [
            {
              "rate": 0,
              "amount": 0,
              "reverse_charge": true,
              "is_deductible": true,
              "deductible_percentage": 0
            }
          ],
          "total": 0,
          "total_with_tax": 0,
          "total_tax": 0
        }
      ],
      "taxes": [
        {
          "rate": 0,
          "base": 0,
          "amount": 0,
          "reverse_charge": true,
          "is_deductible": true,
          "deductible_percentage": 0
        }
      ],
      "total": 0,
      "total_with_tax": 0,
      "total_discount": 0,
      "summary_classification": "product"
    },
    "error_code": "error-code",
    "error_message": "error-message",
    "request_id": "request-id",
    "source_filename": "source-filename",
    "source_mime_type": "source-mime-type",
    "source_bytes": 0,
    "source_content_sha256": "source-content-sha256",
    "simulation_mode": "sandbox_demo",
    "source_replaced": true,
    "expense_updated_at_snapshot": "2025-01-15T10:30:00.000Z",
    "queued_at": "2025-01-15T10:30:00.000Z",
    "started_at": "2025-01-15T10:30:00.000Z",
    "completed_at": "2025-01-15T10:30:00.000Z",
    "created_at": "2025-01-15T10:30:00.000Z",
    "updated_at": "2025-01-15T10:30:00.000Z"
  },
  "expense_id": "expense-id",
  "file_metadata_id": "file-metadata-id",
  "status": "queued"
}

Create or rotate expense inbound email address

POST/expenses/inbound-email

Creates the entity's inbound email address, or issues a new one when an address already exists. Rotation invalidates the previous address immediately; mail sent to it afterwards is not accepted.
Every supported attachment (PDF, JPEG, PNG or WebP) forwarded to the entity's private inbound address becomes a draft expense. Attachments are recognised automatically when expense recognition is available to the entity; otherwise the draft expense is saved with the attachment so it can be completed manually. Anyone who knows the address can send to it, so treat it like a password: rotate it if it leaks, which invalidates the previous address immediately.

Requires permission to manage entity settings. Responds with 503 when expense inbound email is not configured on this deployment and 403 when it is hidden for the entity's white label.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.rotateExpenseInboundEmail({
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

json
{
  "available": true,
  "enabled": true,
  "address": "k3m7q2x9v5b8n4c6d1f0hjwy@invoices.example.com",
  "created_at": "2026-10-05T09:30:00.000Z"
}


List expenses

GET/expenses

Retrieve a paginated list of expenses with optional filtering.
Supports cursor-based pagination, full-text search across supplier snapshot and document fields, and suite-standard JSON query filters for date, totals, payment state, and supplier snapshot data. Filter expenses that contain a saved catalog item with {"items.item_id":"item_..."}.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Query parameters

limitintegeroptional

Number of results per request.

Default: 10

next_cursorstringoptional

Opaque cursor to fetch the next page of results. Reuse only with the same effective ordering. Use the value from pagination.next_cursor in the previous response.

prev_cursorstringoptional

Opaque cursor to fetch the previous page of results. Reuse only with the same effective ordering. Use the value from pagination.prev_cursor in the previous response.

include_total_countbooleanoptional

Whether to include the total count of items in pagination.total.
Default is true.
When false, pagination.total returns -1 for better performance.

has_attachmentbooleanoptional

Filter expenses by whether at least one attachment exists.

querystring<json>optional

JSON query object for filtering results. Supports MongoDB-style operators.

Array columns (such as an item's categories) compare as sets: a direct value asks whether the list contains it, contains takes an array and requires all of them, in matches any of them, and notIn matches none. Scalar operators such as gt do not apply and are ignored.

Supported operators:
- equals or direct value - Exact match (default)
- gte - Greater than or equal
- lte - Less than or equal
- gt - Greater than
- lt - Less than
- in - Value in array
- notIn - Value not in array
- contains - String contains (case-insensitive)
- startsWith - String starts with
- endsWith - String ends with
- between - Value between two numbers/dates [min, max]

Allowed fields: id, number, type, is_draft, voided_at, deleted_at, supplier_id, supplier, supplier_document_number, date, date_received, date_due, date_service, date_service_to, currency_code, transaction_type, reference, note, summary_classification, total, total_with_tax, total_paid, total_due, paid_in_full, created_at, updated_at, metadata, items.item_id

Examples:
- {"total": {"gte": 1000}} - Invoices over 1000
- {"customer.name": {"contains": "Acme"}} - Customer name contains "Acme"
- {"date": {"between": ["2025-01-01", "2025-12-31"]}} - Date range

order_byoptional

Sort by one field or provide a repeated array for multi-column ordering. Prefix a field with - for descending order. When paginating, reuse cursors only with the same effective ordering.

searchstringoptional

Full-text search query to filter results across multiple fields.
Searches are case-insensitive and match partial strings.
Searches across all text fields including names, descriptions, addresses, and metadata values.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.list({
  limit: 20,
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

dataarray of objects
paginationobject

Pagination metadata including cursors and result counts

json
{
  "data": [
    {
      "id": "exp_6595a27b5d35015c3ef0c3fd",
      "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
      "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
      "type": "invoice",
      "is_draft": false,
      "voided_at": null,
      "supplier": {
        "name": "Orbital Power Systems GmbH",
        "address": "Energieweg 8",
        "address_2": null,
        "post_code": "10115",
        "city": "Berlin",
        "state": null,
        "country": "Germany",
        "country_code": "DE",
        "tax_number": "DE987654321",
        "company_number": "HRB 98765",
        "email": "accounts@orbital-power.example",
        "phone": "+493012345678",
        "peppol_id": "0088:9876543210982",
        "is_tax_subject": true
      },
      "supplier_document_number": "OPS-2025-001",
      "date": "2025-10-03",
      "date_received": "2025-10-03",
      "date_due": "2025-11-02",
      "date_service": null,
      "date_service_to": null,
      "currency_code": "EUR",
      "transaction_type": "domestic",
      "reference": "DE00-2025-001",
      "note": "Ground facility maintenance — March billing period",
      "summary_classification": null,
      "items": [
        {
          "name": "Ground facility maintenance",
          "description": "Monthly ground facility maintenance",
          "quantity": 1,
          "unit": "service",
          "classification": "service",
          "price": 100,
          "gross_price": 119,
          "discounts": [],
          "taxes": [
            {
              "rate": 19,
              "amount": 19,
              "is_deductible": true,
              "deductible_percentage": 100
            }
          ],
          "total": 100,
          "total_with_tax": 119,
          "total_tax": 19
        }
      ],
      "taxes": [
        {
          "rate": 19,
          "base": 100,
          "amount": 19,
          "is_deductible": true,
          "deductible_percentage": 100,
          "reverse_charge": false
        }
      ],
      "total": 100,
      "total_with_tax": 119,
      "total_discount": 0,
      "total_paid": 0,
      "total_due": 119,
      "paid_in_full": false,
      "exchange_rate": null,
      "attachment_count": 1,
      "has_attachment": true,
      "metadata": {
        "source": "manual"
      },
      "created_at": "2025-10-03T08:00:00.000Z",
      "updated_at": "2025-10-03T08:00:00.000Z"
    },
    {
      "id": "exp_7595a27b5d35015c3ef0c3fe",
      "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
      "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
      "type": "invoice",
      "is_draft": false,
      "voided_at": null,
      "supplier": {
        "name": "Orbital Power Systems GmbH",
        "address": "Energieweg 8",
        "address_2": null,
        "post_code": "10115",
        "city": "Berlin",
        "state": null,
        "country": "Germany",
        "country_code": "DE",
        "tax_number": "DE987654321",
        "company_number": "HRB 98765",
        "email": "accounts@orbital-power.example",
        "phone": "+493012345678",
        "peppol_id": "0088:9876543210982",
        "is_tax_subject": true
      },
      "supplier_document_number": "AP-CUSTOM-001",
      "date": "2025-10-03",
      "date_received": "2025-10-03",
      "date_due": "2025-11-02",
      "date_service": null,
      "date_service_to": null,
      "currency_code": "EUR",
      "transaction_type": "domestic",
      "reference": "DE00-2025-001",
      "note": "Supplier provided totals only",
      "summary_classification": "service",
      "items": [],
      "taxes": [
        {
          "rate": 19,
          "base": 45.22,
          "amount": 8.59,
          "is_deductible": true,
          "deductible_percentage": 100,
          "reverse_charge": false
        },
        {
          "rate": 0,
          "base": 125.63,
          "amount": 0,
          "is_deductible": true,
          "deductible_percentage": 100,
          "reverse_charge": false
        }
      ],
      "total": 170.85,
      "total_with_tax": 179.44,
      "total_discount": 0,
      "total_paid": 0,
      "total_due": 179.44,
      "paid_in_full": false,
      "exchange_rate": null,
      "attachment_count": 0,
      "has_attachment": false,
      "metadata": {
        "source": "manual"
      },
      "created_at": "2025-10-03T08:00:00.000Z",
      "updated_at": "2025-10-04T08:00:00.000Z"
    }
  ],
  "pagination": {
    "total": 2,
    "next_cursor": null,
    "prev_cursor": null,
    "has_more": false
  }
}
Example:

Export expenses to Excel

GET/expenses/export

Export up to 10,000 entity-scoped supplier invoice expenses to an Excel workbook. Supports an optional date range of up to one year and lets callers filter by document date (the default) or received date; when the selected date is missing, filtering falls back to the other date. The workbook includes document type, trusted source provenance (including completed legacy migrations), supplier snapshots with country-code fallback, summary product/service classification, payment state and amount due, original totals and tax amounts in each expense currency, and separately labeled converted totals and tax amounts in the entity currency when currency conversion applies. Narrow the date range if the export exceeds the row limit.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Query parameters

formatstringrequired

Export format. Expense exports currently support Excel workbooks only.

Possible values: "xlsx"

date_basisstringoptional

Date used to apply date_from and date_to. document (default) uses the document date and falls back to the received date; received uses the received date and falls back to the document date.

Possible values: "document", "received"

date_fromstring<date>optional

Optional inclusive lower bound for the selected expense date basis. The date range cannot exceed one year.

date_tostring<date>optional

Optional inclusive upper bound for the selected expense date basis. The date range cannot exceed one year.

languagestringoptional

Language for workbook headers. Defaults to the entity locale when omitted.

Possible values: "en", "de", "sl", "it", "fr", "es", "pt", "nl", "pl", "hr", "sv", "fi", "et", "bg", "cs", "sk", "nb", "is", "hu"

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const blob = await sdk.expenses.exportExpenses({
  format: "xlsx"
}, {
  entity_id: "YOUR_ENTITY_ID"
});

const arrayBuffer = await blob.arrayBuffer();
const { writeFile } = await import('node:fs/promises');
await writeFile('download.bin', Buffer.from(arrayBuffer));
console.log('Saved download.bin');

Get expenses by financial category

GET/expenses/report

Return finalized expense net amounts grouped by financial category. Depending on expense-recognition settings and line overrides, recognized amounts use document dates or generated daily service-period schedules.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Query parameters

date_fromstring<date>required

Report start date in YYYY-MM-DD format. Must be the first calendar day of a month.

date_tostring<date>required

Report end date in YYYY-MM-DD format. Must be the final calendar day of a month.

basisstringoptional

recognized returns expense recognized inside each period. deferred returns the remaining future expense balance at the end of each period.

Possible values: "recognized", "deferred"

Default: "recognized"

group_bystringoptional

Report grouping dimension.

Possible values: "financial_category"

Default: "financial_category"

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getExpenseCategoryReport({
  date_from: "2026-01-01",
  date_to: "2026-12-31"
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

totalsarray of numbers
totalnumber
currency_codestring
date_fromstring
date_tostring
json
{
  "basis": "recognized",
  "group_by": "financial_category",
  "calculation_mode": "recognition_entries",
  "periods": [
    {
      "period": "2026-01",
      "date_from": "2026-01-01",
      "date_to": "2026-01-31"
    },
    {
      "period": "2026-02",
      "date_from": "2026-02-01",
      "date_to": "2026-02-28"
    }
  ],
  "series": [
    {
      "key": "fcat_office",
      "financial_category_id": "fcat_office",
      "name": "Office expenses",
      "color": "#2563eb",
      "values": [
        1200,
        850
      ],
      "total": 2050
    },
    {
      "key": "uncategorized",
      "financial_category_id": null,
      "name": "Uncategorized",
      "color": null,
      "values": [
        50,
        125
      ],
      "total": 175
    }
  ],
  "totals": [
    1250,
    975
  ],
  "total": 2225,
  "currency_code": "EUR",
  "date_from": "2026-01-01",
  "date_to": "2026-02-28"
}

Get expense recognition settings

GET/expenses/recognition/settings

Get expense recognition settings

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getRecognitionSettings({
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

json
{
  "default_method": "service_period_daily"
}

Get expense inbound email address

GET/expenses/inbound-email

Returns the entity's expense inbound email address and whether the feature is available.
Every supported attachment (PDF, JPEG, PNG or WebP) forwarded to the entity's private inbound address becomes a draft expense. Attachments are recognised automatically when expense recognition is available to the entity; otherwise the draft expense is saved with the attachment so it can be completed manually. Anyone who knows the address can send to it, so treat it like a password: rotate it if it leaks, which invalidates the previous address immediately.

available is false when inbound email is not configured on this deployment or is hidden for the entity's white label; in that case enabled is false and address is null.

Requires permission to create documents for the entity, because the address itself lets its holder create expenses.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getExpenseInboundEmail({
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

json
{
  "available": true,
  "enabled": true,
  "address": "k3m7q2x9v5b8n4c6d1f0hjwy@invoices.example.com",
  "created_at": "2026-10-05T09:30:00.000Z"
}
Example:

List expense inbound email messages

GET/expenses/inbound-email/messages

Lists messages received on the entity's inbound addresses, newest first, with the outcome for each attachment (created expense, recognition job, or why it was skipped). Messages are kept for 90 days; older messages are never returned and are purged from this log (created expenses are not affected). Supports cursor pagination.
Every supported attachment (PDF, JPEG, PNG or WebP) forwarded to the entity's private inbound address becomes a draft expense. Attachments are recognised automatically when expense recognition is available to the entity; otherwise the draft expense is saved with the attachment so it can be completed manually. Anyone who knows the address can send to it, so treat it like a password: rotate it if it leaks, which invalidates the previous address immediately.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Query parameters

limitintegeroptional

Number of results per request.

Default: 10

next_cursorstringoptional

Opaque cursor to fetch the next page of results. Reuse only with the same effective ordering. Use the value from pagination.next_cursor in the previous response.

prev_cursorstringoptional

Opaque cursor to fetch the previous page of results. Reuse only with the same effective ordering. Use the value from pagination.prev_cursor in the previous response.

include_total_countbooleanoptional

Whether to include the total count of items in pagination.total.
Default is true.
When false, pagination.total returns -1 for better performance.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.listExpenseInboundEmailMessages(undefined, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

dataarray of objects
paginationobject

Pagination metadata including cursors and result counts

json
{
  "data": [
    {
      "id": "eim_6595a27b5d35015c3ef0c3fd",
      "from_email": "accountant@example.com",
      "subject": "Fwd: October supplier invoices",
      "status": "processed",
      "reject_reason": null,
      "attachments": [
        {
          "index": 0,
          "filename": "invoice-1042.pdf",
          "mime_type": "application/pdf",
          "bytes": 48321,
          "mode": "ocr",
          "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
          "recognition_job_id": "erj_6595a27b5d35015c3ef0c3fd",
          "reason": null
        },
        {
          "index": 1,
          "filename": "notes.txt",
          "mime_type": "text/plain",
          "bytes": 120,
          "mode": "skipped",
          "expense_id": null,
          "recognition_job_id": null,
          "reason": "unsupported_type"
        }
      ],
      "received_at": "2026-10-05T09:30:00.000Z",
      "processed_at": "2026-10-05T09:30:04.000Z"
    },
    {
      "id": "eim_6595a27b5d35015c3ef0c3fe",
      "from_email": "supplier@example.net",
      "subject": "Invoice",
      "status": "rejected",
      "reject_reason": "no_attachments",
      "attachments": [],
      "received_at": "2026-10-04T14:12:00.000Z",
      "processed_at": "2026-10-04T14:12:00.000Z"
    }
  ],
  "pagination": {
    "total": 2,
    "next_cursor": null,
    "prev_cursor": null,
    "has_more": false
  }
}

Get expense recognition job by ID

GET/expenses/recognitions/{id}

Returns recognition job status, extraction results, warnings, reconciliation, and advisory payment suggestion. Entity-scoped.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired

Expense recognition job ID

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getRecognition("erj_6595a27b5d35015c3ef0c3fd", {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

idstring

Recognition job ID

Other parameters
attemptsinteger
max_attemptsinteger
pages_processedintegernullable
page_countintegernullable
source_filenamestringnullable
source_mime_typestring
source_bytesinteger
expense_updated_at_snapshotstring<date-time>
queued_atstring<date-time>
started_atstring<date-time>nullable
completed_atstring<date-time>nullable
created_atstring<date-time>
updated_atstring<date-time>
json
{
  "id": "erj_6595a27b5d35015c3ef0c3fd",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
  "file_metadata_id": "fil_6595a27b5d35015c3ef0c3fd",
  "status": "queued",
  "attempts": 0,
  "max_attempts": 3,
  "source_mime_type": "application/pdf",
  "source_bytes": 48321,
  "source_content_sha256": "f5c4c9c33d9b42e4f130cb593f17741b30e0fb23ac95a6d91d01bf438467a17c",
  "simulation_mode": null,
  "source_replaced": false,
  "expense_updated_at_snapshot": "2026-07-11T08:00:00.000Z",
  "queued_at": "2026-07-11T08:00:00.000Z",
  "created_at": "2026-07-11T08:00:00.000Z",
  "updated_at": "2026-07-11T08:00:00.000Z"
}

Get expense by ID

GET/expenses/{id}

Get expense by ID

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstring<resource-id>required

Unique resource identifier. Prefix depends on the resource, for example inv_, cus_, or ent_.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.get('exp_6595a27b5d35015c3ef0c3fd', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

idstring
Other parameters
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
json
{
  "id": "exp_6595a27b5d35015c3ef0c3fd",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
  "type": "invoice",
  "is_draft": false,
  "voided_at": null,
  "supplier": {
    "name": "Orbital Power Systems GmbH",
    "address": "Energieweg 8",
    "address_2": null,
    "post_code": "10115",
    "city": "Berlin",
    "state": null,
    "country": "Germany",
    "country_code": "DE",
    "tax_number": "DE987654321",
    "company_number": "HRB 98765",
    "email": "accounts@orbital-power.example",
    "phone": "+493012345678",
    "peppol_id": "0088:9876543210982",
    "is_tax_subject": true
  },
  "supplier_document_number": "OPS-2025-001",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": "2025-11-02",
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": "Ground facility maintenance — March billing period",
  "summary_classification": null,
  "items": [
    {
      "name": "Ground facility maintenance",
      "description": "Monthly ground facility maintenance",
      "quantity": 1,
      "unit": "service",
      "classification": "service",
      "price": 100,
      "gross_price": 119,
      "discounts": [],
      "taxes": [
        {
          "rate": 19,
          "amount": 19,
          "is_deductible": true,
          "deductible_percentage": 100
        }
      ],
      "total": 100,
      "total_with_tax": 119,
      "total_tax": 19
    }
  ],
  "taxes": [
    {
      "rate": 19,
      "base": 100,
      "amount": 19,
      "is_deductible": true,
      "deductible_percentage": 100,
      "reverse_charge": false
    }
  ],
  "total": 100,
  "total_with_tax": 119,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 119,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 1,
  "has_attachment": true,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-03T08:00:00.000Z"
}

Update expense recognition settings

PATCH/expenses/recognition/settings

Update expense recognition settings

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Body parameters

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.updateRecognitionSettings({
  default_method: "service_period_daily"
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);
Example:

Returns

json
{
  "default_method": "service_period_daily"
}

Update expense

PATCH/expenses/{id}

Update expense

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstring<resource-id>required

Unique resource identifier. Prefix depends on the resource, for example inv_, cus_, or ent_.

Body parameters

is_draftbooleanoptional
supplier_idstringoptionalnullable
datestring<date>optionalnullable
date_receivedstring<date>optionalnullable
date_duestring<date>optionalnullable
date_servicestring<date>optionalnullable
date_service_tostring<date>optionalnullable
currency_codestringoptionalnullable
referencestringoptionalnullable
notestringoptionalnullable
totalnumberoptionalnullable
total_with_taxnumberoptionalnullable
total_discountnumberoptionalnullable
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.update('exp_6595a27b5d35015c3ef0c3fd', {
  is_draft: false,
  supplier_document_number: "OPS-2025-099",
  date: "2025-10-12",
  date_received: "2025-10-13",
  currency_code: "EUR",
  summary_classification: "service",
  taxes: [
    {
      rate: 22,
      base: 80,
      amount: 17.6
    }
  ],
  total: 80,
  total_with_tax: 97.6
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);
Example:

Returns

idstring
Other parameters
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
json
{
  "id": "exp_6595a27b5d35015c3ef0c3fd",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
  "type": "invoice",
  "is_draft": false,
  "voided_at": null,
  "supplier": {
    "name": "Orbital Power Systems GmbH",
    "address": "Energieweg 8",
    "address_2": null,
    "post_code": "10115",
    "city": "Berlin",
    "state": null,
    "country": "Germany",
    "country_code": "DE",
    "tax_number": "DE987654321",
    "company_number": "HRB 98765",
    "email": "accounts@orbital-power.example",
    "phone": "+493012345678",
    "peppol_id": "0088:9876543210982",
    "is_tax_subject": true
  },
  "supplier_document_number": "OPS-2025-001",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": "2025-11-02",
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": "Ground facility maintenance — March billing period",
  "summary_classification": null,
  "items": [
    {
      "name": "Ground facility maintenance",
      "description": "Monthly ground facility maintenance",
      "quantity": 1,
      "unit": "service",
      "classification": "service",
      "price": 100,
      "gross_price": 119,
      "discounts": [],
      "taxes": [
        {
          "rate": 19,
          "amount": 19,
          "is_deductible": true,
          "deductible_percentage": 100
        }
      ],
      "total": 100,
      "total_with_tax": 119,
      "total_tax": 19
    }
  ],
  "taxes": [
    {
      "rate": 19,
      "base": 100,
      "amount": 19,
      "is_deductible": true,
      "deductible_percentage": 100,
      "reverse_charge": false
    }
  ],
  "total": 100,
  "total_with_tax": 119,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 119,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 1,
  "has_attachment": true,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-20T00:00:00.000Z"
}

Void expense

POST/expenses/{id}/void

Voids a posted expense and frees its supplier_document_number for reuse by a new expense from the same supplier. A voided expense can be restored unless that number has since been reused by another active expense from the same supplier.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstring<resource-id>required

Unique resource identifier. Prefix depends on the resource, for example inv_, cus_, or ent_.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.void('exp_6595a27b5d35015c3ef0c3fd', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

idstring
Other parameters
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
json
{
  "id": "exp_6595a27b5d35015c3ef0c3fd",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
  "type": "invoice",
  "is_draft": false,
  "voided_at": "2025-10-20T12:00:00.000Z",
  "supplier": {
    "name": "Orbital Power Systems GmbH",
    "address": "Energieweg 8",
    "address_2": null,
    "post_code": "10115",
    "city": "Berlin",
    "state": null,
    "country": "Germany",
    "country_code": "DE",
    "tax_number": "DE987654321",
    "company_number": "HRB 98765",
    "email": "accounts@orbital-power.example",
    "phone": "+493012345678",
    "peppol_id": "0088:9876543210982",
    "is_tax_subject": true
  },
  "supplier_document_number": "OPS-2025-001",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": "2025-11-02",
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": "Ground facility maintenance — March billing period",
  "summary_classification": null,
  "items": [
    {
      "name": "Ground facility maintenance",
      "description": "Monthly ground facility maintenance",
      "quantity": 1,
      "unit": "service",
      "classification": "service",
      "price": 100,
      "gross_price": 119,
      "discounts": [],
      "taxes": [
        {
          "rate": 19,
          "amount": 19,
          "is_deductible": true,
          "deductible_percentage": 100
        }
      ],
      "total": 100,
      "total_with_tax": 119,
      "total_tax": 19
    }
  ],
  "taxes": [
    {
      "rate": 19,
      "base": 100,
      "amount": 19,
      "is_deductible": true,
      "deductible_percentage": 100,
      "reverse_charge": false
    }
  ],
  "total": 100,
  "total_with_tax": 119,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 119,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 1,
  "has_attachment": true,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-03T08:00:00.000Z"
}

Disable expense inbound email address

DELETE/expenses/inbound-email

Revokes the entity's active inbound email address; mail sent to it afterwards is not accepted. Idempotent: responds 200 even when no address was active. Previously received messages and the expenses created from them are kept. Requires permission to manage entity settings.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

await sdk.expenses.disableExpenseInboundEmail({
  entity_id: "YOUR_ENTITY_ID"
});

console.log('Deleted successfully');

Returns

json
{
  "available": true,
  "enabled": false,
  "address": null,
  "created_at": null
}

Delete expense

DELETE/expenses/{id}

Deletes an expense together with all of its attachments, including the source file of an OCR recognition. Draft expenses can always be deleted. Posted expenses (including voided ones) can be deleted only when they were entered manually (creation_source=standard) or created by OCR (creation_source=ocr) and did not come from a received e-invoice; expenses created through /expenses/custom, legacy-migrated expenses and expenses from received e-invoices can only be voided (422).

The expense's payments are deleted with it, and each emits a payment.deleted event, exactly like deleting the payment on its own. An expense with credit-note settlements applied to it (or recorded by it) cannot be deleted (422): void it instead. While automatic recognition of the expense's document is still queued or processing, or has finished but its usage is not yet recorded, the request fails with 409 (try again shortly).

Deleting does not change usage: the expense still counts toward the document count of the billing period it was created in, and OCR pages that were scanned stay counted (their usage is kept in the metered usage ledger). Submitting the same document again creates a new expense and a new recognition that is counted again. Stock movements and accounting-recognition entries of the expense are removed.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstring<resource-id>required

Unique resource identifier. Prefix depends on the resource, for example inv_, cus_, or ent_.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

await sdk.expenses.delete('exp_6595a27b5d35015c3ef0c3fd', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log('Deleted successfully');

Delete expense attachment

DELETE/expenses/{id}/attachments/{fileId}

Delete expense attachment

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired
fileIdstringrequired
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

await sdk.expenses.deleteExpenseAttachment('exp_6595a27b5d35015c3ef0c3fd', 'FILE_ID', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log('Deleted successfully');


Retry recognition after a transient failure

POST/expenses/recognitions/{id}/retry

Re-queues a failed recognition job only after an allowed transient provider or source-service error and when attempts remain below max_attempts. Bad or unsupported content should be uploaded as a new expense instead.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired

Expense recognition job ID

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.retryRecognition("erj_6595a27b5d35015c3ef0c3fd", {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

idstring

Recognition job ID

Other parameters
attemptsinteger
max_attemptsinteger
pages_processedintegernullable
page_countintegernullable
source_filenamestringnullable
source_mime_typestring
source_bytesinteger
expense_updated_at_snapshotstring<date-time>
queued_atstring<date-time>
started_atstring<date-time>nullable
completed_atstring<date-time>nullable
created_atstring<date-time>
updated_atstring<date-time>
json
{
  "id": "erj_6595a27b5d35015c3ef0c3fd",
  "entity_id": "entity-id",
  "expense_id": "expense-id",
  "file_metadata_id": "file-metadata-id",
  "status": "queued",
  "provider": "provider",
  "model": "model",
  "parser_version": "parser-version",
  "attempts": 0,
  "max_attempts": 0,
  "pages_processed": 0,
  "page_count": 0,
  "warnings": [
    {
      "code": "missing_required_field",
      "field": "field",
      "message": "message"
    }
  ],
  "provenance": {
    "provider": "mistral",
    "model": "model",
    "parser_version": "parser-version",
    "pages_processed": 0,
    "doc_size_bytes": 0,
    "fields": [
      {
        "field": "field",
        "page": 0,
        "confidence": 0,
        "source": "annotation",
        "note": "note"
      }
    ]
  },
  "reconciliation": {
    "is_reconciled": true,
    "expected_total": 0,
    "expected_total_with_tax": 0,
    "expected_tax": 0,
    "reported_total": 0,
    "reported_total_with_tax": 0,
    "reported_tax": 0,
    "differences": [
      {
        "field": "field",
        "expected": 0,
        "reported": 0,
        "delta": 0
      }
    ]
  },
  "payment_suggestion": {
    "status": "paid",
    "amount": 0,
    "date": "date",
    "method": "method",
    "evidence": [
      "evidence"
    ],
    "confidence": 0,
    "is_partial": true
  },
  "extracted_draft": {
    "type": "invoice",
    "supplier": {
      "name": "name",
      "email": "user@example.com",
      "address": "address",
      "address_2": "address-2",
      "post_code": "post-code",
      "city": "city",
      "state": "state",
      "country": "country",
      "country_code": "country-code",
      "tax_number": "tax-number",
      "company_number": "company-number",
      "phone": "phone",
      "peppol_id": "peppol-id",
      "bank_accounts": [
        {
          "iban": "iban",
          "bic": "bic",
          "bank_name": "bank-name",
          "account_number": "account-number",
          "currency_code": "currency-code"
        }
      ],
      "is_tax_subject": true
    },
    "supplier_document_number": "supplier-document-number",
    "date": "date",
    "date_received": "date-received",
    "date_due": "date-due",
    "date_service": "date-service",
    "date_service_to": "date-service-to",
    "currency_code": "currency-code",
    "transaction_type": "domestic",
    "reference": "reference",
    "note": "note",
    "items": [
      {
        "name": "name",
        "description": "description",
        "quantity": 0,
        "unit": "unit",
        "classification": "product",
        "price": 0,
        "gross_price": 0,
        "discounts": [
          {
            "value": 0,
            "type": "percent"
          }
        ],
        "taxes": [
          {
            "rate": 0,
            "amount": 0,
            "reverse_charge": true,
            "is_deductible": true,
            "deductible_percentage": 0
          }
        ],
        "total": 0,
        "total_with_tax": 0,
        "total_tax": 0
      }
    ],
    "taxes": [
      {
        "rate": 0,
        "base": 0,
        "amount": 0,
        "reverse_charge": true,
        "is_deductible": true,
        "deductible_percentage": 0
      }
    ],
    "total": 0,
    "total_with_tax": 0,
    "total_discount": 0,
    "summary_classification": "product"
  },
  "error_code": "error-code",
  "error_message": "error-message",
  "request_id": "request-id",
  "source_filename": "source-filename",
  "source_mime_type": "source-mime-type",
  "source_bytes": 0,
  "source_content_sha256": "source-content-sha256",
  "simulation_mode": "sandbox_demo",
  "source_replaced": true,
  "expense_updated_at_snapshot": "2025-01-15T10:30:00.000Z",
  "queued_at": "2025-01-15T10:30:00.000Z",
  "started_at": "2025-01-15T10:30:00.000Z",
  "completed_at": "2025-01-15T10:30:00.000Z",
  "created_at": "2025-01-15T10:30:00.000Z",
  "updated_at": "2025-01-15T10:30:00.000Z"
}

Get the latest recognition job for an expense

GET/expenses/{id}/recognition

Returns the latest recognition job linked to the expense, or job: null for manually created expenses. This makes recognition state durable across navigation.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstring<resource-id>required

Unique resource identifier. Prefix depends on the resource, for example inv_, cus_, or ent_.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getLatestRecognition('exp_6595a27b5d35015c3ef0c3fd', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

json
{
  "job": {
    "id": "erj_6595a27b5d35015c3ef0c3fd",
    "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
    "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
    "file_metadata_id": "fil_6595a27b5d35015c3ef0c3fd",
    "status": "queued",
    "attempts": 0,
    "max_attempts": 3,
    "source_mime_type": "application/pdf",
    "source_bytes": 48321,
    "source_content_sha256": "f5c4c9c33d9b42e4f130cb593f17741b30e0fb23ac95a6d91d01bf438467a17c",
    "simulation_mode": null,
    "source_replaced": false,
    "expense_updated_at_snapshot": "2026-07-11T08:00:00.000Z",
    "queued_at": "2026-07-11T08:00:00.000Z",
    "created_at": "2026-07-11T08:00:00.000Z",
    "updated_at": "2026-07-11T08:00:00.000Z"
  }
}

Restore (un-void) an expense

POST/expenses/{id}/restore

Reverses a void, re-activating the expense. Fails with 409 if its supplier_document_number has since been reused by another active expense from the same supplier.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstring<resource-id>required

Unique resource identifier. Prefix depends on the resource, for example inv_, cus_, or ent_.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.restoreExpense('exp_6595a27b5d35015c3ef0c3fd', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

idstring
Other parameters
numberstring
entity_idstring
supplier_idstringnullable
is_draftboolean
voided_atstring<date-time>nullable
deleted_atstring<date-time>nullable
supplier_document_numberstringnullable
datestringnullable
date_receivedstringnullable
date_duestringnullable
date_servicestringnullable
date_service_tostringnullable
currency_codestringnullable
transaction_typestringnullable
referencestringnullable
notestringnullable
totalnumbernullable
total_with_taxnumbernullable
total_convertednumbernullable
total_with_tax_convertednumbernullable
total_discountnumber
total_paidnumber
total_duenumber
paid_in_fullboolean
date_yearinteger
metadatastringnullable
created_atstring<date-time>
updated_atstring<date-time>
attachment_countinteger
has_attachmentboolean
json
{
  "id": "exp_6595a27b5d35015c3ef0c3fd",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "supplier_id": "sup_6595a27b5d35015c3ef0c3fd",
  "type": "invoice",
  "is_draft": false,
  "voided_at": null,
  "supplier": {
    "name": "Orbital Power Systems GmbH",
    "address": "Energieweg 8",
    "address_2": null,
    "post_code": "10115",
    "city": "Berlin",
    "state": null,
    "country": "Germany",
    "country_code": "DE",
    "tax_number": "DE987654321",
    "company_number": "HRB 98765",
    "email": "accounts@orbital-power.example",
    "phone": "+493012345678",
    "peppol_id": "0088:9876543210982",
    "is_tax_subject": true
  },
  "supplier_document_number": "OPS-2025-001",
  "date": "2025-10-03",
  "date_received": "2025-10-03",
  "date_due": "2025-11-02",
  "date_service": null,
  "date_service_to": null,
  "currency_code": "EUR",
  "transaction_type": "domestic",
  "reference": "DE00-2025-001",
  "note": "Ground facility maintenance — March billing period",
  "summary_classification": null,
  "items": [
    {
      "name": "Ground facility maintenance",
      "description": "Monthly ground facility maintenance",
      "quantity": 1,
      "unit": "service",
      "classification": "service",
      "price": 100,
      "gross_price": 119,
      "discounts": [],
      "taxes": [
        {
          "rate": 19,
          "amount": 19,
          "is_deductible": true,
          "deductible_percentage": 100
        }
      ],
      "total": 100,
      "total_with_tax": 119,
      "total_tax": 19
    }
  ],
  "taxes": [
    {
      "rate": 19,
      "base": 100,
      "amount": 19,
      "is_deductible": true,
      "deductible_percentage": 100,
      "reverse_charge": false
    }
  ],
  "total": 100,
  "total_with_tax": 119,
  "total_discount": 0,
  "total_paid": 0,
  "total_due": 119,
  "paid_in_full": false,
  "exchange_rate": null,
  "attachment_count": 1,
  "has_attachment": true,
  "metadata": {
    "source": "manual"
  },
  "created_at": "2025-10-03T08:00:00.000Z",
  "updated_at": "2025-10-03T08:00:00.000Z"
}

Upload expense attachment

POST/expenses/{id}/attachments

Upload expense attachment

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired

Body parameters

filestring<binary>required

File to upload

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';
import fs from 'fs';

const sdk = new SpaceInvoices('YOUR_API_KEY');

// Read file as Buffer
const fileBuffer = fs.readFileSync('/path/to/image.png');
const file = new File([fileBuffer], 'image.png', { type: 'image/png' });

const response = await sdk.expenses.uploadExpenseAttachment('ID', {
  file
}, { entity_id: 'YOUR_ENTITY_ID' });

console.log(response);

Returns

idstring
Other parameters
entity_idstring
business_unit_idstringnullable
invoice_idstringnullable
estimate_idstringnullable
credit_note_idstringnullable
advance_invoice_idstringnullable
delivery_note_idstringnullable
expense_idstringnullable
categorystring
urlstring
formatstring
widthintegernullable
heightintegernullable
bytesinteger
filenamestringnullable
mime_typestring
metadatastringnullable
cache_keystringnullable
created_atstring<date-time>
updated_atstring<date-time>
json
{
  "id": "file_9595a27b5d35015c3ef0c3fa",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "invoice_id": null,
  "estimate_id": null,
  "credit_note_id": null,
  "advance_invoice_id": null,
  "delivery_note_id": null,
  "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
  "category": "attachment",
  "url": "https://storage.example.com/si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
  "secureUrl": "https://storage.example.com/si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
  "publicId": "si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
  "secure_url": "https://storage.example.com/si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
  "public_id": "si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
  "format": "pdf",
  "width": null,
  "height": null,
  "bytes": 245678,
  "filename": "supplier-invoice.pdf",
  "mime_type": "application/pdf",
  "metadata": {},
  "created_at": "2025-10-03T08:05:00.000Z",
  "updated_at": "2025-10-03T08:05:00.000Z"
}

List expense attachments

GET/expenses/{id}/attachments

List expense attachments

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired

Query parameters

limitintegeroptional

Number of results per request.

Default: 10

next_cursorstringoptional

Opaque cursor to fetch the next page of results. Reuse only with the same effective ordering. Use the value from pagination.next_cursor in the previous response.

prev_cursorstringoptional

Opaque cursor to fetch the previous page of results. Reuse only with the same effective ordering. Use the value from pagination.prev_cursor in the previous response.

include_total_countbooleanoptional

Whether to include the total count of items in pagination.total.
Default is true.
When false, pagination.total returns -1 for better performance.

import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getExpenseAttachments('exp_6595a27b5d35015c3ef0c3fd', undefined, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

dataarray of objects
paginationobject

Pagination metadata including cursors and result counts

json
{
  "data": [
    {
      "id": "file_9595a27b5d35015c3ef0c3fa",
      "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
      "invoice_id": null,
      "estimate_id": null,
      "credit_note_id": null,
      "advance_invoice_id": null,
      "delivery_note_id": null,
      "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
      "category": "attachment",
      "url": "https://storage.example.com/si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
      "secureUrl": "https://storage.example.com/si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
      "publicId": "si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
      "secure_url": "https://storage.example.com/si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
      "public_id": "si/entities/ent_6595a27b5d35015c3ef0c3fd/attachments/expense.pdf",
      "format": "pdf",
      "width": null,
      "height": null,
      "bytes": 245678,
      "filename": "supplier-invoice.pdf",
      "mime_type": "application/pdf",
      "metadata": {},
      "created_at": "2025-10-03T08:05:00.000Z",
      "updated_at": "2025-10-03T08:05:00.000Z"
    }
  ],
  "pagination": {
    "total": 1,
    "next_cursor": null,
    "prev_cursor": null,
    "has_more": false
  }
}

List payments affecting an expense

GET/expenses/{id}/payments

List payments affecting an expense

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.getExpensePayments('exp_6595a27b5d35015c3ef0c3fd', {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

dataarray of objects
paginationobject

Pagination metadata including cursors and result counts

json
{
  "data": [
    {
      "id": "pmt_abc123def456",
      "invoice_id": null,
      "credit_note_id": null,
      "advance_invoice_id": null,
      "delivery_note_id": null,
      "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
      "applied_to_expense_id": null,
      "amount": 122,
      "amount_converted": 122,
      "currency_code": "EUR",
      "type": "bank_transfer",
      "date": "2025-10-10T00:00:00.000Z",
      "reference": "DE00-2025-001",
      "tag": null,
      "note": "Supplier payment",
      "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
      "metadata": {},
      "deleted_at": null,
      "created_at": "2025-10-10T08:00:00.000Z",
      "updated_at": "2025-10-10T08:00:00.000Z"
    }
  ],
  "pagination": {
    "total": 1,
    "next_cursor": null,
    "prev_cursor": null,
    "has_more": false
  }
}

Create a payment for an expense

POST/expenses/{id}/payments

Record a direct payment against a finalized supplier invoice expense. The payment is capped at the expense's open balance (total_with_tax minus the payments already recorded), compared at the currency's minor unit (0.01 EUR, 1 JPY, 0.001 KWD). A payment that would exceed it returns 422 with cause.code expense_payment_exceeds_open_balance and records nothing. Concurrent payments on one expense are serialized, so they can never together exceed its total.

Header parameters

entity_idstringoptional

Entity ID on which the request is made. Auto-selected when only one entity exists, required when multiple entities exist.

Path parameters

idstringrequired

Body parameters

amountnumberrequired

Payment amount in the linked document currency's major unit; for EUR, 29.90 means €29.90, not 2,990 cents.

typestringrequired

Possible values: "cash", "bank_transfer", "card", "check", "paypal", "coupon", "other", "advance"

Other parameters
tagstringoptionalnullable
referencestringoptionalnullable
notestringoptionalnullable
import SpaceInvoices from '@spaceinvoices/js-sdk/sdk';

const sdk = new SpaceInvoices('YOUR_API_KEY');

const response = await sdk.expenses.createExpensePayment('exp_6595a27b5d35015c3ef0c3fd', {
  amount: 122,
  type: "bank_transfer",
  date: "2025-10-10",
  reference: "DE00-2025-001",
  note: "Supplier payment"
}, {
  entity_id: "YOUR_ENTITY_ID"
});

console.log(response);

Returns

idstring
Other parameters
invoice_idstringnullable
credit_note_idstringnullable
advance_invoice_idstringnullable
expense_idstringnullable
applied_to_expense_idstringnullable
currency_codestring
amount_convertednumber
tagstringnullable
referencestringnullable
notestringnullable
entity_idstring
deleted_atstring<date-time>nullable
created_atstring<date-time>
updated_atstring<date-time>
json
{
  "id": "pmt_abc123def456",
  "invoice_id": null,
  "credit_note_id": null,
  "advance_invoice_id": null,
  "delivery_note_id": null,
  "expense_id": "exp_6595a27b5d35015c3ef0c3fd",
  "applied_to_expense_id": null,
  "amount": 122,
  "amount_converted": 122,
  "currency_code": "EUR",
  "type": "bank_transfer",
  "date": "2025-10-10T00:00:00.000Z",
  "reference": "DE00-2025-001",
  "tag": null,
  "note": "Supplier payment",
  "entity_id": "ent_6595a27b5d35015c3ef0c3fd",
  "metadata": {},
  "deleted_at": null,
  "created_at": "2025-10-10T08:00:00.000Z",
  "updated_at": "2025-10-10T08:00:00.000Z"
}