REST API
Frihets REST API giver programmatisk adgang til og manipulation af dine kontoresurser. Al kommunikation foregår via HTTPS, og svar er i JSON-format.
Base-URL
https://api.frihet.io/v1
Alle endpoints beskrevet på denne side er relative til denne Base-URL.
Opdagelse: En GET-anmodning til roden (https://api.frihet.io/) returnerer de primære links uden behov for autentifikation:
{
"name": "Frihet API",
"version": "1.0.0",
"docs": "https://docs.frihet.io/desarrolladores/api-rest",
"openapi": "https://api.frihet.io/openapi.yaml",
"mcp": "https://mcp.frihet.io",
"status": "https://status.frihet.io"
}
OpenAPI 3.1-specifikationen er tilgængelig på https://api.frihet.io/openapi.yaml.
Hvis du bruger TypeScript eller JavaScript, forenkler det officielle SDK integrationen:
npm install @frihet/sdk
import Frihet from '@frihet/sdk';
const frihet = new Frihet({ apiKey: 'fri_...' });
const invoices = await frihet.invoices.list({ status: 'overdue' });
Repository: github.com/Frihet-io/frihet-sdk
Autentifikation
Hver anmodning skal inkludere en API-nøgle i X-API-Key-headeren. Nøgler oprettes under Indstillinger > Udviklere > API-nøgler i Frihet-panelet.
Nøgler har præfikset fri_ efterfulgt af 32 tilfældige bytes kodet i base64url. Eksempel: fri_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345678.
curl https://api.frihet.io/v1/clients \
-H "X-API-Key: fri_tu-clave-aqui"
Alternativt kan du sende nøglen som et Bearer-token i Authorization-headeren:
curl https://api.frihet.io/v1/clients \
-H "Authorization: Bearer fri_tu-clave-aqui"
Nøglernes sikkerhed
- Nøglen i klartekst vises kun én gang, ved oprettelsestidspunktet. Den kan ikke gendannes efterfølgende.
- Serveren gemmer et SHA-256-hash af nøglen. Selv i tilfælde af et databrud kan den originale nøgle ikke gendannes.
- Du kan oprette nøgler med konfigurerbar udløbsdato.
- Hvis du mistænker, at en nøgle er blevet kompromitteret, skal du straks tilbagekalde den fra panelet.
Nøglernes livscyklus
Opret en nøgle:
- Gå til Indstillinger > Udviklere > API-nøgler
- Klik på Opret nøgle
- Tildel et beskrivende navn (f.eks.
integration-regnskab) - Indstil eventuelt en udløbsdato i dage. Hvis feltet efterlades tomt, udløber nøglen ikke.
- Kopier nøglen med det samme -- du vil ikke kunne se den igen.
Udløb:
Nøgler med udløbsdato holder automatisk op med at fungere, når fristen udløber. Anmodninger med en udløbet nøgle modtager en 401 Unauthorized.
Tilbagekaldelse:
Du kan tilbagekalde en nøgle når som helst under Indstillinger > Udviklere > API-nøgler. Tilbagekaldelse er øjeblikkelig og irreversibel: igangværende anmodninger med den nøgle vil fejle fra det øjeblik.
Nøglerotation:
For at rotere en nøgle uden at afbryde tjenesten:
- Opret en ny nøgle med samme omfang.
- Opdater din integration til at bruge den nye nøgle.
- Bekræft, at anmodningerne fungerer korrekt.
- Tilbagekald den tidligere nøgle.
Overvågning:
Hver nøgle viser datoen for seneste brug i indstillingspanelet. Gennemgå regelmæssigt inaktive nøgler og tilbagekald dem, der ikke længere bruges.
Rate limiting
Hver API-nøgle har en grænse på 100 anmodninger pr. minut. Hvis dette overskrides, svarer API'en med en 429-kode:
{
"error": "Rate limit exceeded",
"message": "Maximum 100 requests per minute",
"retryAfter": 60
}
Rate limiting-headers
Alle API-svar inkluderer headers, så du proaktivt kan administrere grænsen:
| Header | Beskrivelse | Eksempel |
|---|---|---|
X-RateLimit-Limit | Tilladte anmodninger pr. minut | 100 |
X-RateLimit-Remaining | Resterende anmodninger i det nuværende vindue | 87 |
X-RateLimit-Reset | Unix-timestamp (sekunder), hvor vinduet nulstilles | 1709312400 |
Eksempel på svar med rate limiting-headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1709312400
Content-Type: application/json
Håndtering af 429-koden:
Når du modtager en 429, skal du bruge headers til at beregne, hvor længe du skal vente, før du forsøger igen:
async function fetchWithRateLimit(url, options) {
const response = await fetch(url, options);
if (response.status === 429) {
const resetTimestamp = response.headers.get('X-RateLimit-Reset');
const waitMs = (Number(resetTimestamp) * 1000) - Date.now();
await new Promise(resolve => setTimeout(resolve, Math.max(waitMs, 1000)));
return fetch(url, options);
}
return response;
}
Anbefalinger:
- Hvis du modtager en
429, skal du vente til det timestamp, der er angivet iX-RateLimit-Reset, før du forsøger igen. - Overvåg
X-RateLimit-Remainingfor at bremse anmodninger, før grænsen nås. - Fordel anmodninger over tid i stedet for at sende dem i byger.
Anmodningsstørrelse
Brødteksten for POST-, PUT- og PATCH-anmodninger må ikke overstige 1 MB. Større anmodninger modtager en 413-kode.
Ressourcer
API'en eksponerer 7 primære ressourcer: invoices, expenses, clients, products, quotes, vendors og webhooks. Alle understøtter komplette CRUD-operationer (GET, POST, PUT/PATCH, DELETE). Derudover har kunder CRM-underkollektioner: contacts, activities og notes.
Både PUT og PATCH accepterer delvise opdateringer. Du behøver ikke at sende hele ressourcen -- kun de felter, du ønsker at ændre.
Fakturaer (/invoices)
Vis fakturaer
GET /v1/invoices
Forespørgselsparametre:
| Parameter | Type | Standard | Beskrivelse |
|---|---|---|---|
limit | integer | 50 | Resultater pr. side (maks. 100) |
offset | integer | 0 | Antal resultater, der skal springes over (maks. 10.000) |
status | string | -- | Filtrer efter status: kladde, sendt, betalt, forfalden, annulleret |
from | string | -- | Startdato (ISO 8601: ÅÅÅÅ-MM-DD). Filtrerer efter issueDate |
to | string | -- | Slutdato (ISO 8601: ÅÅÅÅ-MM-DD). Filtrerer efter issueDate |
Eksempel:
curl "https://api.frihet.io/v1/invoices?limit=10&status=paid&from=2026-01-01&to=2026-03-31" \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"data": [
{
"id": "abc123",
"clientName": "Acme S.L.",
"items": [
{ "description": "Consultoria", "quantity": 10, "unitPrice": 75 }
],
"status": "paid",
"issueDate": "2026-01-15",
"dueDate": "2026-02-15",
"taxRate": 21,
"notes": "",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-20T14:00:00.000Z"
}
],
"total": 42,
"limit": 10,
"offset": 0
}
Hent faktura
GET /v1/invoices/:id
curl https://api.frihet.io/v1/invoices/abc123 \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"id": "abc123",
"clientName": "Acme S.L.",
"items": [
{ "description": "Consultoria", "quantity": 10, "unitPrice": 75 }
],
"status": "paid",
"issueDate": "2026-01-15",
"dueDate": "2026-02-15",
"taxRate": 21,
"notes": "",
"createdAt": "2026-01-15T10:30:00.000Z",
"updatedAt": "2026-01-20T14:00:00.000Z"
}
Opret faktura
POST /v1/invoices
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
clientName | string | Kundenavn (maks. 10.000 tegn) |
items | array | Liste over fakturalinjer. Hver linje: { description, quantity, unitPrice } |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
status | string | kladde (standard), sendt, betalt, forfalden, annulleret |
issueDate | string | Udstillingsdato (ISO 8601). Standard: i dag |
dueDate | string | Forfaldsdato (ISO 8601) |
notes | string | Interne noter (maks. 10.000 tegn) |
taxRate | number | Skattesats i procent (0-100). F.eks.: 21 for 21% moms |
Struktur for hver linje (items[]):
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
description | string | Ja | Beskrivelse af elementet (maks. 10.000 tegn) |
quantity | number | Ja | Antal |
unitPrice | number | Ja | Enhedspris |
curl -X POST https://api.frihet.io/v1/invoices \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"clientName": "Acme S.L.",
"items": [
{ "description": "Desarrollo web", "quantity": 40, "unitPrice": 60 }
],
"dueDate": "2026-03-01",
"taxRate": 21,
"notes": "Proyecto Q1 2026"
}'
Svar (201):
{
"id": "def456",
"clientName": "Acme S.L.",
"items": [
{ "description": "Desarrollo web", "quantity": 40, "unitPrice": 60 }
],
"status": "draft",
"issueDate": "2026-02-12",
"dueDate": "2026-03-01",
"taxRate": 21,
"notes": "Proyecto Q1 2026",
"createdAt": "2026-02-12T09:00:00.000Z",
"updatedAt": "2026-02-12T09:00:00.000Z"
}
Opdater faktura (PUT eller PATCH)
PUT /v1/invoices/:id
PATCH /v1/invoices/:id
Du skal kun sende de felter, du ønsker at ændre. Ikke-inkluderede felter forbliver uændrede.
curl -X PATCH https://api.frihet.io/v1/invoices/def456 \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"status": "sent",
"notes": "Enviada al cliente"
}'
Svar (200): Opdateret fakturaobjekt.
Hvis du sender items, skal du sende hele array'et -- delvise opdateringer af individuelle linjer er ikke tilladt.
Slet faktura
DELETE /v1/invoices/:id
curl -X DELETE https://api.frihet.io/v1/invoices/def456 \
-H "X-API-Key: fri_tu-clave-aqui"
Svar: 204 No Content
Download faktura i PDF
GET /v1/invoices/:id/pdf
Returnerer fakturaens PDF som application/pdf med Content-Disposition: attachment-headeren.
curl -o factura.pdf https://api.frihet.io/v1/invoices/abc123/pdf \
-H "X-API-Key: fri_tu-clave-aqui"
Send faktura via e-mail
POST /v1/invoices/:id/send
Sender fakturaen til den specificerede modtager via Resend. Hvis fakturaen er i status kladde, opdateres den automatisk til sendt.
Felter:
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
recipientEmail | string | Ja | Modtagerens e-mail (maks. 255 tegn) |
recipientName | string | Nej | Modtagerens navn (maks. 200 tegn) |
customMessage | string | Nej | Tilpasset besked i e-mailens brødtekst (maks. 5.000 tegn) |
locale | string | Nej | E-mailsprog: es (standard) eller en |
curl -X POST https://api.frihet.io/v1/invoices/abc123/send \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"recipientEmail": "admin@acme.es",
"recipientName": "Departamento de Contabilidad",
"locale": "es"
}'
Svar (200):
{ "success": true, "messageId": "re_abc123..." }
Marker faktura som betalt
POST /v1/invoices/:id/paid
| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
paidDate | string | Nej | Betalingsdato (ISO 8601). Standard: i dag |
curl -X POST https://api.frihet.io/v1/invoices/abc123/paid \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{ "paidDate": "2026-03-15" }'
Svar (200):
{ "success": true, "status": "paid", "paidAt": "2026-03-15" }
Udgifter (/expenses)
Vis udgifter
GET /v1/expenses
Forespørgselsparametre:
| Parameter | Type | Standard | Beskrivelse |
|---|---|---|---|
limit | integer | 50 | Resultater pr. side (maks. 100) |
offset | integer | 0 | Antal resultater, der skal springes over |
from | string | -- | Startdato (ISO 8601). Filtrerer efter date |
to | string | -- | Slutdato (ISO 8601). Filtrerer efter date |
curl "https://api.frihet.io/v1/expenses?limit=20&from=2026-01-01" \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"data": [
{
"id": "exp789",
"description": "Licencia Adobe Creative Cloud",
"amount": 59.99,
"category": "software",
"date": "2026-02-01",
"vendor": "Adobe Inc.",
"taxDeductible": true,
"createdAt": "2026-02-01T10:00:00.000Z",
"updatedAt": "2026-02-01T10:00:00.000Z"
}
],
"total": 15,
"limit": 20,
"offset": 0
}
Hent udgift
GET /v1/expenses/:id
Opret udgift
POST /v1/expenses
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
description | string | Beskrivelse af udgiften (maks. 10.000 tegn) |
amount | number | Udgiftsbeløb |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
category | string | Udgiftskategori (maks. 10.000 tegn) |
date | string | Udgiftsdato (ISO 8601). Standard: i dag |
vendor | string | Leverandør (maks. 10.000 tegn) |
taxDeductible | boolean | Om udgiften er fradragsberettiget |
curl -X POST https://api.frihet.io/v1/expenses \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"description": "Licencia Adobe Creative Cloud",
"amount": 59.99,
"category": "software",
"date": "2026-02-01",
"vendor": "Adobe Inc.",
"taxDeductible": true
}'
Svar (201):
{
"id": "exp789",
"description": "Licencia Adobe Creative Cloud",
"amount": 59.99,
"category": "software",
"date": "2026-02-01",
"vendor": "Adobe Inc.",
"taxDeductible": true,
"createdAt": "2026-02-12T09:15:00.000Z",
"updatedAt": "2026-02-12T09:15:00.000Z"
}
Opdater udgift (PUT eller PATCH)
PUT /v1/expenses/:id
PATCH /v1/expenses/:id
curl -X PATCH https://api.frihet.io/v1/expenses/exp789 \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{ "amount": 65.99, "taxDeductible": false }'
Svar (200): Opdateret udgiftsobjekt.
Slet udgift
DELETE /v1/expenses/:id
Svar: 204 No Content
Kunder (/clients)
Vis kunder
GET /v1/clients
Accepterer limit, offset, from og to (filtrerer efter createdAt).
curl "https://api.frihet.io/v1/clients?limit=50" \
-H "X-API-Key: fri_tu-clave-aqui"
Hent kunde
GET /v1/clients/:id
Opret kunde
POST /v1/clients
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
name | string | Kundenavn (maks. 10.000 tegn) |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
email | string | Kontakt e-mail |
phone | string | Telefon |
taxId | string | NIF/CIF/VAT |
address | object | Adresse (se struktur nedenfor) |
Struktur af address:
| Felt | Type | Beskrivelse |
|---|---|---|
street | string | Gade og nummer |
city | string | By |
state | string | Provins eller delstat |
postalCode | string | Postnummer |
country | string | Land |
Alle felter i address er valgfrie.
curl -X POST https://api.frihet.io/v1/clients \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme S.L.",
"email": "admin@acme.es",
"taxId": "B12345678",
"address": {
"street": "Calle Gran Via 42",
"city": "Madrid",
"postalCode": "28013",
"country": "ES"
}
}'
Svar (201):
{
"id": "cli001",
"name": "Acme S.L.",
"email": "admin@acme.es",
"taxId": "B12345678",
"address": {
"street": "Calle Gran Via 42",
"city": "Madrid",
"postalCode": "28013",
"country": "ES"
},
"createdAt": "2026-02-12T09:30:00.000Z",
"updatedAt": "2026-02-12T09:30:00.000Z"
}
Opdater kunde (PUT eller PATCH)
PUT /v1/clients/:id
PATCH /v1/clients/:id
curl -X PATCH https://api.frihet.io/v1/clients/cli001 \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{ "phone": "+34 912 345 678" }'
Svar (200): Opdateret kundeobjekt.
Slet kunde
DELETE /v1/clients/:id
Svar: 204 No Content
CRM: Kontaktpersoner, Aktiviteter og Noter
Kunder har tre underkollektioner til styring af CRM-relationer: kontaktpersoner, aktiviteter og noter. Alle endpoints kræver et gyldigt clientId i URL'en.
Kontaktpersoner (/v1/clients/:id/contacts)
Vis kontakter
GET /v1/clients/:id/contacts
curl "https://api.frihet.io/v1/clients/cli001/contacts" \
-H "X-API-Key: fri_tu-clave-aqui"
Hent kontakt
GET /v1/clients/:id/contacts/:contactId
curl "https://api.frihet.io/v1/clients/cli001/contacts/con001" \
-H "X-API-Key: fri_tu-clave-aqui"
Opret kontakt
POST /v1/clients/:id/contacts
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
name | string | Navn på kontaktperson |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
email | string | Kontaktens e-mail |
phone | string | Telefon |
role | string | Titel eller rolle (f.eks. "Finansdirektør") |
isPrimary | boolean | Om det er kundens primære kontaktperson |
curl -X POST https://api.frihet.io/v1/clients/cli001/contacts \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"name": "Maria Garcia",
"email": "maria@acme.es",
"phone": "+34 612 345 678",
"role": "Directora financiera",
"isPrimary": true
}'
Svar (201):
{
"id": "con001",
"name": "Maria Garcia",
"email": "maria@acme.es",
"phone": "+34 612 345 678",
"role": "Directora financiera",
"isPrimary": true,
"createdAt": "2026-03-15T10:00:00.000Z",
"updatedAt": "2026-03-15T10:00:00.000Z"
}
Opdater kontakt
PATCH /v1/clients/:id/contacts/:contactId
curl -X PATCH https://api.frihet.io/v1/clients/cli001/contacts/con001 \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{ "role": "CEO" }'
Svar (200): Opdateret kontaktobjekt.
Slet kontakt
DELETE /v1/clients/:id/contacts/:contactId
curl -X DELETE https://api.frihet.io/v1/clients/cli001/contacts/con001 \
-H "X-API-Key: fri_tu-clave-aqui"
Svar: 204 No Content
Aktiviteter (/v1/clients/:id/activities)
Aktivitetstidslinjen registrerer interaktioner med en kunde. Systemaktiviteter (såsom invoice_created, quote_sent osv.) genereres automatisk. Du kan også oprette manuelle aktiviteter.
Aktiviteter er uforanderlige. De kan ikke opdateres eller slettes, når de først er oprettet.
Vis aktiviteter
GET /v1/clients/:id/activities
curl "https://api.frihet.io/v1/clients/cli001/activities" \
-H "X-API-Key: fri_tu-clave-aqui"
Hent aktivitet
GET /v1/clients/:id/activities/:activityId
curl "https://api.frihet.io/v1/clients/cli001/activities/act001" \
-H "X-API-Key: fri_tu-clave-aqui"
Opret aktivitet
POST /v1/clients/:id/activities
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
type | string | Aktivitetstype: call, email, meeting eller task |
title | string | Beskrivende titel for aktiviteten |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
description | string | Detaljeret beskrivelse |
metadata | object | Yderligere data i frit format |
Typerne call, email, meeting og task er til manuelt oprettede aktiviteter. Systemtyper som invoice_created, quote_sent eller expense_linked genereres automatisk og kan ikke oprettes via API.
curl -X POST https://api.frihet.io/v1/clients/cli001/activities \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"type": "call",
"title": "Llamada de seguimiento presupuesto Q2",
"description": "Comentamos las condiciones del presupuesto. Pendiente de confirmar.",
"metadata": {
"duration": "15min",
"outcome": "pending"
}
}'
Svar (201):
{
"id": "act001",
"type": "call",
"title": "Llamada de seguimiento presupuesto Q2",
"description": "Comentamos las condiciones del presupuesto. Pendiente de confirmar.",
"metadata": {
"duration": "15min",
"outcome": "pending"
},
"createdAt": "2026-03-15T14:30:00.000Z"
}
Noter (/v1/clients/:id/notes)
Vis noter
GET /v1/clients/:id/notes
curl "https://api.frihet.io/v1/clients/cli001/notes" \
-H "X-API-Key: fri_tu-clave-aqui"
Hent note
GET /v1/clients/:id/notes/:noteId
curl "https://api.frihet.io/v1/clients/cli001/notes/note001" \
-H "X-API-Key: fri_tu-clave-aqui"
Opret note
POST /v1/clients/:id/notes
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
content | string | Notens indhold |
curl -X POST https://api.frihet.io/v1/clients/cli001/notes \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"content": "Cliente interesado en plan Business. Contactar en abril para renovacion."
}'
Svar (201):
{
"id": "note001",
"content": "Cliente interesado en plan Business. Contactar en abril para renovacion.",
"createdAt": "2026-03-15T16:00:00.000Z",
"updatedAt": "2026-03-15T16:00:00.000Z"
}
Opdater note
PATCH /v1/clients/:id/notes/:noteId
curl -X PATCH https://api.frihet.io/v1/clients/cli001/notes/note001 \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"content": "Cliente interesado en plan Business. Reunion confirmada 5 de abril."
}'
Svar (200): Opdateret noteobjekt.
Slet note
DELETE /v1/clients/:id/notes/:noteId
curl -X DELETE https://api.frihet.io/v1/clients/cli001/notes/note001 \
-H "X-API-Key: fri_tu-clave-aqui"
Svar: 204 No Content
Produkter (/products)
Vis produkter
GET /v1/products
Accepterer limit, offset, from og to (filtrerer efter createdAt).
Hent produkt
GET /v1/products/:id
Opret produkt
POST /v1/products
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
name | string | Navn på produkt eller service (maks. 10.000 tegn) |
unitPrice | number | Enhedspris |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
description | string | Beskrivelse (maks. 10.000 tegn) |
taxRate | number | Skattesats i procent (0-100) |
curl -X POST https://api.frihet.io/v1/products \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"name": "Hora de consultoria",
"unitPrice": 75,
"description": "Consultoria estrategica",
"taxRate": 21
}'
Svar (201):
{
"id": "prod001",
"name": "Hora de consultoria",
"unitPrice": 75,
"description": "Consultoria estrategica",
"taxRate": 21,
"createdAt": "2026-02-12T10:00:00.000Z",
"updatedAt": "2026-02-12T10:00:00.000Z"
}
Opdater produkt (PUT eller PATCH)
PUT /v1/products/:id
PATCH /v1/products/:id
curl -X PATCH https://api.frihet.io/v1/products/prod001 \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{ "unitPrice": 85 }'
Svar (200): Opdateret produktobjekt.
Slet produkt
DELETE /v1/products/:id
Svar: 204 No Content
Tilbud (/quotes)
Vis tilbud
GET /v1/quotes
Forespørgselsparametre:
| Parameter | Type | Standard | Beskrivelse |
|---|---|---|---|
limit | integer | 50 | Resultater pr. side (maks. 100) |
offset | integer | 0 | Antal resultater, der skal springes over |
status | string | -- | Filtrer efter status: kladde, sendt, accepteret, afvist, udløbet |
from | string | -- | Startdato (ISO 8601). Filtrerer efter issueDate |
to | string | -- | Slutdato (ISO 8601). Filtrerer efter issueDate |
curl "https://api.frihet.io/v1/quotes?status=sent" \
-H "X-API-Key: fri_tu-clave-aqui"
Hent tilbud
GET /v1/quotes/:id
Opret tilbud
POST /v1/quotes
Påkrævede felter:
| Felt | Type | Beskrivelse |
|---|---|---|
clientName | string | Kundenavn (maks. 10.000 tegn) |
items | array | Tilbudslinjer. Hver linje: { description, quantity, unitPrice } |
Valgfrie felter:
| Felt | Type | Beskrivelse |
|---|---|---|
validUntil | string | Gyldighedsdato (ISO 8601) |
notes | string | Noter eller betingelser (maks. 10.000 tegn) |
status | string | kladde (standard), sendt, accepteret, afvist, udløbet |
curl -X POST https://api.frihet.io/v1/quotes \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"clientName": "Design Studio SL",
"items": [
{ "description": "Desarrollo web", "quantity": 80, "unitPrice": 60 },
{ "description": "Diseno UX", "quantity": 20, "unitPrice": 55 }
],
"validUntil": "2026-04-01",
"notes": "Incluye 2 rondas de revision"
}'
Svar (201):
{
"id": "quo001",
"clientName": "Design Studio SL",
"items": [
{ "description": "Desarrollo web", "quantity": 80, "unitPrice": 60 },
{ "description": "Diseno UX", "quantity": 20, "unitPrice": 55 }
],
"status": "draft",
"validUntil": "2026-04-01",
"notes": "Incluye 2 rondas de revision",
"createdAt": "2026-02-12T11:00:00.000Z",
"updatedAt": "2026-02-12T11:00:00.000Z"
}
Opdater tilbud (PUT eller PATCH)
PUT /v1/quotes/:id
PATCH /v1/quotes/:id
Slet tilbud
DELETE /v1/quotes/:id
Svar: 204 No Content
Download tilbud i PDF
GET /v1/quotes/:id/pdf
Fungerer som /invoices/:id/pdf. Returnerer application/pdf.
curl -o presupuesto.pdf https://api.frihet.io/v1/quotes/quo001/pdf \
-H "X-API-Key: fri_tu-clave-aqui"
Send tilbud via e-mail
POST /v1/quotes/:id/send
Samme felter som /invoices/:id/send (recipientEmail, recipientName, customMessage, locale). Hvis tilbuddet er i status kladde, opdateres det automatisk til sendt.
Batchoperationer (/batch)
Alle primære ressourcer understøtter batchoprettelse. Send et array med op til 50 elementer i én enkelt anmodning.
POST /v1/{resource}/batch
Understøttede ressourcer: invoices, expenses, clients, products, quotes
Anmodningens brødtekst:
{
"items": [
{ "clientName": "Acme SL", "items": [{ "description": "Hora consultoria", "quantity": 1, "unitPrice": 95 }] },
{ "clientName": "TechStart SL", "items": [{ "description": "Desarrollo web", "quantity": 8, "unitPrice": 60 }] }
]
}
curl -X POST https://api.frihet.io/v1/invoices/batch \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "clientName": "Acme SL", "items": [{ "description": "Consultoria", "quantity": 1, "unitPrice": 95 }] },
{ "clientName": "TechStart SL", "items": [{ "description": "Desarrollo", "quantity": 8, "unitPrice": 60 }] }
]
}'
Svar (207 Multi-Status):
{
"results": [
{ "status": 201, "data": { "id": "inv_001", "clientName": "Acme SL", "status": "draft" } },
{ "status": 201, "data": { "id": "inv_002", "clientName": "TechStart SL", "status": "draft" } }
],
"summary": { "total": 2, "succeeded": 2, "failed": 0 }
}
Hvis et af elementerne fejler validering, oprettes resten alligevel. Individuelle fejl returneres i results-array'et:
{
"results": [
{ "status": 201, "data": { "id": "inv_001", "clientName": "Acme SL" } },
{ "status": 400, "error": { "message": "Missing required field: items" } }
],
"summary": { "total": 2, "succeeded": 1, "failed": 1 }
}
Grænser:
| Koncept | Grænse |
|---|---|
| Elementer pr. batch | 50 maks. |
| Anmodningsstørrelse | 1 MB maks. |
Idempotens
POST-anmodninger accepterer en Idempotency-Key-header for at undgå duplikat oprettelse af ressourcer ved netværksforsøg. Hvis den samme nøgle sendes inden for de næste 24 timer, returnerer API'en det originale svar uden at udføre operationen igen.
curl -X POST https://api.frihet.io/v1/invoices \
-H "X-API-Key: fri_tu-clave-aqui" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"clientName": "Acme SL",
"items": [{ "description": "Consultoria", "quantity": 10, "unitPrice": 95 }]
}'
Opførsel:
| Scenarie | Resultat |
|---|---|
| Første anmodning med nøglen | Ressourcen oprettes normalt |
| Gentagen anmodning med samme nøgle (inden for 24 timer) | Det originale svar returneres, uden duplikering |
| Samme nøgle efter 24 timer | Behandles som en ny anmodning |
Svarheader:
Når API'en registrerer en gentaget nøgle, inkluderer den X-Idempotent-Replayed: true-headeren, så forbrugeren ved, at svaret er en gentagelse.
HTTP/1.1 201 Created
X-Idempotent-Replayed: true
Content-Type: application/json
Krav:
- Nøglen må højst være 64 tegn lang
- Vi anbefaler at bruge UUID v4
- Gælder kun for
POST-anmodninger (oprettelse af ressourcer)
Søgning
Liste-endpoints understøtter fuldtekstsøgning via parameteren q:
curl "https://api.frihet.io/v1/invoices?q=acme" \
-H "X-API-Key: fri_tu-clave-aqui"
Søgningen anvendes på ressourcens primære tekstfelter (kundenavn, beskrivelse, noter osv.). Den kan kombineres med eksisterende filtre (status, from, to).
Intelligens-endpoints
Disse endpoints leverer aggregerede data og forretningskontekst. De er især nyttige for AI-agenter og eksterne dashboards.
Forretningskontekst (/context)
GET /v1/context
Returnerer en komplet oversigt over virksomheden, designet til at forsyne AI-agenter med den nødvendige kontekst for at træffe informerede beslutninger. Inkluderer finansiel oversigt, nylig aktivitet, alarmer og skattekonfiguration.
curl https://api.frihet.io/v1/context \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"business": {
"name": "BRTHLS Studio",
"taxId": "12345678A",
"fiscalZone": "canarias",
"currency": "EUR"
},
"summary": {
"revenue": { "invoiced": 15000, "paid": 12000, "pending": 2000, "overdue": 1000 },
"expenses": { "total": 4500 },
"profit": 7500,
"counts": { "invoices": 25, "clients": 12, "products": 5 }
},
"recentActivity": [
{ "type": "invoice.created", "id": "inv_001", "description": "Factura para Acme SL", "timestamp": "2026-03-18T10:00:00Z" },
{ "type": "expense.created", "id": "exp_042", "description": "Adobe Creative Cloud", "timestamp": "2026-03-17T14:30:00Z" }
],
"alerts": [
{ "type": "overdue", "count": 2, "amount": 1000 },
{ "type": "tax_deadline", "model": "303", "dueDate": "2026-04-20" }
]
}
Månedlig P&L (/monthly)
GET /v1/monthly?month=YYYY-MM
Returnerer resultatopgørelsen (P&L) for en specifik måned: fakturerede indtægter, udgifter pr. kategori, nettooverskud og sammenligning med den foregående måned.
curl "https://api.frihet.io/v1/monthly?month=2026-02" \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"month": "2026-02",
"revenue": {
"invoiced": 8500.00,
"collected": 6200.00,
"outstanding": 2300.00
},
"expenses": {
"total": 3100.00,
"byCategory": {
"software": 450.00,
"marketing": 800.00,
"office": 350.00,
"professional_services": 1500.00
}
},
"profit": 5400.00,
"comparison": {
"revenueChange": 12.5,
"expenseChange": -5.2,
"profitChange": 22.1
}
}
Kvartalsvise skattetal (/quarterly)
GET /v1/quarterly?quarter=YYYY-Q1
Returnerer skattetal for et kvartal, forberedt til indberetning af Model 303 (Moms) og Model 130 (IRPF). Inkluderer skattepligtige baser, påløbne afgifter, fradragsberettigede afgifter og opgørelsens resultat.
curl "https://api.frihet.io/v1/quarterly?quarter=2026-Q1" \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"quarter": "2026-Q1",
"period": { "from": "2026-01-01", "to": "2026-03-31" },
"modelo303": {
"baseImponible21": 12000.00,
"cuotaDevengada21": 2520.00,
"baseImponible10": 0,
"cuotaDevengada10": 0,
"baseImponible4": 0,
"cuotaDevengada4": 0,
"totalDevengado": 2520.00,
"ivaDeducible": 980.00,
"resultado": 1540.00
},
"modelo130": {
"ingresos": 12000.00,
"gastos": 4500.00,
"rendimientoNeto": 7500.00,
"porcentaje": 20,
"cuota": 1500.00,
"retenciones": 0,
"pagosAnteriores": 0,
"resultado": 1500.00
}
}
Endpoints /context, /monthly og /quarterly er designet til at være det ideelle indgangspunkt for AI-agenter. De giver den nødvendige information i et enkelt kald, uden behov for at konsultere flere individuelle endpoints.
Finansielt dashboard (/summary)
GET /v1/summary
Returnerer en finansiel oversigt over virksomheden: indtægter, udgifter, overskud og tællere.
Forespørgselsparametre:
| Parameter | Type | Beskrivelse |
|---|---|---|
from | string | Startdato (ISO 8601) |
to | string | Slutdato (ISO 8601) |
curl "https://api.frihet.io/v1/summary?from=2026-01-01&to=2026-03-31" \
-H "X-API-Key: fri_tu-clave-aqui"
Svar (200):
{
"period": { "from": "2026-01-01", "to": "2026-03-31" },
"revenue": {
"invoiced": 15000.00,
"paid": 12000.00,
"pending": 2000.00,
"overdue": 1000.00
},
"expenses": { "total": 4500.00 },
"profit": 7500.00,
"counts": {
"invoices": 25,
"quotes": 8,
"expenses": 42,
"clients": 12,
"products": 5
},
"invoicesByStatus": {
"draft": 3,
"sent": 5,
"paid": 15,
"overdue": 2
},
"overdue": { "count": 2, "amount": 1000.00 }
}
Fejlkoder
API'en bruger standard HTTP-koder. Fejlsvar inkluderer et JSON-objekt med felterne error og, valgfrit, message og details.
| Kode | Betydning | Beskrivelse |
|---|---|---|
400 | Bad Request | Påkrævet felt mangler, forkert format eller ikke-tilladt felt |
401 | Unauthorized | API-nøglen er ikke angivet, er ugyldig, har forkert format eller er udløbet |
403 | Forbidden | API-nøglen har ikke tilladelse til at tilgå denne ressource |
404 | Not Found | Den anmodede ressource findes ikke |
405 | Method Not Allowed | HTTP-metoden understøttes ikke for dette endpoint |
413 | Payload Too Large | Anmodningens brødtekst overstiger 1 MB |
422 | Unprocessable Entity | Gyldige data, men serveren kan ikke behandle dem (f.eks. skatteprofil ikke konfigureret) |
429 | Too Many Requests | Grænsen på 100 anmodninger pr. minut er overskredet |
500 | Internal Server Error | Intern serverfejl |
Fejlsvarstrukturen
Valideringsfejl (400):
{
"error": "Validation error",
"details": [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["clientName"],
"message": "Required"
}
]
}
Valideringsfejl bruger Zod-formatet. Feltet path angiver, hvilket felt der indeholder fejlen, og message beskriver problemet.
Ugyldig eller udløbet API-nøgle (401):
{
"error": "Invalid or expired API key"
}
Ugyldigt nøgleformat (401):
{
"error": "Invalid API key format"
}
Ressource ikke fundet (404):
{
"error": "Resource not found"
}
Ugyldig status i filter (400):
{
"error": "Invalid status filter",
"message": "Valid values: draft, sent, paid, overdue, cancelled"
}
Rate limit overskredet (429):
{
"error": "Rate limit exceeded",
"message": "Maximum 100 requests per minute",
"retryAfter": 60
}
Intern fejl (500):
{
"error": "Internal server error"
}
Sideinddeling
Liste-endpoints returnerer sideinddelte resultater med følgende struktur:
{
"data": [],
"total": 142,
"limit": 50,
"offset": 0
}
total: det samlede antal poster, der opfylder de anvendte filtrelimit: antallet af poster, der returneres på denne side (maks. 100)offset: antallet af overspringede poster (maks. 10.000)
For at hente den næste side:
curl "https://api.frihet.io/v1/invoices?limit=50&offset=50" \
-H "X-API-Key: fri_tu-clave-aqui"
Resultaterne sorteres efter ressourcens naturlige dato i faldende rækkefølge (nyeste først):
- Fakturaer og tilbud:
issueDate - Udgifter:
date - Kunder og produkter:
createdAt
Strikt validering
API'en bruger strikt validering (Zod strict mode). Anmodninger med ukendte felter afvises med en 400-fejl:
{
"error": "Validation error",
"details": [
{
"code": "unrecognized_keys",
"keys": ["campoInventado"],
"path": [],
"message": "Unrecognized key(s) in object: 'campoInventado'"
}
]
}
Dette forhindrer tavse fejl på grund af tastefejl i feltnavnene.
CORS
API'en understøtter CORS for anmodninger fra browseren. De tilladte oprindelser er:
https://app.frihet.iohttps://frihet.iohttps://www.frihet.io
For server-til-server-integrationer er CORS ikke relevant. Hvis du skal have adgang til API'en fra et andet domæne i browseren, skal du bruge en proxy i din backend.
Sikkerhedshearders
Alle svar inkluderer sikkerhedshearders:
| Header | Værdi |
|---|---|
X-Content-Type-Options | nosniff |
X-Frame-Options | DENY |
X-XSS-Protection | 1; mode=block |
X-Request-Id | Unikt anmodnings-ID (nyttigt til debugging) |
OAuth for MCP
Endpointet POST /api/oauth/api-key gør det muligt automatisk at tildele en API-nøgle via MCP's OAuth-flow. MCP-serveren bruger dette endpoint internt -- du behøver ikke at kalde det direkte.
Flowet:
- Brugeren autentificerer via Firebase Auth
- MCP-klienten sender Firebase-tokenet til
/api/oauth/api-key - Serveren returnerer en ny nøgle
fri_xxx...mærket som "MCP OAuth" - Nøglen udløber efter 365 dage
Grænse: 5 aktive nøgler pr. bruger. Hvis grænsen overskrides, svarer endpointet med en 429.
Bedste praksis
- Opbevar API-nøglen sikkert. Inkluder den aldrig i frontend-kode, offentlige repositories eller logs.
- Håndter rate limiting. Implementer eksponentiel backoff, hvis du modtager en
429. - Brug sideinddeling. Anmod ikke om alle poster på én gang; iterer med
limitogoffset. - Verificer svarkoderne. Antag ikke, at alle anmodninger vil lykkes.
- Roter nøgler regelmæssigt. Opret en ny nøgle, opdater din integration og tilbagekald den tidligere.
- Brug altid HTTPS. Alle anmodninger til API'en skal ske via HTTPS.
- Brug filtre. Parametrene
status,fromogtoreducerer mængden af overførte data. - Udnyt PATCH. Ved delvise opdateringer skal du kun sende de ændrede felter.