# Invoices

Invoice management, recipients, and location settings

## GET /api/v1/invoice-location-settings

Get invoice location settings

Retrieve invoice settings for a specific location. Creates default settings if none exist.

**Permissions:** 🔵 `invoices.read`

Query parameters:
- `locationId` (number, required) — Location ID to fetch settings for (required)

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    defaultPaymentTermsDays: number
    invoiceNumberPrefix?: string | null
    invoiceNumberCounter: number
    minInvoiceAmount: number
    senderName?: string | null
    senderAddressLine1?: string | null
    senderAddressLine2?: string | null
    senderPostalCode?: string | null
    senderCity?: string | null
    senderCountry?: string | null
    senderEmail?: string | null
    senderPhone?: string | null
    senderOrganizationNumber?: string | null
    senderVatNumber?: string | null
    senderLogoUrl?: string | null
    bankAccountNumber?: string | null
    bankName?: string | null
    swiftBic?: string | null
    iban?: string | null
    paymentReferencePrefix?: string | null
    invoiceFooterText?: string | null
    invoiceTermsText?: string | null
    latePaymentFee: number
    latePaymentInterestRate: number
    autoGenerateEnabled: boolean
    autoSendOnGeneration: boolean
    defaultInvoiceSendMode: "manual" | "scheduled" | "immediate"
    defaultInvoiceSchedule: {
      scheduleType: "weekly" | "monthly" | "interval_days"
      dayOfWeek: number | null
      dayOfMonth: number | null
      intervalDays: number | null
      timeOfDay: string
      timezone: string
    } | null
    registerPurchasesInCashRegister: boolean
    collectionPeriodType: "calendar_month" | "rolling_30_days" | "weekly"
    reminderEnabled: boolean
    firstReminderDaysAfterDue: number
    secondReminderDaysAfterDue: number
    thirdReminderDaysAfterDue: number
    reminderFeeAmount: number
    autoMarkOverdueDays: number
    currency: string
    overrideParentSettings: boolean
    shareInvoiceNumberSeries: boolean
    allowChildRecipientCreation: boolean
    canCreateRecipients: boolean
    requiredRecipientFields: "name" | "email" | "organizationName" | "organizationNumber" | "phone" | "billingAddressLine1" | "billingAddressLine2" | "postalCode" | "city" | "country" | "reference" | "contactPerson" | "vatNumber"[]
    posReferenceRequirement: "optional" | "required" | "existing"
    sourceLocationId: number
    sourceLocationName?: string | null
    isInherited: boolean
    hasParent: boolean
    numberSeriesSourceLocationId: number
    numberSeriesSourceLocationName?: string | null
    createdAt: string // date-time
    updatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## PUT /api/v1/invoice-location-settings

Update invoice location settings

Update invoice settings for a specific location. Creates settings if they do not exist (upsert). All fields except locationId are optional for partial updates.

**Permissions:** 🟠 `invoices.update`

Request body:

```ts
{
  locationId: number
  defaultPaymentTermsDays?: number
  invoiceNumberPrefix?: string | null
  minInvoiceAmount?: number
  senderName?: string | null
  senderAddressLine1?: string | null
  senderAddressLine2?: string | null
  senderPostalCode?: string | null
  senderCity?: string | null
  senderCountry?: string | null
  senderEmail?: string | null
  senderPhone?: string | null
  senderOrganizationNumber?: string | null
  senderVatNumber?: string | null
  senderLogoUrl?: string | null
  bankAccountNumber?: string | null
  bankName?: string | null
  swiftBic?: string | null
  iban?: string | null
  paymentReferencePrefix?: string | null
  invoiceFooterText?: string | null
  invoiceTermsText?: string | null
  latePaymentFee?: number
  latePaymentInterestRate?: number
  autoGenerateEnabled?: boolean
  autoSendOnGeneration?: boolean
  defaultInvoiceSendMode?: "manual" | "scheduled" | "immediate"
  defaultInvoiceSchedule?: {
    scheduleType: "weekly" | "monthly" | "interval_days"
    dayOfWeek: number | null
    dayOfMonth: number | null
    intervalDays: number | null
    timeOfDay: string
    timezone: string
  } | null
  registerPurchasesInCashRegister?: boolean
  collectionPeriodType?: "calendar_month" | "rolling_30_days" | "weekly"
  reminderEnabled?: boolean
  firstReminderDaysAfterDue?: number
  secondReminderDaysAfterDue?: number
  thirdReminderDaysAfterDue?: number
  reminderFeeAmount?: number
  autoMarkOverdueDays?: number
  currency?: string
  overrideParentSettings?: boolean
  shareInvoiceNumberSeries?: boolean
  allowChildRecipientCreation?: boolean
  requiredRecipientFields?: "name" | "email" | "organizationName" | "organizationNumber" | "phone" | "billingAddressLine1" | "billingAddressLine2" | "postalCode" | "city" | "country" | "reference" | "contactPerson" | "vatNumber"[]
  posReferenceRequirement?: "optional" | "required" | "existing"
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    defaultPaymentTermsDays: number
    invoiceNumberPrefix?: string | null
    invoiceNumberCounter: number
    minInvoiceAmount: number
    senderName?: string | null
    senderAddressLine1?: string | null
    senderAddressLine2?: string | null
    senderPostalCode?: string | null
    senderCity?: string | null
    senderCountry?: string | null
    senderEmail?: string | null
    senderPhone?: string | null
    senderOrganizationNumber?: string | null
    senderVatNumber?: string | null
    senderLogoUrl?: string | null
    bankAccountNumber?: string | null
    bankName?: string | null
    swiftBic?: string | null
    iban?: string | null
    paymentReferencePrefix?: string | null
    invoiceFooterText?: string | null
    invoiceTermsText?: string | null
    latePaymentFee: number
    latePaymentInterestRate: number
    autoGenerateEnabled: boolean
    autoSendOnGeneration: boolean
    defaultInvoiceSendMode: "manual" | "scheduled" | "immediate"
    defaultInvoiceSchedule: {
      scheduleType: "weekly" | "monthly" | "interval_days"
      dayOfWeek: number | null
      dayOfMonth: number | null
      intervalDays: number | null
      timeOfDay: string
      timezone: string
    } | null
    registerPurchasesInCashRegister: boolean
    collectionPeriodType: "calendar_month" | "rolling_30_days" | "weekly"
    reminderEnabled: boolean
    firstReminderDaysAfterDue: number
    secondReminderDaysAfterDue: number
    thirdReminderDaysAfterDue: number
    reminderFeeAmount: number
    autoMarkOverdueDays: number
    currency: string
    overrideParentSettings: boolean
    shareInvoiceNumberSeries: boolean
    allowChildRecipientCreation: boolean
    canCreateRecipients: boolean
    requiredRecipientFields: "name" | "email" | "organizationName" | "organizationNumber" | "phone" | "billingAddressLine1" | "billingAddressLine2" | "postalCode" | "city" | "country" | "reference" | "contactPerson" | "vatNumber"[]
    posReferenceRequirement: "optional" | "required" | "existing"
    sourceLocationId: number
    sourceLocationName?: string | null
    isInherited: boolean
    hasParent: boolean
    numberSeriesSourceLocationId: number
    numberSeriesSourceLocationName?: string | null
    createdAt: string // date-time
    updatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoice-recipients

List invoice recipients

List all invoice recipients for a location with optional filtering and pagination.

**Permissions:** 🔵 `invoices.read`

Query parameters:
- `locationId` (number, required) — Location ID (required)
- `isActive` (boolean, optional) — Filter by active status
- `search` (string, optional) — Match against name, organization name, email or organization number
- `page` (number, optional) — Page number
- `limit` (number, optional) — Items per page

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    items: Array<{
        id: string // uuid
        locationId: number
        name: string
        email: string
        organizationName?: string | null
        organizationNumber?: string | null
        phone?: string | null
        billingAddressLine1?: string | null
        billingAddressLine2?: string | null
        postalCode?: string | null
        city?: string | null
        country?: string | null
        reference?: string | null
        contactPerson?: string | null
        vatNumber?: string | null
        totalInvoicedAmount: number
        totalPaidAmount: number
        outstandingAmount: number
        invoiceCount: number
        isActive: boolean
        showInvoiceAddOns: boolean
        invoiceReferenceGrouping: "per_reference" | "combined"
        sourceLocationId: number
        sourceLocationName?: string | null
        isInherited: boolean
        relationship: "local" | "ancestor" | "descendant"
        createdAt: string // date-time
        updatedAt: string // date-time
      }>
    pagination: {
      page: number
      limit: number
      total: number
      totalPages: number
    }
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoice-recipients

Create invoice recipient

Create a new invoice recipient for a location.

**Permissions:** 🟢 `invoices.create`

Request body:

```ts
{
  locationId: number
  name: string
  email: string
  organizationName?: string
  organizationNumber?: string
  phone?: string
  billingAddressLine1?: string
  billingAddressLine2?: string
  postalCode?: string
  city?: string
  country: string
  reference?: string
  contactPerson?: string
  vatNumber?: string
  showInvoiceAddOns?: boolean
  invoiceReferenceGrouping?: "per_reference" | "combined"
}
```

Response 201 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    name: string
    email: string
    organizationName?: string | null
    organizationNumber?: string | null
    phone?: string | null
    billingAddressLine1?: string | null
    billingAddressLine2?: string | null
    postalCode?: string | null
    city?: string | null
    country?: string | null
    reference?: string | null
    contactPerson?: string | null
    vatNumber?: string | null
    totalInvoicedAmount: number
    totalPaidAmount: number
    outstandingAmount: number
    invoiceCount: number
    isActive: boolean
    showInvoiceAddOns: boolean
    invoiceReferenceGrouping: "per_reference" | "combined"
    sourceLocationId: number
    sourceLocationName?: string | null
    isInherited: boolean
    relationship: "local" | "ancestor" | "descendant"
    createdAt: string // date-time
    updatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoice-recipients/{recipientId}

Get invoice recipient

Get a single invoice recipient by ID.

**Permissions:** 🔵 `invoices.read`

Path parameters:
- `recipientId` (string, required) — Recipient UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    name: string
    email: string
    organizationName?: string | null
    organizationNumber?: string | null
    phone?: string | null
    billingAddressLine1?: string | null
    billingAddressLine2?: string | null
    postalCode?: string | null
    city?: string | null
    country?: string | null
    reference?: string | null
    contactPerson?: string | null
    vatNumber?: string | null
    totalInvoicedAmount: number
    totalPaidAmount: number
    outstandingAmount: number
    invoiceCount: number
    isActive: boolean
    showInvoiceAddOns: boolean
    invoiceReferenceGrouping: "per_reference" | "combined"
    sourceLocationId: number
    sourceLocationName?: string | null
    isInherited: boolean
    relationship: "local" | "ancestor" | "descendant"
    createdAt: string // date-time
    updatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## PUT /api/v1/invoice-recipients/{recipientId}

Update invoice recipient

Update an existing invoice recipient. All fields are optional for partial updates.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `recipientId` (string, required) — Recipient UUID

Request body:

```ts
{
  name?: string
  email?: string
  organizationName?: string | null
  organizationNumber?: string | null
  phone?: string | null
  billingAddressLine1?: string | null
  billingAddressLine2?: string | null
  postalCode?: string | null
  city?: string | null
  country?: string | null
  reference?: string | null
  contactPerson?: string | null
  vatNumber?: string | null
  isActive?: boolean
  showInvoiceAddOns?: boolean
  invoiceReferenceGrouping?: "per_reference" | "combined"
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    name: string
    email: string
    organizationName?: string | null
    organizationNumber?: string | null
    phone?: string | null
    billingAddressLine1?: string | null
    billingAddressLine2?: string | null
    postalCode?: string | null
    city?: string | null
    country?: string | null
    reference?: string | null
    contactPerson?: string | null
    vatNumber?: string | null
    totalInvoicedAmount: number
    totalPaidAmount: number
    outstandingAmount: number
    invoiceCount: number
    isActive: boolean
    showInvoiceAddOns: boolean
    invoiceReferenceGrouping: "per_reference" | "combined"
    sourceLocationId: number
    sourceLocationName?: string | null
    isInherited: boolean
    relationship: "local" | "ancestor" | "descendant"
    createdAt: string // date-time
    updatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## DELETE /api/v1/invoice-recipients/{recipientId}

Delete invoice recipient

Permanently delete an invoice recipient that has no invoices.

**Permissions:** 🔴 `invoices.delete`

Path parameters:
- `recipientId` (string, required) — Recipient UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    deleted: true
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoice-recipients/{recipientId}/lift

Lift invoice recipient

Move a recipient owned by a descendant location into the viewing parent while preserving invoice links.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `recipientId` (string, required) — Recipient UUID

Request body:

```ts
{
  targetLocationId: number
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    name: string
    email: string
    organizationName?: string | null
    organizationNumber?: string | null
    phone?: string | null
    billingAddressLine1?: string | null
    billingAddressLine2?: string | null
    postalCode?: string | null
    city?: string | null
    country?: string | null
    reference?: string | null
    contactPerson?: string | null
    vatNumber?: string | null
    totalInvoicedAmount: number
    totalPaidAmount: number
    outstandingAmount: number
    invoiceCount: number
    isActive: boolean
    showInvoiceAddOns: boolean
    invoiceReferenceGrouping: "per_reference" | "combined"
    sourceLocationId: number
    sourceLocationName?: string | null
    isInherited: boolean
    relationship: "local" | "ancestor" | "descendant"
    createdAt: string // date-time
    updatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoice-recipients/{recipientId}/rules

List recipient rules

List all active eligibility rules for an invoice recipient.

**Permissions:** 🔵 `invoices.read`

Path parameters:
- `recipientId` (string, required) — Recipient UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    rules: Array<{
        id: string // uuid
        recipientId: string // uuid
        locationId: number
        ruleType: "email_exact" | "email_wildcard" | "user_id"
        ruleValue: string
        isActive: boolean
        maxCreditLimit?: number | null
        autoApprove: boolean
        createdAt: string // date-time
        updatedAt: string // date-time
        userName?: string | null
        userEmail?: string | null
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoice-recipients/{recipientId}/rules

Create recipient rule

Create a new eligibility rule for automatic invoice assignment.

**Permissions:** 🟢 `invoices.create`

Path parameters:
- `recipientId` (string, required) — Recipient UUID

Request body:

```ts
{
  locationId: number
  ruleType: "email_exact" | "email_wildcard" | "user_id"
  ruleValue: string
  maxCreditLimit?: number
  autoApprove?: boolean
}
```

Response 201 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    recipientId: string // uuid
    locationId: number
    ruleType: "email_exact" | "email_wildcard" | "user_id"
    ruleValue: string
    isActive: boolean
    maxCreditLimit?: number | null
    autoApprove: boolean
    createdAt: string // date-time
    updatedAt: string // date-time
    userName?: string | null
    userEmail?: string | null
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## DELETE /api/v1/invoice-recipients/{recipientId}/rules/{ruleId}

Delete recipient rule

Delete an eligibility rule.

**Permissions:** 🔴 `invoices.delete`

Path parameters:
- `recipientId` (string, required) — Recipient UUID
- `ruleId` (string, required) — Rule UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    deleted: true
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoices

List invoices

List all invoices for a location with optional filtering and pagination.

**Permissions:** 🔵 `invoices.read`

Query parameters:
- `locationId` (number, required) — Location ID (required)
- `includeChildren` (boolean, optional) — Include authorized descendants of locationId.
- `locationIds` (string, optional) — Optional comma-separated subset of the resolved location hierarchy.
- `recipientId` (string, optional) — Filter by recipient
- `status` ("draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft", optional) — Filter by status
- `invoiceType` ("manual" | "auto_generated" | "credit", optional) — Filter by invoice type
- `startDate` (string, optional) — Filter by start date
- `endDate` (string, optional) — Filter by end date
- `page` (number, optional) — Page number
- `limit` (number, optional) — Items per page

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    items: Array<{
        id: string // uuid
        locationId: number
        recipientId: string // uuid
        referenceId?: string | null // uuid
        reference?: string | null
        invoiceNumber: string
        status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
        invoiceType: "manual" | "auto_generated" | "credit"
        collectionPeriodStart?: string | null // date-time
        collectionPeriodEnd?: string | null // date-time
        totalAmount: number
        taxAmount: number
        subtotalAmount: number
        currency: string
        dueDate: string // date
        issuedDate?: string | null // date
        paidDate?: string | null // date
        paymentReference?: string | null
        notes?: string | null
        createdBy?: number | null
        createdAt: string // date-time
        updatedAt: string // date-time
        originalInvoiceId?: string | null // uuid
        timeline?: unknown[]
      }>
    pagination: {
      page: number
      limit: number
      total: number
      totalPages: number
    }
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices

Create invoice

Create a new invoice. Invoice number is automatically generated.

**Permissions:** 🟢 `invoices.create`

Request body:

```ts
{
  locationId: number
  recipientId: string // uuid
  referenceId?: string // uuid
  dueDate: string // date
  currency?: string
  invoiceType?: "manual" | "auto_generated"
  collectionPeriodStart?: string // date-time
  collectionPeriodEnd?: string // date-time
  totalAmount?: number
  taxAmount?: number
  subtotalAmount?: number
  issuedDate?: string // date
  paymentReference?: string
  notes?: string
  purchaseIds?: number[]
}
```

Response 201 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoices/{invoiceId}

Get invoice

Get a single invoice by ID.

**Permissions:** 🔵 `invoices.read`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## PUT /api/v1/invoices/{invoiceId}

Update invoice

Update an existing invoice. All fields are optional for partial updates.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Request body:

```ts
{
  status?: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
  dueDate?: string // date
  issuedDate?: string | null // date
  paidDate?: string | null // date
  paymentReference?: string | null
  notes?: string | null
  totalAmount?: number
  taxAmount?: number
  subtotalAmount?: number
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## DELETE /api/v1/invoices/{invoiceId}

Delete invoice

Delete a draft invoice. Only draft or auto_draft invoices can be deleted.

**Permissions:** 🔴 `invoices.delete`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    deleted: true
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/cancel

Void invoice

Void an unsent draft invoice.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/credit-invoices

Create credit invoice

Create a negative draft invoice from selected lines on a sent invoice. Amounts are specified in whole cents.

**Permissions:** 🟢 `invoices.create`

Path parameters:
- `invoiceId` (string, required) — Original invoice UUID

Request body:

```ts
{
  lines: Array<{
      lineItemId: integer
      amountCents: integer
    }>
  notes?: string
}
```

Response 201 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/mark-paid

Mark invoice as paid

Mark an invoice as paid. Cannot mark cancelled invoices as paid.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Request body:

```ts
{
  paymentReference?: string
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/mark-sent

Mark invoice as sent

Mark a draft invoice as sent without emailing it or creating it in an accounting integration.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoices/{invoiceId}/pdf-data

Get invoice PDF data

Get all data needed for PDF generation (invoice, recipient, settings, location, purchases).

**Permissions:** 🔵 `invoices.read`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    invoice: {
      id: string // uuid
      locationId: number
      recipientId: string // uuid
      referenceId?: string | null // uuid
      reference?: string | null
      invoiceNumber: string
      status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
      invoiceType: "manual" | "auto_generated" | "credit"
      collectionPeriodStart?: string | null // date-time
      collectionPeriodEnd?: string | null // date-time
      totalAmount: number
      taxAmount: number
      subtotalAmount: number
      currency: string
      dueDate: string // date
      issuedDate?: string | null // date
      paidDate?: string | null // date
      paymentReference?: string | null
      notes?: string | null
      createdBy?: number | null
      createdAt: string // date-time
      updatedAt: string // date-time
      originalInvoiceId?: string | null // uuid
      timeline?: { … }[]
    }
    recipient?: {
      id: string // uuid
      locationId: number
      name: string
      email: string
      organizationName?: string | null
      organizationNumber?: string | null
      phone?: string | null
      billingAddressLine1?: string | null
      billingAddressLine2?: string | null
      postalCode?: string | null
      city?: string | null
      country?: string | null
      reference?: string | null
      contactPerson?: string | null
      vatNumber?: string | null
      totalInvoicedAmount: number
      totalPaidAmount: number
      outstandingAmount: number
      invoiceCount: number
      isActive: boolean
      showInvoiceAddOns: boolean
      invoiceReferenceGrouping: "per_reference" | "combined"
      sourceLocationId: number
      sourceLocationName?: string | null
      isInherited: boolean
      relationship: "local" | "ancestor" | "descendant"
      createdAt: string // date-time
      updatedAt: string // date-time
    } | null
    settings?: {
      id: string // uuid
      locationId: number
      defaultPaymentTermsDays: number
      invoiceNumberPrefix?: string | null
      invoiceNumberCounter: number
      minInvoiceAmount: number
      senderName?: string | null
      senderAddressLine1?: string | null
      senderAddressLine2?: string | null
      senderPostalCode?: string | null
      senderCity?: string | null
      senderCountry?: string | null
      senderEmail?: string | null
      senderPhone?: string | null
      senderOrganizationNumber?: string | null
      senderVatNumber?: string | null
      senderLogoUrl?: string | null
      bankAccountNumber?: string | null
      bankName?: string | null
      swiftBic?: string | null
      iban?: string | null
      paymentReferencePrefix?: string | null
      invoiceFooterText?: string | null
      invoiceTermsText?: string | null
      latePaymentFee: number
      latePaymentInterestRate: number
      autoGenerateEnabled: boolean
      autoSendOnGeneration: boolean
      defaultInvoiceSendMode: "manual" | "scheduled" | "immediate"
      defaultInvoiceSchedule: {
        scheduleType: "weekly" | "monthly" | "interval_days"
        dayOfWeek: number | null
        dayOfMonth: number | null
        intervalDays: number | null
        timeOfDay: string
        timezone: string
      } | null
      registerPurchasesInCashRegister: boolean
      collectionPeriodType: "calendar_month" | "rolling_30_days" | "weekly"
      reminderEnabled: boolean
      firstReminderDaysAfterDue: number
      secondReminderDaysAfterDue: number
      thirdReminderDaysAfterDue: number
      reminderFeeAmount: number
      autoMarkOverdueDays: number
      currency: string
      overrideParentSettings: boolean
      shareInvoiceNumberSeries: boolean
      allowChildRecipientCreation: boolean
      canCreateRecipients: boolean
      requiredRecipientFields: "name" | "email" | "organizationName" | "organizationNumber" | "phone" | "billingAddressLine1" | "billingAddressLine2" | "postalCode" | "city" | "country" | "reference" | "contactPerson" | "vatNumber"[]
      posReferenceRequirement: "optional" | "required" | "existing"
      sourceLocationId: number
      sourceLocationName?: string | null
      isInherited: boolean
      hasParent: boolean
      numberSeriesSourceLocationId: number
      numberSeriesSourceLocationName?: string | null
      createdAt: string // date-time
      updatedAt: string // date-time
    } | null
    location?: {
      id: number
      name?: string | null
      address?: string | null
      postalCode?: string | null
      city?: string | null
      country?: string | null
      phone?: string | null
      organizationNumber?: string | null
      email?: string | null
      vatNumber?: string | null
    } | null
    purchaseDetails: Array<{
        id: number
        intentId: string
        purchasedAt: string // date-time
        totalAmountCents: number
        vatAmountCents: number
        items?: string | null
        reference?: string | null
        orderNumber?: string | null
        orderComments?: string | null
        lineItems: unknown[]
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/purchases

Add purchases to invoice

Add purchases to an invoice. Only draft invoices can have purchases added.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Request body:

```ts
{
  purchaseIds: number[]
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## DELETE /api/v1/invoices/{invoiceId}/purchases/{purchaseId}

Remove purchase from invoice

Remove a purchase from an invoice. Only draft invoices can have purchases removed.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID
- `purchaseId` (number, required) — Purchase ID to remove

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## PATCH /api/v1/invoices/{invoiceId}/purchases/{purchaseId}

Set a purchase's reference on an invoice

Set or clear the reference shown for one purchase on an invoice. Only draft invoices can change.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID
- `purchaseId` (number, required) — Purchase ID on the invoice

Request body:

```ts
{
  reference: string | null
}
```

Response 200 — Default Response

```ts
{
  status?: string
  data?: {
    purchaseId?: number
    reference?: string | null
  }
}
```

## POST /api/v1/invoices/{invoiceId}/send

Send invoice

Send an invoice to the recipient: generates the PDF server-side, stores it in GCS, emails the recipient (PDF attached + link) via communication-service, and marks the invoice as sent. Only draft invoices can be sent.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
    pdfUrl: string
    emailSentTo: string
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/send-reminder

Send invoice reminder

Send a payment reminder for an overdue invoice.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Request body:

```ts
{
  reminderNumber: number
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    sent: boolean
    reminderNumber: number
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/send-to-fortnox

Send invoice

Send an invoice to the recipient: generates the PDF server-side, stores it in GCS, emails the recipient (PDF attached + link) via communication-service, and marks the invoice as sent. Only draft invoices can be sent.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    locationId: number
    recipientId: string // uuid
    referenceId?: string | null // uuid
    reference?: string | null
    invoiceNumber: string
    status: "draft" | "sent" | "paid" | "overdue" | "cancelled" | "auto_draft"
    invoiceType: "manual" | "auto_generated" | "credit"
    collectionPeriodStart?: string | null // date-time
    collectionPeriodEnd?: string | null // date-time
    totalAmount: number
    taxAmount: number
    subtotalAmount: number
    currency: string
    dueDate: string // date
    issuedDate?: string | null // date
    paidDate?: string | null // date
    paymentReference?: string | null
    notes?: string | null
    createdBy?: number | null
    createdAt: string // date-time
    updatedAt: string // date-time
    originalInvoiceId?: string | null // uuid
    timeline?: Array<{
        id: string
        action: "created" | "updated" | "sent" | "marked_sent" | "sent_to_fortnox" | "paid" | "voided" | "credit_created" | "purchases_added" | "purchase_removed"
        occurredAt: string // date-time
        actor: { … }
        details: { … }
      }>
    pdfUrl: string
    emailSentTo: string
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/{invoiceId}/upload-pdf

Upload invoice PDF

Upload a generated PDF for an invoice. The PDF should be base64-encoded.

**Permissions:** 🟠 `invoices.update`

Path parameters:
- `invoiceId` (string, required) — Invoice UUID

Request body:

```ts
{
  pdfBase64: string
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    id: string // uuid
    invoiceId: string // uuid
    pdfUrl: string
    cdnPath: string
    fileSize: number
    generatedAt: string // date-time
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/auto-send/run

Run auto-send sweep

Claim due auto-send schedules and send their accumulated draft invoices. Invoked by Cloud Scheduler every 15 minutes with an INTERNAL-tier API key. Idempotent: claiming advances next_run_at so concurrent calls cannot double-send.

**Permissions:** 🟠 `invoices.update`

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    schedulesProcessed: number
    invoicesSent: number
    invoicesFailed: number
    details?: Array<{
        recipientId?: string
        recipientName?: string
        sent?: unknown[]
        failed?: unknown[]
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoices/check-eligibility

Check invoice eligibility

Check if a user/email is eligible for invoice payment at a location.

**Permissions:** 🔵 `invoices.read`

Query parameters:
- `locationId` (number, required) — Location ID (required)
- `email` (string, required) — Email to check eligibility for (required)
- `userId` (number, optional) — User ID to check eligibility for (optional)

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    eligible: boolean
    recipientId?: string | null
    creditLimit?: number | null
    outstandingAmount?: number | null
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## POST /api/v1/invoices/start-purchase

Start invoice purchase (POS)

Start an invoice-based purchase from POS. Creates a tab settlement and initiates payment via the invoice PSP.

**Permissions:** 🟢 `invoices.create`

Request body:

```ts
{
  tabId: string // uuid
  locationId: number
  recipientId?: string // uuid
  referenceId?: string // uuid
  selectedKitchenDispatchItemIds?: string[]
  voucherCodes?: string[]
}
```

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    success: boolean
    purchaseIntentId: string // uuid
    invoiceReference?: string | null
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoices/stats

Invoice summary stats

Summary cards + 12-month volume series for the invoices page. Amounts are in major currency units (same unit as invoice totalAmount). Unsent = draft + auto_draft; sent = sent + overdue (issued, unpaid).

**Permissions:** 🔵 `invoices.read`

Query parameters:
- `locationId` (number, required) — Location ID
- `includeChildren` (boolean, optional) — Include authorized descendant locations

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    unsent: {
      count: number
      amount: number
    }
    sent: {
      count: number
      amount: number
    }
    monthly: Array<{
        month: string
        amount: number
        count: number
      }>
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```

## GET /api/v1/invoices/unclaimed-purchases

Get unclaimed invoice purchases

Get purchases that were made with invoice payment but not yet assigned to an invoice.

**Permissions:** 🔵 `invoices.read`

Query parameters:
- `locationId` (number, required) — Location ID (required)
- `page` (number, optional) — Page number
- `limit` (number, optional) — Items per page

Response 200 — Default Response

```ts
{
  status: "success"
  data: {
    items: Array<{
        id: number
        intentId: string
        purchasedAt: string // date-time
        payingUserId?: number | null
        state: string
        currencyCode: string
        totalAmountCents: number
        vatAmountCents: number
        items?: string | null
        userEmail?: string | null
        userName?: string | null
        reference?: string | null
        orderNumber?: string | null
      }>
    pagination: {
      page: number
      limit: number
      total: number
      totalPages: number
    }
  }
  meta: {
    requestId: string
    timestamp: string // date-time
    executionTimeMs: number
  }
}
```
