savrsoft

API-dokumentation

Et enkelt REST API til at læse og skrive dine cateringdata, samt signerede webhooks til begivenheder i realtid. Opret en nøgle under Developer i appen.

Godkendelse

Alle API-forespørgsler bruger en API-nøgle som et bearer token. Opret en i appen under Developer → API keys. Nøgler er enten read-only eller read/write.

curl https://savrsoft.com/api/v1/events \
  -H "Authorization: Bearer savr_live_your_key_here"

Base URL: https://savrsoft.com/api/v1 · Alle svar er i JSON-format. Fejl returnerer { "error": "…" } med en 4xx/5xx-status.

Statuskoder

KodeHvornår du får den
200Vellykket læsning.
201Oprettet med succes. Body'en er { "id": 42 } — hent posten, hvis du har brug for resten af den.
400Et påkrævet felt mangler, f.eks. { "error": "name is required" }, eller en pagineringscursor kunne ikke læses.
401Ingen API-nøgle, en ugyldig en, eller en nøgle der er blevet tilbagekaldt.
403En skrivebeskyttet nøgle blev brugt til en skriveoperation. Opret en læse-/skrivenøgle under Udvikler → API-nøgler.
404Posten findes ikke, eller tilhører en anden organisation — de to er bevidst umulige at skelne fra hinanden. Returneres også for en ukendt sti eller metode.

Omfanget af dette API

API'et er kun læsning og oprettelse. Der findes ingen DELETE, PUT eller PATCH -endpoints — en forespørgsel der bruger en af disse returnerer 404 Unknown endpoint, på samme måde som enhver ukendt sti. Sletning og redigering foregår i appen, så en integration kan ikke destruere en cateringvirksomheds data. Hvis du har brug for skriveadgang ud over oprettelse, så fortæl os hvad du bygger.

Paginering

Alle liste-endpoints er pagineret. Angiv limit (standard 100, maksimum 500) og følg next_cursor indtil has_more er false:

{
  "data": [ ... ],
  "has_more": true,
  "next_cursor": "eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0"
}

Send cursoren direkte tilbage for at få næste side. Behandl den som ugennemsigtig — kodningen kan ændre sig:

curl "https://savrsoft.com/api/v1/clients?limit=100&cursor=eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0" \
  -H "Authorization: Bearer savr_live_your_key_here"

Paginering er forankret til den sidste række, du modtog, ikke til en offset, så rækker, der oprettes eller slettes, mens du paginerer, vil ikke få dig til at springe over eller gentage en post. En cursor forbliver gyldig på ubestemt tid.

ParameterAdfærd
limit1–500. Fraværende, nul, negativ eller ikke-numerisk falder tilbage til 100; alt over 500 begrænses til 500.
cursornext_cursor fra den forrige side. Udelad den for den første side. En cursor, der ikke kan læses — beskadiget eller fra et andet endpoint — returnerer 400 Invalid cursor frem for stiltiende at starte forfra.

Rækkefølge: /events og /invoices nyeste først; /recipes og /clients efter navn, hvor uafgjorte afgøres af id, så pagineringen forbliver stabil, når navne gentages.

Endpoints

GET/v1/me

Din organisation (id, navn, valuta).

GET/v1/events

Liste over events, nyeste først. Pagineret — se Paginering ovenfor.

GET/v1/events/{id}

Et event med sine retter.

POST/v1/events · kræver læse-/skriveadgang

Opret et event. Body:

{ "name": "Acme holiday party", "event_date": "2026-12-18",
  "guests": 120, "price_per_head": 55, "event_type": "corporate" }
GET/v1/recipes · GET/v1/recipes/{id}

List opskrifter (med allergener & kostflag), eller én opskrift med ingredienser. Listen er pagineret og sorteret efter navn.

GET/v1/clients · POST/v1/clients

List kunder (pagineret, efter navn), eller opret en. Body ved oprettelse: { "name": "...", "email": "...", "phone": "...", "company": "..." }

GET/v1/invoices · GET/v1/invoices/{id}

List fakturaer med beregnede totaler, nyeste først, eller én faktura med linjeposter. Listen er pagineret.

Webhooks

Registrer et endpoint under Udvikler → Webhooks. Vi sender en POST med en JSON-payload, når events indtræffer:

{
  "id": "evt_abc123",
  "type": "event.inquiry",
  "created_at": "2026-07-17T18:20:00.000Z",
  "data": { "id": 42, "name": "Corporate lunch — Dana Ruiz", ... }
}

Eventtyper

TypeUdløses når
event.createdEt event oprettes
event.inquiryEn ny online cateringforespørgsel modtages
invoice.sentEn faktura markeres som sendt
invoice.paidEn faktura markeres som betalt
proposal.approvedEn kunde godkender et forslag
client.createdEn kunde oprettes

Verificering af signaturer

Hver levering indeholder en x-savrsoft-signature header: HMAC-SHA256 af den rå request body, nøglet med din webhook signing secret. Beregn den samme og sammenlign:

// Node.js
const crypto = require('crypto');
const sig = crypto.createHmac('sha256', SIGNING_SECRET)
  .update(rawBody).digest('hex');
if (sig !== req.headers['x-savrsoft-signature']) reject();
Privatliv · Sikkerhed · Vilkår · Spørgsmål? savrsoft.com · Byg cateringintegrationer på få minutter.