A webhook enables our ecosystem to push real-time notifications to your backend systems. Webhooks Service uses HTTPS to send these notifications to your backend endpoint as a JSON payload. You can then use these notifications to execute actions in your backend systems.
Hubject uses the Webhook Service to notify your backend system when some event happens in our ecosystem. Webhooks are particularly useful for asynchronous events like when a contract is created or a root certificate expires.
The following figure provides a high-level overview of the interface concept of the webhook service. The service is subscribed to all relevant events within the ecosystem. The partners can register at the webhook service to observe assets in the ecosystem. Relevant events from the other ecosystem components are collected by the callback service and forwarded to the partner’s system.
Available Events
The following actions trigger the event notification. The messages are routed to the observing backends as noted.
Relevant for Role | Event Name | Description | Message (Logging examples) |
---|---|---|---|
ALL | root.cert.added | A new root got added to the root pool (RCP), important for CPOs to check if a new V2G or MO Root CA needs to be pushed to the EVSEs for authentication. | "New root available in RCP" |
ALL | root.cert.expired | A root expired and it will be removed from the RCP. No emergency action needed as it is a natural phase out. | "Root Expired" |
ALL | root.cert.revoked |
A root got revoked and it was removed from the RCP. This requires action of multiple parties depending which root is affected. More manual communication will follow by the PKI provider. |
"Root revoked" |
MO | mo.prov.cert.deleted | The OEM triggered the deletion of all Contracts for a PCID/OEM Prov. Certificate. The MO shall not create new Contracts for the EMAID. (e.g. Factory Reset, Car is sold). | "PnC is currently disabled, bacause the OEM Provisioning certificate was Deleted/Revoked." |
MO | mo.prov.cert.factory.reset | The OEM triggered the deletion of all Contracts for a PCID/OEM Prov. Certificate. The MO shall not create new Contracts for the EMAID. (e.g. Factory Reset, Car is sold). | "Factory Reset was performed. All contracts for PCID where Removed." |
MO | mo.prov.cert.updated.factory.reset | The OEM Prov. Certificate got updated (different privat and public key). Hubject deleted all existing Contract Data for that PCID on CCP as they are not valid anymore. The MO shall communicate with the Customer if the contract shall be recreated for the known PCID. (WERKSTATTFALL) - DEPRECATED | "Contract deleted, because a new OEM Prov. Certificate was created. Sync with customer for next steps." |
MO | mo.prov.cert.updated | The OEM Prov. Certificate got updated (different privat and public key). Hubject deleted all existing Contract Data for that PCID on CCP as they are not valid anymore.The MO shall communicate with the Customer if the contract shall be recreated for the known PCID. (WERKSTATTFALL) | "Contract deleted, because a new OEM Prov. Certificate was created. Sync with customer for next steps." |
MO | mo.contract.created.sent.to.oem | The contract information (oem.contract.created) has been sent to the OEM Backend. | "Contract information (oem.contract.created) has been sent to the OEM Backend." |
MO | mo.contract.updated.sent.to.oem | The contract information (oem.contract.updated) has been sent to the OEM Backend. | "Contract information (oem.contract.updated) has been sent to the OEM Backend." |
MO | mo.contract.deleted.sent.to.oem | The contract information (oem.contract.deleted) has been sent to the OEM Backend. | "Contract information (oem.contract.deleted) has been sent to the OEM Backend." |
MO | mo.contract.delivered.to.oem |
Successfully delivery of the Contract Data. The Contract Data with the given EMAID got either: - Pulled from the OEM Backend - Installed over EVSE (certificateInstallationRequest) |
"Signed Contract Certificate Bundle successfully delivered to OEM or CPO-Backend" |
MO | mo.contract.rejected.by.oem | The contract information Event got rejected by the OEM Backend. A negative response of the OEM Backend about new, updated or deleted contract data was received. Action stopped in case OEM send HTTP400 or HTTP409. Otherwise retry started to OEM. | "Info about contract Creation/Updated/Deletion (oem.contract.*) could not be delivered to OEM." |
MO | mo.contract.queued.to.oem | Retry to OEM started for (oem.contract.*). OEM Backend is not answering properly. | "Retry started in direction of the OEM Backend from Hubject for (oem.contract.*) started." |
OEM | oem.contract.created | Info to OEM Backend about a new Contract Data available in CCP. | "New contract available for PCID … with EMAID….." |
OEM | oem.contract.updated | Info to OEM Backend about the update of the Contract Data in CCP. | "Updated contract data available for PCID… with EMAID…" |
OEM | oem.contract.deleted | Info to OEM Backend about a deletion of a Contract Data in CCP. | "Deleted contract for PCID…. With EMAID…" |
API
The webhook service requires the partner to provide a simple payload service with a public endpoint to receive events as a POST request.
Error Handling
The webhook service has a retry mechanism in place - for HTTP 5xx Server Errors, Hubject will retry in 1-hour intervals, and after 4 days, Hubject will unload the event as a failed event.
Webhooks Payloads Structures
For our webhooks service, we have 2 types of payloads depending on the ISO 15118 Version of the certificates.
-
If a certificate is ISO15118-2:2013, a webhook using ISO15118-2:2014 payload will be sent.
-
If a certificate is ISO15118-20:2022, a webhook using ISO15118-20:2022 payload will be sent.
ISO15118-2:2014 Payload Webhooks
Contract Payload Structure
Request: POST /payload-path HTTP/1.1 Host: your-payload-url.com Headers:
Content-Type: application/json X-Hubject-Signature: sha256=7808b566f4057216e64c6298bfd5a184d4d715ffec6599311e5266f48865XXXX Body:
{
"eventId": "caf56bee-f90d-4e81-a862-7e0d0f21d306", "eventType": "oem.contract.created", "payload": { "emaid": "EMAID", "pcid": "PCID", "contractCert": "CONTRACT_CERTIFICATE_BASE64" } }
Root Payload Structure
Request: POST /payload-path HTTP/1.1 Host: your-payload-url.com Headers:
Content-Type: application/json X-Hubject-Signature: sha256=7808b566f4057216e64c6298bfd5a184d4d715ffec6599311e5266f48865XXXX Body:
{
"eventId": "xxxxx",
"eventType": "root.cert.added",
"payload": {
"rootCertificateId": "xxxxx",
"distinguishedName": "xxxxx",
"commonName": "xxxxx" } }
ISO15118-20:2022 Payload Webhooks
Contract Payload Structure
Request: POST /payload-path HTTP/1.1
Host: your-payload-url.com
Headers:
Content-Type: application/json
X-Hubject-Signature: sha256=7808b566f4057216e64c6298bfd5a184d4d715ffec6599311e5266f48865XXXX
Body:
{
"timestamp": "2019-08-24T14:15:22Z",
"eventId": "xxxxxxxxc",
"eventType": "mo.prov.cert.updated",
"xsdMsgDefNamespace": "urn:iso:15118:20:2022:MsgDef",
"payload": {
"emaid": "EMAID",
"pcid": "PCID",
"contractCert": "CONTRACT_CERTIFICATE_BASE64",
"cpsSignerRootFingerprint": "xxxxxx",
"cpsSignerRootCommonName": "xxxxxx",
"signatureAlgorithm": "secp521r1"
}}
Root Payload Structure
Request: POST /payload-path HTTP/1.1
Host: your-payload-url.com
Headers:
Content-Type: application/json
X-Hubject-Signature: sha256=7808b566f4057216e64c6298bfd5a184d4d715ffec6599311e5266f48865XXXX
Body:
{
"timestamp": "2019-08-24T14:15:22Z",
"eventId": "xxxxxxxxx",
"eventType": "root.cert.added",
"xsdMsgDefNamespace": "urn:iso:15118:20:2022:MsgDef",
"payload": {
"rootCertificateId": "xxxxx",
"distinguishedName": "xxxxx",
"commonName": "xxxxx",
"rootType": "xxx"
"rootSerialNumber": "12345677888666",
"signatureAlogrithm": "secp521r1",
"fingerprintSHA256": "xxxxxxxx"
}}
Validating Payloads from Hubject
Hubject can optionally sign the webhook events it sends to your endpoints by including a signature in each event’s X-Hubject-Signature header. This allows you to verify that the events were sent by Hubject, not by a third party.
In order to validate the signature, you will need a secret of your endpoint, you can find it when you create a new endpoint for the webhook or retrieve the endpoint from the Webhooks's backend.
Hubject generates signatures using a hash-based message authentication code HMAC with SHA-256. To prevent downgrade attacks, you can create a custom solution by following these steps:
Step 1: Prepare the message string
- Get the actual JSON payload (i.e., the request body)
Step 2: Determine the expected signature
- Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the Request body string as the message.
Step 3: Compare the signature
- Compare the signature in the header to the expected signature.
For example, if you have a basic server that listens for webhooks, it might be configured similarly to this:
The recommended way is to calculate a hash using your webhooks secret, and ensure that the result matches the Signature from Hubject. Hubject uses an HMAC hex digest to compute the hash, so you could reconfigure your server to look a little like this:
Java Example
NOTE: Using a plain == operator is not advised. A method like secure_compare performs a "constant time" string comparison, which helps mitigate certain timing attacks against regular equality operators.
Status Code
These are the HTTP status codes that will be expected:
For a successful notification:
- 200 – OK
- 201 – Created
- 202 - Accepted
In those cases, the notification process stops.
For an Error case:
- 400 – Bad Request
- 404 – Not Found
- 409 - Conflict
In those cases, the notification process stops.
Any other error code will be a retry case:
- The notification will be retried every hour.
- The maximum retry period is 4 days.
- After 4 days, the notification process stops and no more retires are made