Skip to main content
Photon normalizes events from its supported messaging channels and sends subscribed events to the App’s registered Event webhook URL. You do not need a separate Slack, email, or iMessage webhook receiver for this Photon integration.

Verify before parsing or processing

Photon uses Standard Webhooks headers:
  • webhook-id
  • webhook-timestamp
  • webhook-signature
Use the registered App’s whsec_… signing secret with a maintained verifier. Preserve the original request bytes. Do not put a JSON-parsing middleware before signature verification or verify JSON.stringify(parsedBody).
The verifier checks the signature and timestamp freshness. Signature verification authenticates the payload; it does not validate its business schema or grant access to your product’s customer account. Keep the server clock synchronized and preserve the library’s freshness check.

Route by installation

App deliveries include app_installation_id. Message events also include the organization and project under data, and the public message under data.object. A simplified envelope looks like this (additional event fields are omitted):
After verification, look up the installation in your backend and check that data.organizationId matches the organization bound to that installation. Check the message’s project ID agrees with the envelope. Resolve your own customer account from this stored association. Never select a customer using a query parameter, an unverified request body, or a global “current installation.” Events can arrive while installation setup is finishing. A production receiver should durably quarantine valid deliveries for installations whose binding is still pending and resolve them before processing. Do not forward them to an arbitrary default customer.

Acknowledge, deduplicate, and retry

Use (app_installation_id, event.id) as a persistent deduplication key. Return 2xx after durable acceptance; process slower business work asynchronously. Make the deduplication record and enqueue operation atomic so a crash cannot mark an unqueued event as complete. Expect retries and out-of-order delivery. Repeated delivery of one event must not cause repeated side effects, but different event IDs can describe successive states of the same message. Do not assume every failure can be safely retried: distinguish known rejection from an unknown outcome of an external operation. For transport-level delivery behavior, see Webhook delivery. App delivery targets are managed by Photon from App subscriptions and installations; do not create a second ordinary project webhook just to receive App events.

Send a reply through the API

Returning text in the webhook response does not send a message. To reply: The current message-creation API requires project:write; the destination project must also be in the installation’s scope. Resolve the sender and conversation from a validated incoming message or the corresponding Photon API; do not use arbitrary browser-supplied identifiers without checking tenant ownership.
Reuse the same idempotency key when retrying the same intended reply. A successful API response is not proof of final delivery; consume the subscribed message-status events to display delivery progress. No automatic reply loop is required. See Send a Message for the complete request and channel-specific requirements.