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

# Receiving HTTP requests

> How to use webhooks handlers to receive HTTP requests from external services

Webhook Handlers enable apps to receive incoming requests from third-party services.
Unlike [server functions](/sdk/server/server-functions), which are used to send requests,
Webhook Handlers are designed to *listen* for and process external requests. They
can be used to sync data into Attio or respond with on-demand data to third-party
services, making them essential for integrating external systems and automating workflows.

## Example: Receiving prospect updated webhook from email sequencing API

You can use a webhook handler to receive a prospect updated event from the email sequencing API and update the corresponding record in Attio.

To add a webhook handler to your app;

* create a file with the `.webhook.ts` suffix.
* The file **must** be placed under the `src/webhooks` directory, and it must `export default` an async function.
* The function **must** take an HTTP [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) argument
  and **must** return an HTTP [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).

```typescript webhooks/prospect-updated.webhook.ts theme={"system"}
import {ATTIO_API_TOKEN} from "attio/server"

type WebhookBody = {
  event: "prospect_updated"
  data: {
    prospectId: string
    prospectName: string
    prospectEmail: string
  }
}

export default async function handleProspectUpdate(req: Request) {
  const body: WebhookBody = await req.json()

  const {prospectEmail, prospectName} = body.data

  // ℹ️ Assert endpoint will update Attio record details
  // or create a new record if it doesn't exist
  try {
    const response = await fetch("`/objects/people/records?matching_attributes=email_addresses", {
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${ATTIO_API_TOKEN}`,
      },
      body: JSON.stringify({
        data: {
          name: {
            full_name: prospectName,
          },
          email_addresses: [
            {
              email: prospectEmail,
            },
          ],
        },
      }),
    })

    if (!response.ok) {
      return new Response(null, {status: 500})
    }

    return new Response(null, {status: 200})
  } catch (error) {
    console.error(error)
    return new Response(null, {status: 500})
  }
}
```

This webhook handler calls the [Assert Record endpoint](/rest-api/endpoint-reference/records/assert-a-record) to create or update a record in Attio.

Whatever status code your handler returns will be passed back to the third-party service to indicate success or failure.
If your handler doesn’t return a `Response` object, the App SDK will respond with a 500 status code by default.

Defining a webhook handler isn’t enough to make it usable. You’ll need to enable it programmatically and register it with the third-party service.
You can do this from any server function, but most of the time you'll want to do it inside the [`connection-added` event](../server/events/connection-added).

The `connection-added` event runs whenever an Attio user connects to a third-party service through your app.
If your event handler completes without throwing an error, the connection will be saved.
If it throws, the user will be asked to authenticate again.

<Note>
  Be sure to test your `connection-added` events carefully. If something goes wrong, users won’t be
  able to connect to third-party services.
</Note>

Now back to our example. We are going to add `connection-added` event handler to our app.

* The file must live in `src/events/connection-added.event.ts`
* The file **must** `export default` an async function that takes a `{ connection: Connection }` argument.

```typescript events/connection-added.event.ts theme={"system"}
import type {Connection} from "attio/server"
import {createWebhookHandler, updateWebhookHandler} from "attio/server"

export default async function connectionAdded({connection}: {connection: Connection}) {
  // ℹ️ The filename must match the file in src/webhooks, but without the suffix
  const handler = await createWebhookHandler({fileName: "prospect-updated"})

  const authorizationToken = connection.value

  const response = await fetch("https://emailsequencingtool.com/api/v1/webhooks", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${authorizationToken}`,
    },
    body: JSON.stringify({
      name: handler.id,
      url: handler.url,
      event: "lead.processed",
    }),
  })

  if (!response.ok) {
    // ℹ️ Because we throw an error, the connection will not be saved
    // and user will be asked to authenticate again
    throw new Error(`Failed to register webhook: ${response.statusText}`)
  }

  const webhook = await response.json()

  // ℹ️ Save the external webhook ID so we
  // can delete it when the connection is removed
  await updateWebhookHandler(handler.id, {
    externalWebhookId: webhook.webhook_id,
  })
}
```

And that's it! now whenever a prospect update webhook is received, the `prospect-updated` webhook handler will be called.

<Tip>
  You can use the `externalWebhookId` to delete the webhook from the third-party service when the
  connection is removed inside the `connection-removed` event.
</Tip>
