Skip to main content
Dynamo CSMS sends webhook events to URLs you register whenever something significant happens — a session starts, a charge point goes offline, or commissioning completes. This guide shows you how to set up endpoints, verify incoming payloads, and troubleshoot failed deliveries.

Register a webhook endpoint

Create an endpoint by providing the URL that should receive events, the list of event types you want to subscribe to, and a secret used to sign payloads.
curl -X POST https://api.dynamo-csms.com/api/v1/webhooks/endpoints \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/dynamo",
    "events": [
      "charge_point.connected",
      "charge_point.disconnected",
      "session.started",
      "session.ended",
      "alert.triggered",
      "commissioning.completed"
    ],
    "secret": "whsec_your_random_secret_here",
    "description": "Production event receiver"
  }'
Response:
{
  "id": "whe_01HXUVWXYZ12345678",
  "url": "https://your-app.example.com/webhooks/dynamo",
  "events": [
    "charge_point.connected",
    "charge_point.disconnected",
    "session.started",
    "session.ended",
    "alert.triggered",
    "commissioning.completed"
  ],
  "status": "active",
  "created_at": "2026-05-01T11:00:00Z"
}
Generate your secret using a cryptographically secure random generator (e.g., openssl rand -hex 32). Store it securely — you’ll need it to verify every incoming payload.

Available event types

EventFired when
charge_point.connectedA charge point establishes an OCPP connection
charge_point.disconnectedA charge point loses its OCPP connection
charge_point.faultA charge point reports a fault or error code
session.startedA driver begins a charging session
session.endedA charging session completes
session.authorizedAn RFID or app authorization is granted
alert.triggeredAn alert rule threshold is exceeded
commissioning.completedA charge point commissioning check finishes
commissioning.failedA commissioning check fails
billing.invoice_readyA monthly invoice has been generated

Webhook payload format

Every event payload shares a common envelope with an event type, a unique id, a timestamp, and an object containing the relevant data. Example session.started payload:
{
  "id": "evt_01HXABCDEF12345678",
  "event": "session.started",
  "created_at": "2026-05-01T08:12:05Z",
  "api_version": "2026-05-01",
  "object": {
    "id": "ses_01HXGHIJKL23456789",
    "charge_point_id": "cp_01HX5P2QRSTUVWXYZ0",
    "connector_id": 1,
    "driver_id": "drv_01HXDEFGH123456789",
    "authorization_method": "rfid",
    "started_at": "2026-05-01T08:12:00Z",
    "tariff_id": "tar_01HX8ABCDE12345678",
    "site_id": "site_01HXMNOPQR34567890"
  }
}

Verify webhook signatures

Dynamo signs every request with an HMAC-SHA256 signature derived from the raw request body and your endpoint secret. Always verify the signature before processing a payload. The signature is sent in the X-Dynamo-Signature header as sha256=<hex_digest>.
const crypto = require('crypto');

function verifySignature(rawBody, signatureHeader, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  const headerBuf = Buffer.from(signatureHeader);
  const expectedBuf = Buffer.from(expected);

  if (headerBuf.length !== expectedBuf.length) return false;
  return crypto.timingSafeEqual(headerBuf, expectedBuf);
}

// Express example
app.post('/webhooks/dynamo', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-dynamo-signature'];
  if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  console.log('Received event:', event.event);
  res.sendStatus(200);
});
Always read the raw request body bytes before parsing JSON. Many frameworks reformat the body during parsing, which will cause signature verification to fail.

Retry behaviour

If your endpoint returns a non-2xx HTTP status code or times out (30 second limit), Dynamo retries the delivery with exponential backoff:
AttemptDelay
1st retry5 seconds
2nd retry30 seconds
3rd retry5 minutes
4th retry30 minutes
5th retry2 hours
After 5 failed attempts, the delivery is marked as failed and no further retries occur. You can manually replay failed deliveries from the dashboard or using the deliveries API.

Manage endpoints

curl -X GET https://api.dynamo-csms.com/api/v1/webhooks/endpoints \
  -H "Authorization: Bearer YOUR_API_KEY"

View delivery history

Inspect past delivery attempts to debug failures or confirm events were received.
curl -X GET "https://api.dynamo-csms.com/api/v1/webhooks/endpoints/whe_01HXUVWXYZ12345678/deliveries?limit=10" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response:
{
  "deliveries": [
    {
      "id": "del_01HXSTUVWX45678901",
      "event_id": "evt_01HXABCDEF12345678",
      "event_type": "session.started",
      "status": "delivered",
      "http_status": 200,
      "attempts": 1,
      "last_attempted_at": "2026-05-01T08:12:06Z",
      "delivered_at": "2026-05-01T08:12:06Z"
    },
    {
      "id": "del_01HXYZ012345678901",
      "event_id": "evt_01HXIJKLMN98765432",
      "event_type": "alert.triggered",
      "status": "failed",
      "http_status": 503,
      "attempts": 5,
      "last_attempted_at": "2026-05-01T10:12:06Z",
      "delivered_at": null
    }
  ],
  "total": 2
}