Aller au contenu principal

API Reference

Gäld exposes a REST API under /api/v1 for external integrations: ERP connectors, reporting dashboards, automation scripts, etc.

Interactive API docs

A full interactive API reference with try-it-out is available at /docs on your Gäld instance (e.g. https://app.gaeld.ch/docs). You can also download the OpenAPI 3.0 specification at /docs/openapi.yaml for use with Postman, Insomnia, or code generators.

Enterprise feature

API access requires the api_access feature flag enabled on your organisation (available on Starter and Business plans, or on any self-hosted instance).

Authentication

Gäld uses Laravel Sanctum bearer tokens. Two token types are available:

TypeCreated byScopeSurvives user removal?
Personal tokenAny userTied to user + orgNo
Organisation tokenAdmin / OwnerOrg-levelYes

Create a personal token

curl -X POST https://app.gaeld.ch/api/v1/tokens \
-H "Authorization: Bearer $EXISTING_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "My Integration", "abilities": ["invoicing.view", "contacts.view"]}'

Response:

{
"token": "1|abc123...",
"abilities": ["invoicing.view", "contacts.view"]
}

Use the returned token in subsequent requests:

curl https://app.gaeld.ch/api/v1/invoices \
-H "Authorization: Bearer 1|abc123..."

Create an organisation token

Organisation tokens support a wildcard ability ("*") that grants full access:

curl -X POST https://app.gaeld.ch/api/v1/org-tokens \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "ERP Sync", "abilities": ["*"]}'

Token fields

FieldTypeRequiredDescription
namestringYesDisplay name (max 255 chars)
abilitiesstring[]NoPermission scopes (see below). Defaults to all.
expires_in_daysintegerNoToken lifetime in days (1–365). Null = no expiry.

Token abilities

Token abilities mirror the application permission system. Use GET /api/v1/meta/abilities to retrieve the full list at runtime.

ScopeAbilities
Accountingaccounting.view, accounting.create, accounting.edit, accounting.delete, accounting.close-year, accounting.reopen-year
Bankingbanking.view, banking.create, banking.edit, banking.delete, banking.import, banking.reconcile
Contactscontacts.view, contacts.create, contacts.edit, contacts.delete
Expensesexpenses.view, expenses.create, expenses.edit, expenses.delete, expenses.approve
Invoicinginvoicing.view, invoicing.create, invoicing.edit, invoicing.delete, invoicing.finalize, invoicing.record-payment
Organisationorganization.view, organization.edit, organization.manage-users, organization.delete, organization.view-audit-log
Reportingreporting.view
Payrollpayroll.view, payroll.create, payroll.edit, payroll.delete
Migrationmigration.import

Organisation tokens also accept "*" (wildcard) as an ability, which grants all permissions.

Rate Limiting

All API endpoints are rate-limited to 60 requests per minute, keyed by authenticated user ID (or IP address for unauthenticated requests). Exceeding the limit returns 429 Too Many Requests.

Pagination

List endpoints return paginated results using Laravel's LengthAwarePaginator format:

{
"data": [ ... ],
"links": {
"first": "https://app.gaeld.ch/api/v1/invoices?page=1",
"last": "https://app.gaeld.ch/api/v1/invoices?page=5",
"prev": null,
"next": "https://app.gaeld.ch/api/v1/invoices?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"per_page": 20,
"to": 20,
"total": 97
}
}

Default page size is 20 items. Use ?page=N to navigate pages.

Filtering and sorting

List endpoints support query parameters for filtering and sorting:

# Sort by due_date ascending
GET /api/v1/invoices?sort=due_date

# Sort descending (prefix with -)
GET /api/v1/invoices?sort=-total

# Filter by status
GET /api/v1/invoices?filter[status]=sent

# Full-text search
GET /api/v1/invoices?search=ACME

Available options vary by resource — see each endpoint section below.

Endpoints

Tokens

MethodEndpointDescription
GET/api/v1/tokensList personal tokens
POST/api/v1/tokensCreate a personal token
DELETE/api/v1/tokens/{id}Revoke a personal token
GET/api/v1/org-tokensList organisation tokens
POST/api/v1/org-tokensCreate an organisation token
DELETE/api/v1/org-tokens/{id}Revoke an organisation token

Meta

MethodEndpointDescription
GET/api/v1/meta/abilitiesList available token abilities
GET/api/v1/meta/webhook-eventsList available webhook event types

Customers

MethodEndpointDescription
GET/api/v1/customersList customers (paginated)
GET/api/v1/customers/{id}Show customer (includes contact persons)
POST/api/v1/customersCreate customer
PUT/api/v1/customers/{id}Update customer
DELETE/api/v1/customers/{id}Delete customer

Create/Update fields:

FieldTypeCreateUpdateDescription
namestringRequiredOptionalCustomer name (max 255)
emailstringOptionalOptionalEmail address
phonestringOptionalOptionalPhone number (max 50)
addressstringOptionalOptionalStreet address (max 500)
citystringOptionalOptionalCity (max 100)
postal_codestringOptionalOptionalPostal code (max 10)
countrystringOptionalOptionalISO 3166-1 alpha-2 code (e.g. CH)
vat_numberstringOptionalOptionalVAT identification number (max 50)
currencystringOptionalOptionalISO 4217 code (e.g. CHF)
payment_termsstringOptionalOptionalPayment terms text (max 255)

Response fields:

{
"id": "uuid",
"type": "company",
"name": "ACME GmbH",
"email": "info@acme.ch",
"phone": "+41 44 123 45 67",
"address": "Bahnhofstrasse 1",
"city": "Zürich",
"postal_code": "8001",
"country": "CH",
"vat_number": "CHE-123.456.789",
"currency": "CHF",
"payment_terms": "30 days net",
"contact_persons": [
{
"id": "uuid",
"first_name": "Hans",
"last_name": "Müller",
"full_name": "Hans Müller",
"email": "hans@acme.ch",
"phone": "+41 79 000 00 00",
"position": "CEO",
"is_primary": true,
"notes": null,
"created_at": "2025-01-15T10:00:00.000000Z",
"updated_at": "2025-01-15T10:00:00.000000Z"
}
],
"created_at": "2025-01-15T10:00:00.000000Z",
"updated_at": "2025-01-15T10:00:00.000000Z"
}

Invoices

MethodEndpointDescription
GET/api/v1/invoicesList invoices (paginated)
GET/api/v1/invoices/{id}Show invoice (includes lines, payments, customer)
POST/api/v1/invoicesCreate invoice
PUT/api/v1/invoices/{id}Update invoice
DELETE/api/v1/invoices/{id}Delete invoice

Sorting: issue_date (default, desc), due_date, total, number, status

Filters: filter[status], filter[type]

Search: ?search= searches by invoice number and customer name.

Create/Update fields:

FieldTypeCreateUpdateDescription
customer_idUUIDRequiredOptionalMust belong to your organisation
numberstringOptionalOptionalInvoice number (auto-generated if omitted)
issue_datedateRequiredOptionalYYYY-MM-DD
due_datedateOptionalOptionalMust be ≥ issue_date
currencystringOptionalOptionalISO 4217 (default: org currency)
notesstringOptionalOptionalNotes shown on invoice
payment_termsstringOptionalOptionalPayment terms text
linesarrayRequiredOptionalAt least 1 line item
lines[].descriptionstringRequiredRequiredLine description
lines[].quantitydecimalRequiredRequiredMinimum 0.01
lines[].unit_pricedecimalRequiredRequiredMinimum 0
lines[].vat_rate_idUUIDOptionalOptionalMust belong to your organisation

Response fields:

{
"id": "uuid",
"number": "INV-2025-001",
"status": "sent",
"type": "invoice",
"related_invoice_id": null,
"customer": { "...": "CustomerResource" },
"issue_date": "2025-01-15",
"due_date": "2025-02-14",
"subtotal": "1000.00",
"vat_amount": "81.00",
"total": "1081.00",
"currency": "CHF",
"notes": null,
"payment_terms": "30 days net",
"amount_paid": "0.00",
"amount_due": "1081.00",
"lines": [
{
"id": "uuid",
"description": "Consulting services",
"quantity": "10.00",
"unit_price": "100.00",
"amount": "1000.00",
"vat_rate_id": "uuid",
"vat_amount": "81.00",
"sort_order": 1
}
],
"payments": [
{
"id": "uuid",
"amount": "500.00",
"payment_date": "2025-02-01",
"payment_method": "bank_transfer",
"reference": "TX-123",
"created_at": "2025-02-01T08:00:00.000000Z"
}
],
"created_at": "2025-01-15T10:00:00.000000Z",
"updated_at": "2025-01-15T10:00:00.000000Z"
}

Expenses

MethodEndpointDescription
GET/api/v1/expensesList expenses (paginated)
GET/api/v1/expenses/{id}Show expense
POST/api/v1/expensesCreate expense
PUT/api/v1/expenses/{id}Update expense
DELETE/api/v1/expenses/{id}Delete expense

Create/Update fields:

FieldTypeCreateUpdateDescription
categorystringRequiredOptionalCategory name (max 100)
amountdecimalRequiredOptionalMinimum 0.01
datedateRequiredOptionalYYYY-MM-DD
descriptionstringOptionalOptionalExpense description
vat_amountdecimalOptionalOptionalVAT amount (min 0)
vat_rate_idUUIDOptionalOptionalMust belong to your organisation
vendorstringOptionalOptionalVendor name (max 255)
currencystringOptionalOptionalISO 4217 (default: org currency)

Response fields:

{
"id": "uuid",
"category": "Office Supplies",
"description": "Printer paper",
"amount": "45.90",
"vat_amount": "3.52",
"date": "2025-01-20",
"vendor": "Büro AG",
"status": "approved",
"currency": "CHF",
"supplier_id": "uuid",
"created_at": "2025-01-20T14:30:00.000000Z",
"updated_at": "2025-01-20T14:30:00.000000Z"
}

Accounts (read-only)

MethodEndpointDescription
GET/api/v1/accountsList chart of accounts
GET/api/v1/accounts/{id}Show account details

Response fields:

{
"id": "uuid",
"code": "1020",
"name": "Bank",
"type": "asset",
"parent_id": null,
"is_active": true,
"description": "Main bank account"
}

Bank accounts (read-only)

MethodEndpointDescription
GET/api/v1/bank-accountsList bank accounts
GET/api/v1/bank-accounts/{id}Show bank account

Response fields:

{
"id": "uuid",
"name": "PostFinance CHF",
"iban": "CH93 0076 2011 6238 5295 7",
"bank_name": "PostFinance",
"currency": "CHF",
"balance": "12500.00",
"is_active": true,
"account_id": "uuid",
"created_at": "2025-01-01T00:00:00.000000Z",
"updated_at": "2025-03-15T09:00:00.000000Z"
}

Webhooks

MethodEndpointDescription
GET/api/v1/webhooksList webhooks
GET/api/v1/webhooks/{id}Show webhook
POST/api/v1/webhooksCreate webhook
PUT/api/v1/webhooks/{id}Update webhook
DELETE/api/v1/webhooks/{id}Delete webhook
POST/api/v1/webhooks/{id}/regenerate-secretRegenerate signing secret

Create/Update fields:

FieldTypeCreateUpdateDescription
urlstringRequiredOptionalHTTPS endpoint URL (max 2048)
eventsstring[]RequiredOptionalAt least 1 event (see Webhooks)
is_activebooleanOptionalOptionalDefault: true

For webhook events, payload format, delivery, and signature verification, see the dedicated Webhooks page.

Error format

All error responses follow a consistent JSON format:

{
"message": "The given data was invalid.",
"errors": {
"name": ["The name field is required."]
}
}
HTTP CodeMeaning
401Unauthenticated — invalid or missing token
403Forbidden — token lacks required ability, or feature not enabled
404Resource not found (or belongs to another organisation)
422Validation error — check errors object for field details
429Rate limit exceeded — wait and retry