{"openapi":"3.1.0","info":{"title":"NovaDirect API","version":"1.0.0","description":"Lees je inspecties, opdrachtgevers, planning en offertes uit NovaDirect.\n\nAuthenticatie: stuur je sleutel mee als `Authorization: Bearer nd_live_...`.\nSleutels maak je aan in de app onder Instellingen → Koppelingen.\n\nDeze API is bedoeld voor verkeer tussen servers. Gebruik een sleutel nooit\nin een webpagina of mobiele app: daar is hij voor iedereen leesbaar.\n\nPaginering gaat met een cursor en niet met paginanummers. Bij nummers\nverschuiven records tussen twee verzoeken zodra er iets bijkomt, en sla je\ner stilletjes één over."},"servers":[{"url":"https://novadirect.nl"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Je API-sleutel (`nd_live_...`)."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machineleesbaar, bijvoorbeeld `not_found` of `plan_required`."},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"Inspection":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","description":"Inspectietype, bijvoorbeeld `NEN3140`."},"status":{"type":"string"},"client_name":{"type":"string","nullable":true},"customer_id":{"type":"string","nullable":true},"location_name":{"type":"string","nullable":true},"location_address":{"type":"string","nullable":true},"inspector_id":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time","nullable":true},"completed_at":{"type":"string","format":"date-time","nullable":true},"report_url":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}}},"Customer":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"postal_code":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"kvk_number":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}}},"PlanningEvent":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"location":{"type":"string","nullable":true},"start_at":{"type":"string","format":"date-time","nullable":true},"end_at":{"type":"string","format":"date-time","nullable":true},"all_day":{"type":"boolean"},"status":{"type":"string"},"assigned_to_id":{"type":"string","nullable":true},"customer_id":{"type":"string","nullable":true},"inspection_id":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}}},"PlanningEventWrite":{"type":"object","description":"Bij een PUT zijn alle velden optioneel; wat je weglaat blijft ongewijzigd.","properties":{"title":{"type":"string","maxLength":200},"description":{"type":"string","nullable":true},"location":{"type":"string","nullable":true},"start_at":{"type":"string","format":"date-time"},"end_at":{"type":"string","format":"date-time","nullable":true},"all_day":{"type":"boolean","default":false},"status":{"type":"string","enum":["SCHEDULED","IN_PROGRESS","DONE","CANCELLED"],"default":"SCHEDULED"},"assigned_to_id":{"type":"string","nullable":true,"description":"Moet een gebruiker van dezelfde organisatie zijn."},"customer_id":{"type":"string","nullable":true},"inspection_id":{"type":"string","nullable":true}},"required":["title","start_at"]},"Quote":{"type":"object","properties":{"id":{"type":"string"},"quote_number":{"type":"string"},"status":{"type":"string"},"title":{"type":"string","nullable":true},"customer_id":{"type":"string","nullable":true},"inspection_id":{"type":"string","nullable":true},"client_name":{"type":"string","nullable":true},"subtotal":{"type":"string","description":"Bedrag als string, om afrondingsfouten te voorkomen."},"vat_amount":{"type":"string"},"total":{"type":"string"},"valid_until":{"type":"string","format":"date-time","nullable":true},"sent_at":{"type":"string","format":"date-time","nullable":true},"responded_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time","nullable":true}}}}},"paths":{"/api/v1/me":{"get":{"summary":"Controleer je sleutel","description":"Geeft terug bij welke organisatie deze sleutel hoort en wat hij mag. Werkt met elke geldige sleutel, ongeacht rechten — gebruik dit om een verbinding te testen.","x-scope":null,"responses":{"200":{"description":"De sleutel is geldig.","content":{"application/json":{"schema":{"type":"object","properties":{"organization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"scopes":{"type":"array","items":{"type":"string","enum":["inspections:read","customers:read","planning:read","planning:write","quotes:read","reports:read","webhooks:read"]}},"can_write":{"type":"boolean"}}}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/inspections":{"get":{"summary":"Inspecties opvragen","x-scope":"inspections:read","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Aantal resultaten per pagina."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"De `next_cursor` uit het vorige antwoord. Laat leeg voor de eerste pagina."},{"name":"updated_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Alleen records die op of na dit tijdstip zijn gewijzigd. Gebruik dit om alleen het nieuwe op te halen."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter op status."},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Filter op inspectietype."}],"responses":{"200":{"description":"Een pagina inspecties.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Inspection"}},"next_cursor":{"type":"string","nullable":true,"description":"Geef mee als `cursor` voor de volgende pagina. `null` betekent: dit was de laatste."},"has_more":{"type":"boolean"}},"required":["data","next_cursor","has_more"]}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/inspections/{id}":{"get":{"summary":"Eén inspectie opvragen","x-scope":"inspections:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"De inspectie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inspection"}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Niet gevonden, of niet van deze organisatie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/customers":{"get":{"summary":"Opdrachtgevers opvragen","x-scope":"customers:read","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Aantal resultaten per pagina."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"De `next_cursor` uit het vorige antwoord. Laat leeg voor de eerste pagina."},{"name":"updated_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Alleen records die op of na dit tijdstip zijn gewijzigd. Gebruik dit om alleen het nieuwe op te halen."}],"responses":{"200":{"description":"Een pagina opdrachtgevers.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"next_cursor":{"type":"string","nullable":true,"description":"Geef mee als `cursor` voor de volgende pagina. `null` betekent: dit was de laatste."},"has_more":{"type":"boolean"}},"required":["data","next_cursor","has_more"]}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/customers/{id}":{"get":{"summary":"Eén opdrachtgever opvragen","x-scope":"customers:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"De opdrachtgever.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Niet gevonden, of niet van deze organisatie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/planning-events":{"post":{"summary":"Afspraak inplannen","description":"Zet een afspraak in de planning. Hiermee kan een extern planningspakket werkorders bij ons neerzetten. Vereist een abonnement met schrijfrechten.","x-scope":"planning:write","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningEventWrite"}}}},"responses":{"201":{"description":"De aangemaakte afspraak.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningEvent"}}}},"400":{"description":"Ongeldige invoer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Niet gevonden, of niet van deze organisatie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"Planning opvragen","x-scope":"planning:read","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Aantal resultaten per pagina."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"De `next_cursor` uit het vorige antwoord. Laat leeg voor de eerste pagina."},{"name":"updated_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Alleen records die op of na dit tijdstip zijn gewijzigd. Gebruik dit om alleen het nieuwe op te halen."},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Alleen afspraken die op of na dit tijdstip beginnen."},{"name":"until","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Alleen afspraken die op of vóór dit tijdstip beginnen."}],"responses":{"200":{"description":"Een pagina afspraken.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlanningEvent"}},"next_cursor":{"type":"string","nullable":true,"description":"Geef mee als `cursor` voor de volgende pagina. `null` betekent: dit was de laatste."},"has_more":{"type":"boolean"}},"required":["data","next_cursor","has_more"]}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/planning-events/{id}":{"put":{"summary":"Afspraak wijzigen","description":"Werkt alleen de meegestuurde velden bij; wat je weglaat blijft staan.","x-scope":"planning:write","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningEventWrite"}}}},"responses":{"200":{"description":"De bijgewerkte afspraak.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanningEvent"}}}},"400":{"description":"Ongeldige invoer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Niet gevonden, of niet van deze organisatie.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/quotes":{"get":{"summary":"Offertes opvragen","x-scope":"quotes:read","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Aantal resultaten per pagina."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"De `next_cursor` uit het vorige antwoord. Laat leeg voor de eerste pagina."},{"name":"updated_since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Alleen records die op of na dit tijdstip zijn gewijzigd. Gebruik dit om alleen het nieuwe op te halen."},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter op status."}],"responses":{"200":{"description":"Een pagina offertes.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}},"next_cursor":{"type":"string","nullable":true,"description":"Geef mee als `cursor` voor de volgende pagina. `null` betekent: dit was de laatste."},"has_more":{"type":"boolean"}},"required":["data","next_cursor","has_more"]}}}},"401":{"description":"Ontbrekende of ongeldige sleutel.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Het abonnement dekt deze API niet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"De sleutel mist het benodigde recht.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Te veel verzoeken. Zie de `Retry-After`-header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}