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

# TypeScript SDK

> Install the TypeScript SDK, send messages with full type safety, paginate, handle typed errors, and verify webhooks.

The TypeScript SDK ships full type definitions for every endpoint, request payload, and response object, so your editor catches mistakes before they hit production. It runs in Node.js 18+ and any modern bundler-based environment.

This page covers installing `@surgeapi/node`, sending your first request, paginating list endpoints, narrowing typed errors, and verifying webhook signatures in your handler.

## Install and authenticate

```bash theme={null}
npm install @surgeapi/node
```

Set your API key as an environment variable:

```bash theme={null}
export SURGE_API_KEY=sk_live_your_key_here
```

```typescript theme={null}
import Surge from "@surgeapi/node";

const surge = new Surge();
```

## Your first request

```typescript theme={null}
const message = await surge.messages.create("acct_01jrzhe8d9enptypyx360pcmxj", {
  to: "+18015551234",
  body: "Your appointment is confirmed for Friday at 2pm.",
});

console.log(message.id); // msg_01j...
```

## Type imports

Every resource and parameter has a corresponding TypeScript type:

```typescript theme={null}
import type { Message, MessageCreateParams } from "@surgeapi/node";

const params: MessageCreateParams = {
  to: "+18015551234",
  body: "Hello",
};

const message: Message = await surge.messages.create("acct_01j...", params);
```

## Pagination

The SDK returns auto-paginating iterators using async iteration:

```typescript theme={null}
// Iterates through all messages
for await (const message of surge.messages.list("acct_01j...")) {
  console.log(message.id);
}
```

Page manually when you need cursor control:

```typescript theme={null}
const page = await surge.messages.list("acct_01j...", { limit: 25 });

console.log(page.data);
console.log(page.pagination.next_cursor);
```

## Retries and timeouts

The SDK retries transient failures automatically. Configure on the client:

```typescript theme={null}
const surge = new Surge({
  maxRetries: 5,
  timeout: 30_000, // milliseconds
});
```

## Error handling

Errors are typed exceptions:

```typescript theme={null}
import { APIError, AuthenticationError } from "@surgeapi/node";

try {
  await surge.messages.create("acct_01j...", { to: "+18015551234", body: "Hello" });
} catch (error) {
  if (error instanceof APIError) {
    console.log(error.status);                  // e.g. 422
    console.log(error.error.error.type);        // e.g. "opted_out"
    console.log(error.error.error.message);
  }
}
```

## Webhooks

Use the SDK's built-in webhook helper to verify signatures and parse events:

```typescript theme={null}
// Express example:
const surge = new Surge({ webhookSigningSecret: process.env.SURGE_WEBHOOK_SECRET });

app.post("/webhooks/surge", express.raw({ type: "application/json" }), (req, res) => {
  let event;
  try {
    event = surge.webhooks.unwrap(req.body.toString(), { headers: req.headers });
  } catch {
    return res.status(400).end();
  }

  switch (event.type) {
    case "message.received":
      handleInbound(event.data);
      break;
    case "contact.opted_out":
      handleOptOut(event.data);
      break;
  }

  res.status(200).end();
});
```

<Warning>
  Pass the raw request body (string) to `surge.webhooks.unwrap`, not the parsed JSON. Signature verification requires the exact byte sequence that was signed. Use `express.raw()` or your framework's equivalent. The webhook secret is passed to the `Surge` client constructor as `webhookSigningSecret`, or it can be passed per-call as the `key` option.
</Warning>
