Skip to content

Receive Slack events

A complete inbound walkthrough: take Slack Events API deliveries, verify the signing-secret HMAC, and fan them out to your API and a queue — while Emithook auto-answers Slack's url_verification handshake so setup never fails.

What you'll build

Slack  ──▶  <ingest-domain>/slack-app/events  ──▶  ├─ HTTPS  https://api.acme.in/slack
       (acked + buffered <100ms; signature verified in processing)  └─ SQS    acme-slack-q

1. Create the endpoint

Use the Slack preset — it configures the signing-secret HMAC check and auto-answers the one-time url_verification challenge Slack sends when you save the Request URL.

bash
curl -X POST https://api.emithook.com/v1/endpoints \
  -H "Authorization: Bearer $EK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://wh.emhk.in/acme/slack-app/events",
    "preset": "slack",
    "destinations": ["dst_acme_https", "dst_acme_sqs"]
  }'
json
// → 201 Created
{
  "id": "ep_01JX9...",
  "url": "https://<ingest-domain>/slack-app/events",
  "verification": "slack",
  "status": "active"
}

TIP

The URL is live immediately on the shared ingest domain (<ingest-domain>, config-driven) — no DNS. Paste it as the Request URL under Event Subscriptions in your Slack app config.

2. Add the signing secret

Copy your app's Signing Secret from Slack app → Basic Information → App Credentials so Emithook can verify the X-Slack-Signature header:

bash
curl -X PUT https://api.emithook.com/v1/endpoints/ep_01JX9.../secret \
  -H "Authorization: Bearer $EK_KEY" \
  -d '{ "secret": "your-slack-signing-secret" }'

Slack signs v0:<X-Slack-Request-Timestamp>:<raw-body> with HMAC-SHA256 (hex) and sends it as X-Slack-Signature: v0=<hex>. Emithook recomputes it over the raw body and enforces a 5-minute replay window on the timestamp. The edge accepts and durably buffers every request in <100 ms (never dropped); verification then runs in the processing plane. A request that fails verification is quarantined — durable and inspectable, but never delivered (not a 401 at the edge, never silently dropped).

The url_verification handshake

When you first save the Request URL, Slack POSTs a { "type": "url_verification", "challenge": "<token>" } body and expects the challenge echoed back synchronously. The Slack preset answers this at the edge for you — you never write handshake code, and the URL verifies on the first try.

3. What an incoming request looks like

http
POST /slack-app/events HTTP/1.1
Host: <ingest-domain>
X-Slack-Request-Timestamp: 1720099471
X-Slack-Signature: v0=8f2a1c...
Content-Type: application/json

{ "type": "event_callback", "event": { "type": "app_mention", "text": "hi <@U0BOT>" } }
http
HTTP/1.1 200 OK
{ "received": true }

Emithook acks in under 100 ms, then fans the event out to both destinations independently — each signed, retried, and logged on its own.

4. Confirm delivery

bash
emithook logs tail --endpoint /slack-app/events
12:04:31  evt_01JX… app_mention → dst_acme_https   200  142ms  ✓
12:04:31  evt_01JX… app_mention → dst_acme_sqs      enqueued    ✓

If api.acme.in is down, Emithook retries with backoff and parks events behind the circuit breaker — when it recovers, they drain automatically. Nothing is lost.

5. Replay if needed

bash
# replay everything that dead-lettered for this endpoint
emithook replay --dlq --endpoint /slack-app/events

See also

Emithook · a Finnoto product