GitHub webhooks

Connect a repository's webhooks to DataMind Oda so that an event can start work by itself: a verified delivery reaches your rules, and a rule can open a chat in a workspace, with the delivery recorded on the chat's first message. This page covers the endpoint you connect, the contract a GitHub delivery must satisfy, the answers GitHub sees, and what Oda does and does not guarantee. The step-by-step setup is on GitHub webhooks, and what a delivery creates is on Webhook sessions.

How a delivery starts work

Connect the endpoint

Set up the endpoint with these fields. Every one of them is required.

FieldWhat it is
sourceA name for this endpoint, for example primary-github. Each verified delivery carries it to the rules.
pathThe endpoint's exact path, for example /github. It starts with /, is not / alone, and carries no trailing slash, query or fragment.
secretEnvThe reference to the stored secret that Oda verifies deliveries with. The secret itself is not written here.
maxBodyBytesThe largest raw request body Oda accepts, as a positive whole number.

A value that fails its check refuses the endpoint before it registers, with messages such as webhook-github source must be a non-empty trimmed string or webhook-github path must be an absolute non-root pathname without a trailing slash, query, or fragment.

By default the endpoint shares the address that serves the Oda interface. A deployment can give it a listener of its own on a local address instead, behind a TLS reverse proxy or tunnel. The endpoint adds no encryption of its own, so keep it local and give GitHub the public address the proxy serves.

What GitHub must send

What GitHub sees back

The 202 answer means only that the verified delivery was taken and dispatched in memory. It comes before the rules run, and it does not say that a rule matched or that a chat was created. The other answers:

StatusWhat GitHub receivesWhen Oda returns it
202An empty bodyThe delivery was verified and dispatched in memory.
400missing <name> header, invalid Content-Length, request body was aborted, request body is not valid UTF-8, request body is not valid JSON, GitHub webhook payload must be a JSON object, GitHub webhook payload is not lossless JSONA required header, the declared length, the body or the payload failed its checks.
401invalid webhook signatureThe signature does not match the secret.
405method not allowed, with the header allow: POSTThe request is not a POST.
413request body is too largeThe declared or streamed body exceeds maxBodyBytes.
415content type must be application/jsonThe media type is not application/json.
503GitHub webhook secret is unavailable, webhook runtime is unavailable, webhook ingress is unavailableThe secret does not resolve, the part of Oda that takes deliveries is unavailable, or the request could not be handled.

Limits to plan around

When a delivery or a request is refused

Before a rule runs, the delivery itself is checked. A delivery must carry a non-empty kind, source and id (webhook delivery kind must be a non-empty string, webhook delivery source must be a non-empty string, webhook delivery id must be a non-empty string), a non-negative whole-number receipt time (webhook delivery receivedAt must be a non-negative safe integer), and a lossless JSON payload (webhook delivery must be lossless JSON). Nothing runs when a check fails.

A rule must return nothing or a single request: webhook rule result must be null or a Session request object.

A request for a chat has its own checks. Every text value must be non-empty (webhook Session request <field> must be a non-empty string), the folder must be an absolute path (webhook Session request workspacePath must be absolute, got "<path>"), and a model, when named, must be an object whose token cap, when set, is a positive whole number (webhook Session request model must be an object, webhook Session request model.maxTokens must be a positive safe integer). A request that fails is refused before anything is created.

When a webhook message enters a chat, Oda checks that the chat's recorded folder matches exactly one workspace. The check fails with webhook Session "<id>" has no cwd, webhook Session "<id>" belongs to <n> Workspaces at prompt admission, or webhook Session "<id>" cwd <cwd> differs from its Workspace path.

What the log records

Each rule run records one line naming its provider, source, delivery and rule, in the shape webhook: provider=... source=... delivery=... rule=.... A rule that fails adds the reason after failed:; a run stopped because the handling shut down is noted after stopped after disposal:. A failed rollback adds a warning of its own. The log never contains the secret, the signature or the payload.

Questions, answered

How do I trace one delivery through Oda?

Start from the delivery id. The log line for each rule run carries it, so you can see which rules saw the delivery. If a rule opened a chat, the chat's identifier starts with webhook-, and its first message is a webhook notice recording the same provider, source, delivery and rule.

In what order does the endpoint check a delivery?

Method, media type, body, headers, secret, signature, then JSON: the endpoint works through a request in that order, and the signature is verified over the raw body before anything is parsed. A delivery that fails the signature check never has its payload read.

Does Oda retry a delivery that failed or arrived while Oda was offline?

No. Nothing queues, replays or retries a delivery: one that was refused or lost is not picked up again later, and a rule call that had not yet reached a prompt when Oda stopped is lost. Check that the work happened instead of counting on a retry.

Why was a delivery refused before any rule ran?

The delivery itself is checked first: its kind, source and id must be non-empty, its receipt time must be a non-negative whole number, and its payload must be lossless JSON. A delivery that fails one of these checks is refused with the message that names the check, and nothing runs.

What makes a rule's chat request valid?

Every text value it carries must be non-empty, the folder must be an absolute path, and a model, when named, must be an object whose token cap, when set, is a positive whole number. Oda validates all of this before anything is changed; a request that fails is refused and leaves nothing behind.

How does the endpoint find the webhook secret?

The endpoint's secretEnv setting holds a reference, not the secret. Oda resolves that reference against its stored credentials for every request, so rotating the stored secret takes effect on the next delivery, and the raw secret never sits in the endpoint's settings. Stored credentials covers where credentials live.

Do the logs contain the delivery's payload?

No. The log records the provider, source, delivery and rule for each run, and a failure adds the reason, but the secret, the signature and the payload are never logged.

Can the endpoint run on a separate listener?

Yes. It can run as a listener of its own on a local address while the Oda interface keeps its usual address; put a TLS reverse proxy or tunnel in front, and the endpoint itself stays without encryption.

Which GitHub events can start work?

Whatever events your repository sends. The endpoint hands every verified delivery to the rules with the event's name, such as pull_request, and its payload; which events a rule acts on, and what the fields of an event must contain, is the rule's choice. The endpoint guarantees only that the delivery is authenticated and that its payload is a lossless JSON object.

What happens if a chat attempt fails partway?

Before the prompt is accepted, nothing of the chat remains: a chat that was already attached is detached and disposed, and a folder registered during the attempt can stay registered, because another caller may already use it. The rollbacks are best effort, and a failed rollback is logged.