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

# Webhooks

> Give another service a URL to call, and turn each of its calls into an event that starts your workflows.

Many services announce what happens on their side by calling a URL you give them: a payment succeeded, a pull request was merged, a form was sent. A webhook is that URL. Each call to it becomes an event in your project, and every workflow listening for that event starts a run with the call's body as its payload.

You don't write or host any code to receive the call. Nelkap receives it.

## Create a webhook

1. Go to Webhooks and create one in your project.
2. Choose the event it emits, like `checkout.completed`.
3. Copy its URL, and paste it in the other service's webhook settings.

The URL looks like `https://api.nelkap.com/webhooks/<secret>`. Then register a workflow that listens for the event:

```ts theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
nelkap.registerWorkflows([
  {
    name: 'fulfillOrder',
    handler: fulfillOrder,
    events: ['checkout.completed'],
  },
]);
```

```ts theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
export async function fulfillOrder(checkout: {
  id: string;
  customer_email: string;
}) {
  await nelkap.step.run('shipment', () =>
    createShipment(checkout.id),
  );

  await nelkap.step.run('confirmation', () =>
    sendConfirmation(checkout.customer_email),
  );
}
```

The payload is the call's JSON body, exactly as the service sent it. Type it after the service's own documentation.

## Accepted requests

Each call is a POST with a JSON body. Nelkap answers:

| Status | When |
| - | - |
| `200` | The event was emitted. The workflows listening for it start their runs. |
| `400` | The body isn't JSON, or it's nested more than 64 levels deep. |
| `402` | The workspace is no longer active. |
| `403` | The call came from an IP the webhook doesn't allow. |
| `404` | No enabled webhook has this URL. |
| `413` | The body is larger than your plan allows. |
| `429` | Your workspace got more requests in the same second than your plan allows. |

A webhook emits an event with no tags and no `wakeOn` key, so it starts runs but doesn't wake waiting ones. To wake a run from another service's call, receive the call in your app and [emit the event](https://docs.nelkap.com/triggers/events.md#wake-waiting-runs) yourself.

## Security

The secret in the URL is what proves a call is meant for your project, so treat the URL like a password:

* If it leaks, rotate the webhook's secret. The old URL stops working at once, so paste the new one in the other service right after.
* To accept calls only from the service's servers, set the webhook's allowed IPs: up to 20 addresses or ranges, like `203.0.113.7` or `203.0.113.0/24`, in IPv4 or IPv6.

Nelkap doesn't check the signatures some services add to their calls. When you need that check, receive the webhook in a route of your app, check the signature there, and emit the event with [`emit`](https://docs.nelkap.com/triggers/events#emit-an-event). The [order fulfillment example](https://docs.nelkap.com/examples/stripe-orders.md) does this for Stripe.

## Disable a webhook

Disable a webhook to stop it for a while without losing its URL. While it's disabled, its calls get a `404` and emit nothing. Enable it again, and the same URL works as before.

## Webhook history

Each webhook shows its event, its project, its URL, its allowed IPs, its status, and how many events it has emitted. The events themselves are listed with every other event, with the runs each one started. See [Events](https://docs.nelkap.com/triggers/events.md#event-history).

## Permissions

Everyone in the workspace can see webhooks. Creating, changing, and disabling them takes the Member role or above, and rotating a webhook's secret the Admin role. See [Members and roles](https://docs.nelkap.com/manage/members.md).

Your plan sets how many webhooks your workspace can have. See [Limits](https://docs.nelkap.com/limits.md#by-plan).


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