Ons API Webhooks in je integratie gebruiken
Ons API Webhooks stelt externe integraties in staat om notificaties te ontvangen van gebeurtenissen (wijzigingen in de data van applicaties) in de Ons Suite.
Usecases
Er zijn twee veelvoorkomende situaties waarbij het handig is om Ons API Webhooks te gebruiken:
Een gesynchroniseerde dataset onderhouden voor gebruik in je integratie
Na het eenmalig ophalen van alle gegevens (bijvoorbeeld via /t/employees/x-stream-connect/data
), kun je vervolgens up-to-date blijven door je te abonneren op alle event types voor Employee
en ze te verwerken zodra ze binnenkomen. Zonder webhooks zou je regelmatig moeten controleren op de /t/employees/x-stream-connect/updates
en /t/employees/x-stream-connect/deletes
endpoints, en zelfs bij het controleren om de 5 minuten zou je altijd een beetje achterlopen.
Reageren op gebeurtenissen binnen de Ons Suite
Bijvoorbeeld, de volgende stap nadat een medewerker een Client
aanmaakt in Ons zou kunnen zijn om een bepaalde actie uit te voeren in je geïntegreerde systeem, maar dit kan alleen worden gedaan nadat die Client
is gesynchroniseerd.
- Zonder webhooks moet die gebruiker wachten tot de volgende geplande synchronisatie of zelf een handmatige synchronisatie starten. Dit is geen goede gebruikerservaring.
- Met webhooks kan de Client gesynchroniseerd worden met je geïntegreerde systeem tegen de tijd dat de gebruiker is overgeschakeld.
Hoe webhooks te gebruiken
Abonneren
Om je te abonneren op webhooks, moeten er vier stappen worden voltooid:
-
Genereer een secret op de pagina van jouw koppeling (zie Afbeelding 1). Dit secret wordt gebruikt om de Hash-based Message Authentication Code (HMAC) te verifiëren. Hoe dit te implementeren, staat verder beschreven in authenticatie.
-
Zorg ervoor dat er een
POST
endpoint - dat in staat is om notificaties te ontvangen - beschikbaar is op het URL dat je wil gebruiken voor webhooks. Dit endpoint moet een200 OK
status terug sturen bij een correcte HMAC, en een401 UNAUTHORIZED
bij een incorrecte HMAC. Om te verifiëren dat dit goed is geïmplementeerd, zullen er tijdens het configureren van je URL tweeNOP
events verstuurd worden. Hierbij heeft er één een correcte HMAC heeft, en één een incorrecte HMAC (lees NOP-event). -
Configureer de webhooks-URL’s voor je integratie in het Ons API-dashboard op de pagina van jouw koppeling. Dit zullen drie URL’s zijn, een voor iedere omgeving (
development
,staging
enproduction
). Alle versies van jouw koppeling zullen gebruik maken van deze URL’s. Meer specifieke routing moet worden gedaan aan de kant van de integratie.Afbeelding 1.
-
Selecteer in de versie die webhook-abonnementen vereist alle combinaties van
Model
en event-types die interessant zijn voor de integratie en sla deze vervolgens op. Je geselecteerde webhook-abonnementen maken deel uit van de review die wordt uitgevoerd vóór het volgende ontwikkelstadium kan worden bereikt.Afbeelding 2.
Vanwege redundantie en caching in onze webhook-service kan het tot 5 minuten duren nadat je hebt opgeslagen voordat je op een betrouwbare manier begint (of stopt) met het ontvangen van geselecteerde events. Je zal alleen events ontvangen van klanten omgevingen waar een actief certificaat aan gekoppeld is.
Afhandelen van notificaties
De Notification
objecten die naar je notificatie endpoint worden gepost, zullen altijd thin notificaties zijn. Dit betekent dat ze alleen voldoende informatie bevatten om je te vertellen welke zorgorganisatie-omgeving betrokken is, welk type record op welke manier is gewijzigd en wat de id van dit record is, zie notificatie-model.
Daarom heeft je integratie altijd toegang nodig tot API’s die het ophalen van deze records mogelijk maken op basis van hun ID, zodat je integratie ze kan ophalen, inspecteren en kan bepalen wat te doen.
Technische details en voorbeelden
Webhook endpoint
De Ons API Webhook-service zal Notificatie-objecten POST
‘en naar het geconfigureerde notificatie URL. Jouw integratie moet deze requests accepteren en reageren met een 200
statuscode om aan te geven dat de melding is ontvangen. Verzoeken waarbij geen verbinding kan worden gemaakt, of die geen 200-respons binnen 5 seconden ontvangen, worden beschouwd als mislukte verzoeken.
We raden aan om requests te accepteren, de melding op te slaan in een soort wachtrij, te reageren met een 200
statuscode en vervolgens de request te verwerken in een ander proces. Dit ontkoppelt het ontvangen en verwerken van gebeurtenissen en voorkomt dat je gebeurtenissen mist wanneer de verwerking tijdelijk vertraagt. Plan om 100’en gebeurtenissen per seconde te ontvangen, aangezien het verkeer kan pieken bij: bulkcorrecties, imports, on-demand bulkheraflevering van mislukte notificaties, of een inhaalslag na downtime.
Authenticatie
- Onze service zal zichzelf identificeren door middel van een HTTP-header genaamd
X-Signature-SHA512
. Deze header is een HMAC (Hash-based message authentication code) dat de geconfigureerde secret en payload van de request hashed met het SHA512 algoritme. De secret is te genereren in de pagina van de koppeling. - Bij een correcte HMAC verwacht onze service dat er met een
200
statuscode wordt gereageerd. Als de HMAC incorrect is, wordt er verwacht dat er met een401
statuscode wordt gereageerd. Bij het instellen van je URL’s zal geverifiëerd worden of dit correct is geïmplementeerd door middel van een NOP-event - We verwachten dat je server HTTPS gebruikt.
Dit is hoe een HMAC gegenereerd kan worden in Java
:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class SignatureGenerator {
private static final String ALGORITHM = "HmacSHA512";
public static String generateSignature(String data, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance(ALGORITHM);
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(), ALGORITHM);
mac.init(secretKeySpec);
byte[] macBytes = mac.doFinal(data.getBytes());
return toHexString(macBytes);
}
private static String toHexString(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = String.format("%02x", b);
hexString.append(hex);
}
return hexString.toString();
}
public static void main(String[] args) {
try {
String data = "{\"customerCode\":\"TE1000\",\"modelType\":\"client\",\"eventType\":\"CREATE\",\"id\":1,\"timestamp\":\"2024-08-22T10:08:11+02:00\",\"amountOfRetries\":0}";
String secret = "SuperSecret";
String signature = generateSignature(data, secret);
System.out.println("Signature: " + signature);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
}
}
Notificatie-model
De verzonden Notification
’s zullen eruit zien als:
{
"customerCode": "TE1002",
"modelType": "client",
"eventType": "CREATE",
"id": 1234,
"timestamp": "2024-08-22T10:08:11+02:00",
"amountOfRetries": 0
}
customerCode
zal de zorgorganisatie-omgeving identificeren en dit komt overeen met decustomerCode
die wordt gebruikt in de certificaten die je gebruikt voor API-verzoeken.modelType
zal het model aangeven.eventType
het type actie (CREATE
,UPDATE
,DELETE
,CUSTOM
,NOP
) die het evenement heeft getriggerd.id
het id van het model.timestamp
wanneer het event is getriggered.amountOfRetries
hoevaak dit event geprobeerd is te versturen.
NOP-event
Een NOP-event staat voor “no operation” event. Bij het ontvangen van een NOP-event hoeft er alleen de HMAC gecontroleerd te worden. Op basis van de HMAC moet dan een 200
of 401
statuscode teruggestuurd worden. NOP-events kunnen genegeerd worden (ze worden alleen gebruikt om jouw HMAC-implementatie te valideren)
Ondersteunde events
Beschikbare modelType
’s en eventType
’s kunnen in de loop van de tijd worden uitgebreid, maar je zult nooit meldingen ontvangen voor gebeurtenissen waarop je je niet hebt geabonneerd.
De momenteel ondersteunde events zijn:
CREATE
, UPDATE
, DELETE
Events
EventType | ModelType | Beschrijving |
---|---|---|
client | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een cliënt. |
client_address | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een koppeling tussen cliënt en address. |
client_contact_relation | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een relatie tussen cliënt en contact. |
insurance | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van verzekeringsgegevens. |
client_contact_relation_address | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een adres van een contact dat een relatie heeft met een cliënt. |
location_assignment | UPDATE | Bij het wijzigen van een koppeling tussen locatie en cliënt. |
report | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een rapportage. |
employee | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een medewerker. |
hour_type | CREATE, UPDATE | Bij het aanmaken of wijzigen van uur soorten. |
location | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een locatie. |
team | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een team. |
user | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een gebruiker. |
address | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een adres. |
employee_address | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een koppeling tussen medewerker en adres. |
expertise_profile | CREATE, UPDATE | Bij het aanmaken of wijzigen van een deskundigheidsprofiel. |
contract | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een contract van een medewerker. |
care_plan | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een zorgplan. |
team_assignment | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een koppeling tussen medewerker en team . |
care_allocation | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van zorgopnamegegevens van een cliënt. |
client_employee_relation | CREATE, UPDATE, DELETE | Bij het aanmaken, wijzigen of verwijderen van een relatie tussen cliënt en medewerker. |
CUSTOM
Events
We ondersteunen ook enkele events die niet een CREATE
/UPDATE
/DELETE
van een enkel record zijn maar een bepaalde gebeurtenis vertegenwoordigen. Deze tabel legt uit welke events dat zijn en waar het ID in het event naar verwijst:
EventType | ModelType | Beschrijving | ID verwijst naar |
---|---|---|---|
external_care_providers_changed | CUSTOM | Bij het wijzigen van de zorgverleners van een cliënt | Client |
client_employee_relations_changed | CUSTOM | Bij het wijzigen van betrokken medewerkers in het cliëntennetwerk van een cliënt. | Client |
team_assignment_changed | CUSTOM | Bij het wijzigen van een team van een medewerker. | Employee |
care_plan_activated | CUSTOM | Bij het activeren van een zorgplan van een cliënt. | Client |
client_careallocations_changed | CUSTOM | Bij het wijzigen van zorgopnamegegevens van een cliënt. | Client |
Leveringsvolgorde
We kunnen niet garanderen dat meldingen worden afgeleverd in de volgorde waarin ze worden geactiveerd. Dit betekent dat je bijvoorbeeld een UPDATE
-notificatie kunt zien voor een client
waarvoor je de CREATE
nog niet hebt gezien. Ontwerp je integratie zo dat deze situaties kan afhandelen. Dit kan voorkomen omdat onze webhook-service is geïmplementeerd met meerdere instances die meldingen in batches ophalen, en omdat de levering van een enkele notificaties kan mislukken en de herhaling ervan deze mogelijk na een andere melding voor hetzelfde record plaatst waarvan de levering is gelukt. Bijvoorbeeld:
10:00:00 CREATE CLIENT 1 <- De levering van deze melding mislukt
10:00:05 UPDATE CLIENT 1 <- De levering van deze melding slaagt
10:01:00 CREATE CLIENT 1 <- De heraflevering van de melding slaagt deze keer
Mislukte bezorgpogingen
Requests die niet binnen 5 seconden worden beantwoord met een 200
statuscode worden beschouwd als mislukte requests.
Bezorging wordt niet automatisch opnieuw geprobeerd. We slaan events waarvoor de bezorging is mislukt 24 uur lang op en verwijderen ze vervolgens.
We kunnen tot 1.000.000 events bewaren, daarna komen de events in een ‘overflow’ en gaan ze verloren.
Je integratie kan opnieuw bezorgen van mislukte meldingen aanvragen door een PUT
-request met een lege body te sturen naar /webhooks/redeliver
.
Dit wordt gedaan met een certificaat dat bij een koppeling is geconfigureerd, hiermee kun je per stage (development, staging, production) alle gemiste notificaties van jouw koppeling opnieuw laten afleveren.
Plan voor resynchronisatie
Mislukte bezorgingen van Ons API Webhook-notificaties worden 24 uur lang opgeslagen en kunnen gedurende die periode opnieuw worden geprobeerd. Als je webhook-endpoint langer dan die periode offline is, gaan de gemiste notificaties verloren. We raden je aan een optie voor resynchronisatie te ontwerpen voor het geval dat gebeurt.
Event loops
Als je reageert op een notificatie door het record in Ons bij te werken waarvoor je de notificatie hebt ontvangen, ontvang je een ander event voor datzelfde record. Als dat tweede event een nieuwe update vanuit je integratie activeert, kan dit een event loop veroorzaken. Hieronder staan voorbeelden van twee situaties die een event loop veroorzaken.
Voorbeeld van een event loop in geval van een enkele integratie
Als voorbeeld van hoe dingen mis kunnen gaan, stel dat je een automatische spellingscorrector hebt geïmplementeerd die reageert op notificaties over de creatie of update van een Report
en het Report opnieuw opslaat met gecorrigeerde spelling. Wat er kan gebeuren als je het Report opslaat zonder te controleren of er iets is veranderd:
- Gebeurtenis ontvangen voor
Report
1234
- Haal
Report
1234
op - Corrigeer spelling
PUT
Report
1234
(ongeacht of er iets is veranderd aan het model)- Ga terug naar 1
Je kunt deze lus doorbreken door te detecteren dat je integratie niets heeft veranderd aan het Report en het niet op te slaan.
Voorbeeld van een event loop in geval van een meerdere integraties
Voortbouwend op het bovenstaande voorbeeld. Zelfs als je integratie op de hoogte is van notificaties die zijn gemaakt door zijn eigen acties, kunnen twee integraties elkaar activeren. Stel je twee spellingscontrole-integraties voor, die afzonderlijk geen event loops veroorzaken, met iets andere spellingregels:
- Beide integraties ontvangen een
CREATE
-event voorReport
1234
- Beide integraties voeren hun spellingscontrole uit
- Integratie A brengt geen wijzigingen aan en werkt het
Report
niet bij - Integratie B brengt enkele wijzigingen aan en werkt het
Report
bij
- Integratie A brengt geen wijzigingen aan en werkt het
- Beide integraties ontvangen een UPDATE-event voor
Report
1234
- Integratie A brengt wijzigingen aan en werkt het
Report
bij - Integratie B brengt geen wijzigingen aan en werkt het
Report
niet bij
- Integratie A brengt wijzigingen aan en werkt het
- Beide integraties ontvangen een
UPDATE
-event voorReport
1234
- Integratie A brengt geen wijzigingen aan en werkt het
Report
niet bij - Integratie B brengt wijzigingen aan en werkt het
Report
bij
- Integratie A brengt geen wijzigingen aan en werkt het
- Terug naar 3
Deze loop is iets moeilijker te doorbreken, aangezien er iets is veranderd sinds de laatste keer dat je integratie het record heeft opgeslagen. We raden aan om een controle te implementeren om ervoor te zorgen dat je niet herhaaldelijk hetzelfde record bewerkt.
Open API specificatie
Jouw webhooks endpoint moet aan deze specificatie voldoen. Je kunt je eigen ‘path’ configureren. Download de specificatie hier.