Authenticatie
Alle API-aanvragen gebruiken een API-sleutel als bearer-token. Maak er een aan in de app onder Developer → API keys. Sleutels zijn ofwel alleen-lezen of lezen/schrijven.
curl https://savrsoft.com/api/v1/events \ -H "Authorization: Bearer savr_live_your_key_here"
Basis-URL: https://savrsoft.com/api/v1 · Alle antwoorden zijn JSON. Fouten geven { "error": "…" } terug met een 4xx/5xx-status.
Statuscodes
| Code | Wanneer u dit krijgt |
|---|---|
200 | Succesvol gelezen. |
201 | Succesvol aangemaakt. De body is { "id": 42 } — haal het record op als u de rest ervan nodig heeft. |
400 | Een verplicht veld ontbreekt, bijv. { "error": "name is required" }, of een pagineringscursor kon niet worden gelezen. |
401 | Geen API-sleutel, een onjuiste sleutel, of een sleutel die is ingetrokken. |
403 | Er is een alleen-lezen sleutel gebruikt voor een schrijfactie. Maak een lees-/schrijfsleutel aan onder Developer → API keys. |
404 | Het record bestaat niet, of behoort toe aan een andere organisatie — dit onderscheid wordt bewust niet gemaakt. Wordt ook geretourneerd bij een onbekend pad of een onbekende methode. |
Bereik van deze API
De API is alleen lezen en aanmaken. Er zijn geen DELETE, PUT of PATCH
endpoints — een verzoek dat hier gebruik van maakt, retourneert 404 Unknown endpoint, net als bij elk onbekend pad. Verwijderen en
bewerken gebeurt in de app, zodat een integratie de gegevens van een cateraar niet kan vernietigen. Heb je schrijftoegang nodig die verder gaat dan aanmaken,
laat ons weten wat je aan het bouwen bent.
Paginering
Elk lijst-endpoint is gepagineerd. Geef limit (standaard 100, maximaal 500) mee en
volg next_cursor totdat has_more gelijk is aan false:
{
"data": [ ... ],
"has_more": true,
"next_cursor": "eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0"
}
Geef de cursor direct terug om de volgende pagina op te halen. Behandel deze als ondoorzichtig — de codering kan wijzigen:
curl "https://savrsoft.com/api/v1/clients?limit=100&cursor=eyJuYW1lIjoiQWNtZSIsImlkIjo0Mn0" \ -H "Authorization: Bearer savr_live_your_key_here"
Paginering is verankerd aan de laatst ontvangen rij, niet aan een offset, zodat rijen die tijdens het pagineren worden aangemaakt of verwijderd er niet toe leiden dat u een record overslaat of herhaalt. Een cursor blijft voor onbepaalde tijd geldig.
| Parameter | Gedrag |
|---|---|
limit | 1–500. Ontbrekend, nul, negatief of niet-numeriek valt terug op 100; alles boven 500 wordt afgetopt op 500. |
cursor | next_cursor van de vorige pagina. Laat dit weg voor de eerste pagina. Een cursor die niet gelezen kan worden — corrupt, of afkomstig van een ander endpoint — retourneert 400 Invalid cursor in plaats van stilzwijgend opnieuw vanaf het begin te starten. |
Sortering: /events en /invoices nieuwste eerst; /recipes en
/clients op naam, waarbij gelijke standen worden beslist op id zodat paginering stabiel blijft wanneer namen zich herhalen.
Endpoints
/v1/meUw organisatie (id, naam, valuta).
/v1/eventsToon evenementen, nieuwste eerst. Gepagineerd — zie Paginering hierboven.
/v1/events/{id}Eén evenement met de bijbehorende gerechten.
/v1/events · vereist lees-/schrijftoegangMaak een evenement aan. Body:
{ "name": "Acme holiday party", "event_date": "2026-12-18",
"guests": 120, "price_per_head": 55, "event_type": "corporate" }
/v1/recipes · GET/v1/recipes/{id}Toon recepten (met allergenen & dieetlabels), of één recept met ingrediënten. De lijst is gepagineerd en gesorteerd op naam.
/v1/clients · POST/v1/clientsToon klanten (gepagineerd, op naam) of maak er één aan. Body om aan te maken: { "name": "...", "email": "...", "phone": "...", "company": "..." }
/v1/invoices · GET/v1/invoices/{id}Toon facturen met berekende totalen, nieuwste eerst, of één factuur met factuurregels. De lijst is gepagineerd.
Webhooks
Registreer een endpoint onder Developer → Webhooks. We sturen een POST met een JSON-payload zodra er gebeurtenissen plaatsvinden:
{
"id": "evt_abc123",
"type": "event.inquiry",
"created_at": "2026-07-17T18:20:00.000Z",
"data": { "id": 42, "name": "Corporate lunch — Dana Ruiz", ... }
}
Soorten evenementen
| Type | Wordt geactiveerd bij |
|---|---|
event.created | Een evenement wordt aangemaakt |
event.inquiry | Er komt een nieuwe online cateringaanvraag binnen |
invoice.sent | Een factuur wordt gemarkeerd als verzonden |
invoice.paid | Een factuur wordt gemarkeerd als betaald |
proposal.approved | Een klant keurt een offerte goed |
client.created | Er wordt een klant aangemaakt |
Handtekeningen verifiëren
Elke levering bevat een x-savrsoft-signature header: de HMAC-SHA256 van de ruwe request body, gebaseerd op uw webhook-signeersleutel. Bereken hetzelfde en vergelijk:
// 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();
