POST requests to a URL you
control. Use webhooks for a backend that can accept public HTTPS requests. Use
WebSocket when your process needs to receive
events without a public HTTP endpoint.
These pages describe how Photon sends events to your application. A successful
webhook response does not mean a message reached its recipient.
Add a destination
1
Create an HTTPS receiver
Create a public HTTPS URL that accepts
POST requests. Keep the request
body unchanged so you can verify its signature. Photon does not follow
redirects. It also blocks private network destinations, including localhost.2
Choose the events to receive
In the dashboard, open your project’s
Webhooks page and select Add a destination. Set the URL, choose a
payload API version, and select the events your application handles.You can also create a destination through the API.
Supply an
Idempotency-Key with the request. Choose a
selectable API version.
Then choose events from that version’s
event catalog.
enabledEvents: ["*"] subscribes to all events; an empty array subscribes
to none. Keep the destination enabled to receive deliveries.3
Save the signing secret
Store the returned
whsec_... secret in your server’s secret manager, for
example as PHOTON_WEBHOOK_SECRET. It belongs to this destination and is
different from your Photon API key.Photon returns the secret when you create the destination or rotate its
secret. The API also returns it if you repeat that request with its original
Idempotency-Key. Reading a destination does not return its secret. Never
put the secret in browser code, source control, or logs.Verify with Standard Webhooks
We recommend the standardwebhooks package for JavaScript and TypeScript. It verifies Photon’s signatures without custom options and supports secret rotation. Other languages can use the Standard Webhooks libraries.Request. It verifies the request
and returns the parsed JSON body. Call it from your HTTP route before you process
the event.
400. Do not process the event.
The library checks the signature and rejects timestamps more than five minutes
in the past or future. Keep your server clock synchronized.
Verification confirms that Photon signed the request. It does not check the
event schema or prevent you from processing the same event twice. Use the
destination’s event catalog to interpret the body after verification.
Headers and payload
Each request hasContent-Type: application/json and these headers:
The signature is HMAC-SHA256 over
webhook-id.webhook-timestamp.rawBody, using
the Base64-decoded signing key. The library handles this format for you.
The body is the public event JSON for the selected API version. Photon does not
wrap it in another delivery object. Webhooks and WebSocket deliver the same
public event object for the same event and API version.
Handle duplicate deliveries
Save the verified event to storage that survives process restarts. Then return any2xx status. For ordinary event notifications, an empty 204 response is
enough. Queue slow work instead of keeping the request open.
Photon can deliver the same event more than once. For example, a lost response
can cause Photon to retry an event you already processed. Use webhook-id to
detect duplicates.
Save the event ID and its queued work in one atomic operation, such as a database
transaction. Both must succeed or fail together. This prevents a crash from
marking an event complete without saving its work. Return 2xx for a duplicate
you already accepted. If you cannot save the event temporarily, return 503 so
Photon can retry.
Retries and ordering
Photon increases retry delays and adds random variation to avoid simultaneous
retries. A valid
Retry-After on a retryable response can delay the next attempt,
within the retry limits.
The default limits are four days from the first failure and 20 failed attempts.
Delivery can stop earlier. Photon disables a destination when its delivery
failures reach a retry limit. Fix the receiver before you re-enable the destination.
Photon delivers events in order within each destination and event type. A
retrying event holds up later events of that type for that destination. Other
event types and destinations can continue independently. Do not assume that
events arrive in order across different event types or destinations.
Normal deliveries have a 20-second timeout by default. Events that request a
synchronous response have a two-second initial timeout by default. For those
events, return the response that the event’s contract requires before that
deadline. An HTTP response to a webhook is not a new chat message. Send chat
replies through the messaging API.
Rotate the secret
Rotate the signing secret and save the new value securely. During rotation, the old and new keys can be valid at the same time. Photon sends signatures for both in the same header.standardwebhooks accepts the signature that matches your configured secret.
Update your receiver to use the new secret before the old key expires.