Skip to content
useEventStack 0.3.0 is live.Read the quickstart

Integrate

Connect a provider to a project, then receive its events

Adapters belong to a single project, are managed with a signed-in session, and verify each provider's own signature on the inbound route.

Prerequisites

  • A verified signed-in user with access to the organization
  • An owner, admin, or developer role to create and test adapters
  • An active project — the adapter is pinned to it, and every event the adapter ingests is written there
  • A registered event contract for the adapter’s configured event type, in that same project
  • The provider payload and secret or public key expected by the selected adapter

Working flow

1. Manage the adapter through the user session

Use Dashboard → Integrations. List and create calls are project-scoped management requests:

GET  /organizations/{organization_id}/integrations
POST /organizations/{organization_id}/integrations

Both read the x-useeventstack-project header. An adapter created while a project is active belongs to that project: it is invisible to sibling projects, and two projects in the same organization can each connect the same provider independently.

These routes use the browser session. Unsafe management requests also require the session-bound CSRF header. Event-ingestion API keys do not authorize adapter management.

2. Send the provider request to the inbound route

POST /integrations/{adapter_id}/webhook

This is an inbound adapter endpoint, not a session-management endpoint. Its body is provider-specific, and the adapter id plus the provider’s signature is the credential — no session cookie or API key is involved. The resulting event is written into the adapter’s project.

3. Use management operations from the signed-in dashboard

RouteCurrent purpose
POST /integrations/:adapter_id/testReturn inbound readiness or make the configured outbound test call
GET /integrations/health?organization_id=:idList organization integration-health records
POST /integrations/:adapter_id/replay/:event_idReprocess a recorded succeeded or failed inbound diagnostic event
POST /integrations/:adapter_id/retry/:event_idRepeat one recorded outbound delivery from its diagnostic event

Test, replay, and retry require a signed-in owner, admin, or developer whose active project is the adapter’s project. Calling them from a sibling project returns 404. Health reads also allow viewers in the organization.

Signature verification

There is no single shared signature format. Each provider gets the check it actually specifies.

ProviderCredentialWhat is verified
githubsecret on the adapterHMAC-SHA256 in x-hub-signature-256 over the raw body
discordconfig.public_key on the adapterEd25519 in x-signature-ed25519 over x-signature-timestamp concatenated with the raw body
any other providersecret on the adapterx-useeventstack-secret compared against the stored hash

A Discord adapter needs the application’s public key from the Discord developer portal. The public key is not a secret, so it is stored in the adapter config rather than as a shared secret:

POST /organizations/{organization_id}/integrations
{
  "provider": "discord",
  "direction": "inbound",
  "event_type": "discord.interaction_received",
  "config": { "public_key": "<64 hex characters from the Discord portal>" }
}

Discord validates an endpoint by sending a signed {"type": 1} PING and by sending deliberately invalid signatures. The inbound route verifies the signature before it answers, so a correctly signed PING returns {"type": 1} and an unsigned, forged, or tampered request returns 401. An adapter with no public_key rejects every request rather than accepting unverified traffic.

Expected response

When an inbound adapter accepts and processes a payload, it returns:

{
  "event": { "id": "…", "type": "configured.event_type", "payload": {} },
  "adapter_id": "…",
  "published": true
}

The test route returns a status object. Inbound adapters report ready; outbound tests report success, failed, or error with the fields produced by that operation.

Failure diagnosis

  • 401 on inbound: check the signature against the exact raw request body. Re-serialising the JSON before signing changes the bytes and invalidates the signature.
  • 401 on a Discord adapter: confirm config.public_key is the application public key as 64 hex characters, and that the timestamp header is sent alongside the signature.
  • Invalid webhook JSON: send a JSON request body accepted by the provider adapter.
  • Contract error: register the adapter event type and matching version in the adapter’s project.
  • 404 on test, replay, or retry: switch to the project that owns the adapter.
  • Management 403: use a signed-in organization member with the required role and a valid CSRF token for unsafe requests.
  • Replay rejected: use a recorded webhook.delivery.succeeded or webhook.delivery.failed diagnostic event from that adapter.
  • Retry rejected: use an outbound diagnostic event and confirm the adapter still has its outbound destination.

Adapter behavior is provider-specific

Adapter behavior is specific, not universal

The current routes do not define one shared inbound envelope, an automatic retry schedule, or a general customer-facing outbound delivery contract. Validate the exact adapter and provider flow you configure.

Next step

Register the adapter’s runtime payload in Event contracts, then use Dashboard integrations to configure and test the adapter.