> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.etera.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.etera.dev/_mcp/server.

# Webhooks

## Overview

ETERA uses webhooks to notify your application of asynchronous events — payment confirmations, booking status changes, and voice call outcomes.

#### Payment Webhooks

Stripe payment lifecycle events

#### Voice AI Webhooks

Automated reservation call outcomes

#### Async Queue

AI Supervisor processing status

---

## Webhook Types

#### Payment

The Payment service receives Stripe webhook events for payment lifecycle updates.

| Endpoint           | Method | Description           |
| ------------------ | ------ | --------------------- |
| `/payment/webhook` | `POST` | Stripe event receiver |

Stripe events include payment intent confirmations, refund updates, subscription changes, and invoice payments. See the [Payment API reference](/platform) for the full schema.

### Verifying Stripe Signatures

```typescript
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

async function handleWebhook(req: Request) {
  const body = await req.text();
  const sig = req.headers.get("stripe-signature")!;

  const event = stripe.webhooks.constructEvent(
    body, sig, endpointSecret
  );

  switch (event.type) {
    case "payment_intent.succeeded":
      // Handle successful payment
      break;
    case "payment_intent.payment_failed":
      // Handle failed payment
      break;
  }
}
```

#### Voice AI

The Restaurant Booking service integrates with AI-powered voice platforms for automated phone reservations:

| Endpoint                                       | Method | Platform            |
| ---------------------------------------------- | ------ | ------------------- |
| `/restaurant/booking/vapi-reservation-outcome` | `POST` | Vapi voice AI       |
| `/restaurant/booking/ultravox/webhook`         | `POST` | Ultravox voice AI   |
| `/restaurant/booking/elevenlabs-call-outcome`  | `POST` | ElevenLabs voice AI |

### Handling Voice Call Outcomes

```typescript
async function handleVapiOutcome(req: Request) {
  const outcome = await req.json();

  // outcome includes: call status, duration, transcript,
  // reservation result (confirmed/denied/voicemail)

  if (outcome.status === "completed") {
    await updateBookingStatus(outcome.bookingId, outcome.result);
  }
}
```

#### Async Queue

Beyond webhooks, ETERA supports async processing through the AI Supervisor's queue system:

| Endpoint                          | Description                |
| --------------------------------- | -------------------------- |
| `POST /ai/input`                  | Submit an async AI request |
| `GET /ai/status/{conversationId}` | Poll processing status     |
| `GET /ai/queue/{conversationId}`  | Check queue position       |

The AI Supervisor also supports **WebSocket** connections at `/ai/input/ws` for real-time streaming updates instead of polling.

```typescript
// Submit async request
const res = await fetch("https://api.etera.dev/ai/input", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    inputType: "text",
    text: "Book a table for 4 at Nobu tonight",
  }),
});

const { conversationId } = await res.json();

// Poll for status
const status = await fetch(
  `https://api.etera.dev/ai/status/${conversationId}`,
  { headers: { Authorization: `Bearer ${token}` } }
).then((r) => r.json());
```

---

## Webhook Security

> **Warning**
>
> Always verify webhook signatures before processing events. For Stripe webhooks, use the `Stripe-Signature` header with your webhook signing secret.

---

## Best Practices

#### Return 200 quickly

Acknowledge the webhook before processing. Use a queue for heavy work to avoid timeouts.

#### Handle duplicates

Webhooks may be sent more than once. Use event IDs for idempotency to prevent duplicate processing.

#### Implement retry logic

If your endpoint returns a non-2xx status, the event will be retried with exponential backoff.

#### Log everything

Store raw webhook payloads for debugging and auditing. This is essential for troubleshooting payment issues.

---

## Next Steps

#### [Payment API](/platform)

Full Stripe webhook event schemas

#### [Restaurant Booking](/restaurant)

Voice webhook endpoint details

#### [AI Supervisor](/platform)

Async queue and WebSocket docs