REST API for programmatic access to fj data. Requires bearer token authentication.
All endpoints require a bearer token in the Authorization header:
Authorization: Bearer fj_sk_...
Create API keys via the web UI at /keys or manage them in FJ_HOME/.api_keys.json.
GET /api/v1/health - Health check (no authentication required)
{
"status": "ok"
}GET /api/v1/clients - List all clients
{
"clients": [
{
"shortname": "acme",
"company-name": "ACME Corp",
"c/o-name": null,
"street": "123 Main St",
"areacode": "12345",
"city": "Springfield",
"country": "US",
"tax_uid": "US123456789",
"remarks": null,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-15T10:30:00Z",
"revision": 1
}
]
}GET /api/v1/clients/{shortname} - Get single client
{
"shortname": "acme",
"company-name": "ACME Corp",
"c/o-name": null,
"street": "123 Main St",
"areacode": "12345",
"city": "Springfield",
"country": "US",
"tax_uid": "US123456789",
"remarks": null,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-15T10:30:00Z",
"revision": 1
}GET /api/v1/rates - List all rates
{
"rates": [
{
"shortname": "standard",
"hourly": 150,
"hours_per_day": 8,
"daily": 1200,
"weekly": 6000,
"remarks": null,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-15T10:30:00Z",
"revision": 1
}
]
}GET /api/v1/rates/{shortname} - Get single rate
{
"shortname": "standard",
"hourly": 150,
"hours_per_day": 8,
"daily": 1200,
"weekly": 6000,
"remarks": null,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-15T10:30:00Z",
"revision": 1
}GET /api/v1/invoices - List all invoices
{
"invoices": [
{
"id": "2024-001",
"due_date": "2024-01-29",
"paid_date": null,
"client_shortname": "acme",
"date": "2024-01-15",
"project_name": "Website Redesign",
"oms_project": null,
"year": 2024,
"applicable_rates": "standard",
"leistungszeitraum": "January 2024",
"leistungszeitraum_bis": null,
"terms_of_payment": "binnen 14 Tagen",
"coverletter": {
"greeting": null
},
"footer": {
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-15T10:30:00Z",
"revision": 1,
"total": 150000
}
]
}Note: total is in EUR (150000 = €150,000.00).
GET /api/v1/invoices/{id} - Get single invoice
{
"id": "2024-001",
"due_date": "2024-01-29",
"paid_date": null,
"client_shortname": "acme",
"date": "2024-01-15",
"project_name": "Website Redesign",
"oms_project": null,
"year": 2024,
"applicable_rates": "standard",
"leistungszeitraum": "January 2024",
"leistungszeitraum_bis": null,
"terms_of_payment": "binnen 14 Tagen",
"coverletter": {
"greeting": null
},
"footer": {
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-15T10:30:00Z",
"revision": 1,
"total": 150000
}POST /api/v1/invoices/{id}/paid - Mark invoice as paid
Sets paid_date to today. Returns error if already paid.
{
"success": true,
"invoice": {
"id": "2024-001",
"due_date": "2024-01-29",
"paid_date": "2024-11-27",
"client_shortname": "acme",
"date": "2024-01-15",
"project_name": "Website Redesign",
"oms_project": null,
"year": 2024,
"applicable_rates": "standard",
"leistungszeitraum": "January 2024",
"leistungszeitraum_bis": null,
"terms_of_payment": "binnen 14 Tagen",
"coverletter": {
"greeting": null
},
"footer": {
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-11-27T14:00:00Z",
"revision": 1,
"total": 150000
}
}GET /api/v1/offers - List all offers
{
"offers": [
{
"id": "2024-001",
"accepted_date": null,
"declined_date": null,
"client_shortname": "acme",
"date": "2024-01-10",
"project_name": "New Feature",
"oms_project": null,
"applicable_rates": "standard",
"valid_thru": "2024-02-10",
"coverletter": {
"greeting": null,
"show_rates": false
},
"devtime": "2 weeks",
"footer": {
"show_allnetto": true,
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-10T10:30:00Z",
"updated": "2024-01-10T10:30:00Z",
"revision": 1,
"total": 600000
}
]
}GET /api/v1/offers/{id} - Get single offer
{
"id": "2024-001",
"accepted_date": null,
"declined_date": null,
"client_shortname": "acme",
"date": "2024-01-10",
"project_name": "New Feature",
"oms_project": null,
"applicable_rates": "standard",
"valid_thru": "2024-02-10",
"coverletter": {
"greeting": null,
"show_rates": false
},
"devtime": "2 weeks",
"footer": {
"show_allnetto": true,
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-10T10:30:00Z",
"updated": "2024-01-10T10:30:00Z",
"revision": 1,
"total": 600000
}POST /api/v1/offers/{id}/accept - Mark offer as accepted
Sets accepted_date to today. Returns error if already accepted or declined.
{
"success": true,
"offer": {
"id": "2024-001",
"accepted_date": "2024-11-27",
"declined_date": null,
"client_shortname": "acme",
"date": "2024-01-10",
"project_name": "New Feature",
"oms_project": null,
"applicable_rates": "standard",
"valid_thru": "2024-02-10",
"coverletter": {
"greeting": null,
"show_rates": false
},
"devtime": "2 weeks",
"footer": {
"show_allnetto": true,
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-10T10:30:00Z",
"updated": "2024-11-27T14:00:00Z",
"revision": 1,
"total": 600000
}
}POST /api/v1/offers/{id}/reject - Mark offer as rejected
Sets declined_date to today. Returns error if already accepted or declined.
{
"success": true,
"offer": {
"id": "2024-001",
"accepted_date": null,
"declined_date": "2024-11-27",
"client_shortname": "acme",
"date": "2024-01-10",
"project_name": "New Feature",
"oms_project": null,
"applicable_rates": "standard",
"valid_thru": "2024-02-10",
"coverletter": {
"greeting": null,
"show_rates": false
},
"devtime": "2 weeks",
"footer": {
"show_allnetto": true,
"show_agb": true
},
"vat": {
"percent": 0,
"show_exempt_notice": true
},
"remarks": null,
"draft": false,
"created": "2024-01-10T10:30:00Z",
"updated": "2024-11-27T14:00:00Z",
"revision": 1,
"total": 600000
}
}GET /api/v1/transactions - List bank transactions
Query parameters (all optional):
from- Start date filter (ISO 8601: "2025-01-01")to- End date filter (ISO 8601: "2025-12-31")type- Filter by type: "incoming" or "outgoing"limit- Max results per page (default: 100)offset- Skip first N results (default: 0)
{
"transactions": [
{
"id": "abc123def456",
"ref_code": "VD/000000089",
"date": "2025-11-06",
"amount": 540000,
"currency": "EUR",
"description": "RNr. 2025-005 RDat. 29.10.2025 VD/000000089",
"counterparty": {
"name": "ACME Corp",
"iban": "DE47760800400105567700",
"bic": "DRESDEFF760"
},
"reference": null,
"type": "incoming",
"category": null,
"source": {
"file": "web-upload",
"line": 5,
"imported_at": "2025-11-28T00:00:00"
},
"reconciliation": {
"invoice_id": "2025-005",
"matched_at": "2025-11-28T00:00:00",
"confidence": "high"
}
}
],
"summary": {
"count": 1,
"total_incoming": 540000,
"total_outgoing": 0,
"net": 540000
},
"pagination": {
"limit": 100,
"offset": 0,
"total": 90
}
}Notes:
amountis in cents (540000 = €5,400.00). Positive = incoming, negative = outgoing.reconciliation.invoice_idmay contain comma-separated IDs for multi-invoice payments (e.g., "2025-002,2025-003,2025-004").reconciliation.confidenceis "high" for single-invoice matches, "multi" for multi-invoice matches.summaryreflects the filtered results (before pagination).pagination.totalis the total count of filtered transactions.
GET /api/v1/transactions/summary - Get transaction summary
Query parameters (all optional):
from- Start date filter (ISO 8601: "2025-01-01")to- End date filter (ISO 8601: "2025-12-31")group_by- Group results: "month" (only supported value)
Without grouping:
{
"period": {
"from": "2025-01-01",
"to": "2025-12-31"
},
"total_incoming": 8540000,
"total_outgoing": 2150000,
"net": 6390000,
"transaction_count": 90
}With group_by=month:
{
"period": {
"from": "2025-01-01",
"to": "2025-12-31"
},
"by_month": [
{
"month": "2025-07",
"incoming": 2840000,
"outgoing": 460000,
"net": 2380000,
"count": 12
},
{
"month": "2025-08",
"incoming": 1500000,
"outgoing": 320000,
"net": 1180000,
"count": 8
}
]
}All amounts are in cents.
GET /api/v1/balance - Get current bank balance
Returns the calculated balance from sum of all transactions.
{
"balance": 2340567,
"balance_eur": 23405.67,
"currency": "EUR",
"as_of": "2025-11-28",
"transaction_count": 127,
"calculation": "sum_of_all_transactions"
}Notes:
balanceis in cents (2340567 = €23,405.67). Can be negative.balance_euris a convenience float in EUR.as_ofis the date of the most recent transaction (or today if no transactions).calculationdescribes the method used ("sum_of_all_transactions").
GET /api/v1/summary - Get financial summary
{
"invoices": {
"total": 15,
"open": 3,
"total_amount": 4500000,
"open_amount": 450000
},
"offers": {
"total": 8,
"open": 2,
"pending_amount": 300000,
"accepted_amount": 1200000
}
}All amounts are in EUR.
All errors return JSON with an error field:
{"error": "Invalid or missing API key"}{"error": "Client not found"}{"error": "Invoice not found"}{"error": "Invoice is already marked as paid"}{"error": "Offer not found"}{"error": "Offer is already accepted"}{"error": "Offer is already declined"}{"error": "Unknown API endpoint"}{"error": "Use POST for status changes"}{"error": "Invalid invoice action"}{"error": "Invalid offer action"}HTTP status codes:
401 Unauthorized- Missing or invalid API key404 Not Found- Resource not found400 Bad Request- Invalid request or action not allowed405 Method Not Allowed- Wrong HTTP method for endpoint