> ## Documentation Index
> Fetch the complete documentation index at: https://relay-demo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Node SDK

> Send events and verify webhooks from Node.js 18 or later.

```bash theme={null}
npm install relay-sdk
```

```js theme={null}
import { Relay } from "relay-sdk";

const relay = new Relay(process.env.RELAY_API_KEY);
```

## Send an event

```js theme={null}
const event = await relay.events.send(
  { type: "invoice.paid", data: { invoice_id: "inv_123", amount: 4900 } },
  { idempotencyKey: "invoice-inv_123-paid" }
);
console.log(event.id); // evt_2Lk9xQ
```

Send up to 100 at once with `relay.events.sendBatch([...])`.

## Verify a webhook

`verify` checks the signature and the timestamp, then returns the parsed event. It throws `RelaySignatureError` if either check fails. Pass the raw body as a `Buffer` or string, not parsed JSON.

```js theme={null}
const event = relay.webhooks.verify(rawBody, signatureHeader, process.env.RELAY_WEBHOOK_SECRET);
```

## Endpoints

```js theme={null}
const endpoint = await relay.endpoints.create({
  url: "https://yourapp.example/webhooks",
  events: ["invoice.*", "customer.created"],
});
console.log(endpoint.secret); // whsec_..., shown once
```

## Retries and errors

The client retries `429` and `5xx` responses and network errors up to 3 times with backoff, reusing the same idempotency key. Change it with `new Relay(key, { maxRetries: 0 })`.

| Error | When |
| - | - |
| `RelayAuthenticationError` | The key is missing, wrong or revoked (`401`). |
| `RelayRateLimitError` | Still rate limited after retrying (`429`). Has `retryAfter` in seconds. |
| `RelayInvalidRequestError` | The request is malformed (`400`) or conflicts with an idempotency key (`409`). |
| `RelayAPIError` | Anything else. Has `status` and `requestId`. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.