> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tappify.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Server API

> Every export of @tappify/extension-sdk/server, for the server your extension runs.

Your extension's server imports one entry:

```ts theme={null}
import { createTappifyHandler } from "@tappify/extension-sdk/server";
```

Each symbol's page below is generated from the SDK's own TypeScript declarations.

## The handler

| Symbol                                                                                      | Is                                                                                                                                                        |
| ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`createTappifyHandler`](/extensions/reference/server-api/Function.createTappifyHandler)    | Builds a `(Request) => Promise<Response>` from your handlers                                                                                              |
| [`TappifyHandlerOptions`](/extensions/reference/server-api/Interface.TappifyHandlerOptions) | The options: `extensionId`, `health`, `metrics`, `tools`, `mentions`, `actions`, `procedures`, `context`, `events`, `work`, `basePath`, `jwksUrl`, `jwks` |
| [`TappifyFetchHandler`](/extensions/reference/server-api/TypeAlias.TappifyFetchHandler)     | The handler's own type                                                                                                                                    |
| [`TappifyRouteHandler`](/extensions/reference/server-api/TypeAlias.TappifyRouteHandler)     | The signature every route handler has                                                                                                                     |

Six of those options have a guide of their own:

| Handler    | Guide                                                            |
| ---------- | ---------------------------------------------------------------- |
| `metrics`  | [Add a connector](/extensions/build/add-a-connector)             |
| `actions`  | [Add actions](/extensions/build/add-actions)                     |
| `tools`    | [Add assistant tools](/extensions/build/add-assistant-tools)     |
| `mentions` | [Add assistant tools](/extensions/build/add-assistant-tools)     |
| `context`  | [Add context providers](/extensions/build/add-context-providers) |
| `events`   | [Events](/extensions/reference/events)                           |

## The four assistant routes

| Route                           | Handler    | Tappify sends                                                         | You answer with                                                                                          |
| ------------------------------- | ---------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `POST /tappify/tools/<id>`      | `tools`    | The full call body, with the assistant's arguments as `input`         | The keys your tool's `returns` promises                                                                  |
| `POST /tappify/actions/<id>`    | `actions`  | The full call body, once the owner has approved                       | Anything; a 2xx marks the run succeeded and stores it                                                    |
| `GET /tappify/mentions/<id>?q=` | `mentions` | `input.q`, the text the owner has typed                               | [`MentionItems`](/extensions/reference/server-api/Interface.MentionItems) — `{ items: [{ id, label }] }` |
| `GET /tappify/context/<id>`     | `context`  | Nothing; a GET carries no body, so no input, credentials or documents | [`ContextBlock`](/extensions/reference/server-api/Interface.ContextBlock) — `{ summary, data? }`         |

A tool has 30 seconds to answer and 1 MB to answer with, and is never retried. Tappify keeps the
first 20 mention items and cuts each label to 80 characters; a context block is capped at 2 KB
once rendered. An answer that does not match the shape above comes back to you as
`TOOL_RESPONSE_INVALID` or `MENTION_RESPONSE_INVALID`.

## What a handler receives

[`TappifyRequest`](/extensions/reference/server-api/Interface.TappifyRequest) carries
`install`, `context`, `input`, `credentials`, `documents`, `event`, `eventId`, `claims` and
the raw `request`. The pieces are
[`TappifyInstall`](/extensions/reference/server-api/Interface.TappifyInstall),
[`TappifyCallContext`](/extensions/reference/server-api/Interface.TappifyCallContext),
[`TappifyDocuments`](/extensions/reference/server-api/TypeAlias.TappifyDocuments) and
[`TappifyClaims`](/extensions/reference/server-api/Interface.TappifyClaims). A call made from a
filtered surface carries the owner's
[`TapFilters`](/extensions/reference/server-api/Interface.TapFilters).

## Route payloads

[`TappifyHealth`](/extensions/reference/server-api/Interface.TappifyHealth),
[`MetricsInput`](/extensions/reference/server-api/Interface.MetricsInput),
[`MetricsSeries`](/extensions/reference/server-api/Interface.MetricsSeries),
[`MetricsResponse`](/extensions/reference/server-api/Interface.MetricsResponse),
[`MentionItems`](/extensions/reference/server-api/Interface.MentionItems),
[`ContextBlock`](/extensions/reference/server-api/Interface.ContextBlock),
[`WorkOperation`](/extensions/reference/server-api/TypeAlias.WorkOperation).

## The names your manifest declares

`tappify extension types` narrows these from your manifest, so a handler for a name you did not
declare does not compile:
[`ActionId`](/extensions/reference/server-api/TypeAlias.ActionId),
[`ActionInput`](/extensions/reference/server-api/TypeAlias.ActionInput),
[`ToolId`](/extensions/reference/server-api/TypeAlias.ToolId),
[`ToolInput`](/extensions/reference/server-api/TypeAlias.ToolInput),
[`WebhookName`](/extensions/reference/server-api/TypeAlias.WebhookName),
[`WebhookPayload`](/extensions/reference/server-api/TypeAlias.WebhookPayload),
[`TapHostEvents`](/extensions/reference/server-api/TypeAlias.TapHostEvents),
[`TapSettingsValues`](/extensions/reference/server-api/TypeAlias.TapSettingsValues),
[`TapCredentialValues`](/extensions/reference/server-api/TypeAlias.TapCredentialValues).

## Tokens

| Symbol                                                                                | Is                                                               |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| [`verifyTappifyToken`](/extensions/reference/server-api/Function.verifyTappifyToken)  | Verifies an install token against Tappify's JWKS                 |
| [`VerifyTokenOptions`](/extensions/reference/server-api/Interface.VerifyTokenOptions) | `extensionId`, and a `jwksUrl` or a `jwks`                       |
| [`DEFAULT_JWKS_URL`](/extensions/reference/server-api/Variable.DEFAULT_JWKS_URL)      | `https://api.tappify.ai/api/v1/extensions/.well-known/jwks.json` |

`createTappifyHandler` verifies for you. Call these directly only outside it.

## Sending events

| Symbol                                                                            | Is                                                               |
| --------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| [`sendEvent`](/extensions/reference/server-api/Function.sendEvent)                | Posts one of your declared webhook events to Tappify             |
| [`signWebhook`](/extensions/reference/server-api/Function.signWebhook)            | The HMAC signature over a raw body                               |
| [`WebhookEnvelope`](/extensions/reference/server-api/Interface.WebhookEnvelope)   | `event`, `source`, `occurredAt`, `build`, `dedupeKey`, `payload` |
| [`SendEventOptions`](/extensions/reference/server-api/Interface.SendEventOptions) | Where to send it and which secret to sign with                   |

What each delivery becomes is on
[Raise alerts, banners, and markers](/extensions/build/alerts-banners-markers).

## Adapters

[`toExpress`](/extensions/reference/server-api/Function.toExpress) returns
[`ExpressMiddleware`](/extensions/reference/server-api/TypeAlias.ExpressMiddleware) over an
[`ExpressLikeRequest`](/extensions/reference/server-api/Interface.ExpressLikeRequest) and an
[`ExpressLikeResponse`](/extensions/reference/server-api/Interface.ExpressLikeResponse);
[`toNode`](/extensions/reference/server-api/Function.toNode) returns a
[`NodeRequestListener`](/extensions/reference/server-api/TypeAlias.NodeRequestListener), which
reads the body as a [`BodyStream`](/extensions/reference/server-api/Interface.BodyStream).
Cloudflare Workers and Vercel take the handler as it is — see
[Deploy your server](/extensions/build/deploy-your-server).

## Errors

[`TapServerError`](/extensions/reference/server-api/Class.TapServerError) is what you throw. The
code is stable and the message reaches the owner's screen; the ones the SDK itself raises are
[`SERVER_ERROR_CODES`](/extensions/reference/server-api/Variable.SERVER_ERROR_CODES), typed as
[`TapServerErrorCode`](/extensions/reference/server-api/TypeAlias.TapServerErrorCode). Every code
Tappify itself returns is on [Errors](/extensions/reference/errors).
