# Build Channels with the SDK

> Author Channel protocols and Auth Providers that normalize communication without claiming platform authority.

Use `authProvider()` to verify ingress and `channel()` to translate a protocol into canonical events.

## Verify the caller {#verify-caller}

```ts
import { authProvider } from "@constal/sdk";

export default authProvider({
  id: "signed-webhook", version: "1.0.0",
  needs: [{ binding: "verifier", kind: "service", ops: ["verify"] }],
  async authenticate({ request }, context) {
    const proof = await context.invoke<{ valid: boolean; subject?: string }>(
      context.resources.verifier!, "verify", { headers: request.headers, bodyBase64: request.bodyBase64 },
    );
    return proof.valid && proof.subject
      ? { authenticated: true, subject: proof.subject }
      : { authenticated: false, reason: "invalid signature" };
  },
});
```

## Normalize the protocol {#normalize-protocol}

```ts
import { authProviderName, channel, resourceName } from "@constal/sdk";

export default channel({
  id: "webhook", version: "1.0.0", public: true,
  authProvider: authProviderName("crn:constal:production:acme:default:auth-provider/signed-webhook"),
  target: resourceName({ environment: "production", tenant: "acme", namespace: "default", kind: "agent", path: "support" }),
  protocol: {
    id: "json-webhook", version: "1",
    receive(request) {
      const body = JSON.parse(atob(request.bodyBase64 ?? ""));
      return { id: body.id, type: "message", session: body.session, data: body.message };
    },
    respond(result) {
      return { status: result.status === "failed" ? 500 : 200,
        headers: { "content-type": "application/json" }, bodyBase64: btoa(JSON.stringify(result)) };
    },
  },
});
```

Auth Provider output is evidence, not platform authority. Central authentication assigns tenant and customer identity before `receive`. Both contexts expose declared Resources through governed `invoke()` and never expose Credential bytes. See [Deploy a Channel](/docs/channels/deploy.md) and [Deploy an Auth Provider](/docs/channels/auth-providers/deploy.md).

Keep event and delivery ids stable so retries resolve to recorded outcomes. Optional `send` and `alarm` handlers use the same declared Channel context for outbound delivery and scheduled work. Register analytics definitions on the Channel before emitting them.
