# List webhook examples

`GET https://api.versionseven.ai/v1/webhooks/examples`

Three example [`prospect_response`](https://docs.versionseven.ai/api-reference/webhooks/prospect-response) deliveries: an email reply, a LinkedIn reply, and a reply on a campaign with both senders connected. Use them to build and test a receiver before pointing a live campaign at it.

- Required scope: `campaigns:read`

## Request

**cURL**

```bash
curl "https://api.versionseven.ai/v1/webhooks/examples" \
  -H "Authorization: Bearer $VICTORIA_API_KEY"
```

**Node.js**

```javascript
const response = await fetch("https://api.versionseven.ai/v1/webhooks/examples", {
  headers: {
    Authorization: `Bearer ${process.env.VICTORIA_API_KEY}`,
  },
});

const data = await response.json();
```

**Python**

```python
import os

import requests

response = requests.get(
    "https://api.versionseven.ai/v1/webhooks/examples",
    headers={
        "Authorization": f"Bearer {os.environ['VICTORIA_API_KEY']}",
    },
)
data = response.json()
```

## Headers

- `Authorization` (string, required): `Bearer` followed by a space and your API key, for example `Bearer vk_…`.

## Response

### `200`

```json
{
  "examples": [
    {
      "event": "prospect_response",
      "idempotency_key": "f3a1c9d2b8e7460a91d0a25f3e7b4c1d6f8a92e0b4c1d6f8a92e0b4c1d6f8a92",
      "sequence_lead_id": "550e8400-e29b-41d4-a716-446655440000",
      "timestamp": "2025-01-14T19:30:00.123456+00:00",
      "channel": "email",
      "sender": {
        "email": {
          "account_id": "xyz789-id",
          "platform_username": "jane@yourcompany.com",
          "email": "jane@yourcompany.com"
        },
        "linkedin": {
          "account_id": "abc123-id",
          "platform_username": "jane-smith-sdr"
        }
      },
      "lead": {
        "annual_revenue": 5000000,
        "company": "Example Corp",
        "custom_fields": {
          "product_interest": "Enterprise Plan",
          "region": "North America"
        },
        "email": "john.doe@example.com",
        "employee_count": 50,
        "first_name": "John",
        "industry": "Technology",
        "last_name": "Doe",
        "linkedin_profile": "https://linkedin.com/in/johndoe",
        "title": "VP of Sales",
        "website": "https://example.com"
      },
      "ai_response": {
        "agent_action": "reply",
        "agent_version": 2,
        "asset_delivered": true,
        "asset_url": "https://pages.example.com/p/abc123",
        "complete": false,
        "conversation_status": "awaiting_prospect",
        "escalation_reason": null,
        "first_message_mode": "asset",
        "goal": "Schedule a demo",
        "goal_status": "link_sent",
        "out_of_office": false,
        "responder_message": "Thank you for your interest! I'd be happy to schedule a demo for you.",
        "sdr_brief": "Prospect expressed interest, recommend scheduling demo within 24 hours.",
        "sentiment": "positive"
      },
      "campaign": "Q1 2024 Outbound Campaign",
      "conversation_owner": "victoria",
      "prospect_message": "Hi, I'm interested in learning more about your product.",
      "variation": "a"
    }
  ],
  "success": true
}
```

- `examples` (array of objects, required): Array of example webhook payloads
  - `event` (string, required, example `"prospect_response"`): Event type
  - `idempotency_key` (string, required, exactly 64 characters, example `"f3a1c9d2b8e7460a91d0a25f3e7b4c1d6f8a92e0b4c1d6f8a92e0b4c1d6f8a92"`): SHA-256 hex digest (64 characters) of the sequence lead, campaign, channel and prospect message. Identical on every redelivery of the same reply; a different reply from the same prospect gets a new key
  - `sequence_lead_id` (string · uuid, required, example `"550e8400-e29b-41d4-a716-446655440000"`): ID of the sequence lead this response relates to
  - `timestamp` (string, required, example `"2025-01-14T19:30:00.123456+00:00"`): When the delivery was built: ISO 8601, UTC, with a `+00:00` offset and microseconds
  - `channel` (string, required, example `"email"`): Communication channel: 'email' or 'linkedin'
  - `sender` (object, required): The accounts assigned to send to this lead, keyed by channel. A channel is left out when no account is assigned, and the object is empty when the accounts can't be looked up.
    - `email` (object or null, optional): Present when the lead has an email account assigned
      - `account_id` (string, required, example `"xyz789-id"`): ID of the connected email account that sent the outreach.
      - `platform_username` (string, required, example `"jane@yourcompany.com"`): Account username (typically the address)
      - `email` (string, required, example `"jane@yourcompany.com"`): Sender email address
    - `linkedin` (object or null, optional): Present when the lead has a LinkedIn account assigned
      - `account_id` (string, required, example `"abc123-id"`): ID of the connected LinkedIn account that sent the outreach.
      - `platform_username` (string, required, example `"jane-smith-sdr"`): LinkedIn username/handle
  - `lead` (object, required): The lead's details. A field the lead has no value for is `null`.
    - `annual_revenue` (integer or null, optional, example `5000000`)
    - `company` (string or null, optional, example `"Example Corp"`)
    - `custom_fields` (object, optional)
    - `email` (string or null, optional, example `"john.doe@example.com"`)
    - `employee_count` (integer or null, optional, example `50`)
    - `first_name` (string or null, optional, example `"John"`)
    - `industry` (string or null, optional, example `"Technology"`)
    - `last_name` (string or null, optional, example `"Doe"`)
    - `linkedin_profile` (string or null, optional, example `"https://linkedin.com/in/johndoe"`): The lead's LinkedIn profile URL
    - `title` (string or null, optional, example `"VP of Sales"`)
    - `website` (string or null, optional, example `"https://example.com"`): The lead's company website
  - `ai_response` (object, required): The AI Appointment Setter's analysis of the reply. When the reply wasn't analyzed, every field except `goal` is `null`, and `goal` gives the reason.
    - `agent_action` (string or null, optional, example `"reply"`): What the agent did with the reply: 'reply', 'wait', 'nudge', 'escalate', 'close' or 'skip'
    - `agent_version` (integer or null, optional, example `2`): Present (as 2) when the Appointment Setter agent handled the reply; absent on legacy payloads. Feature-detect on this field
    - `asset_delivered` (boolean or null, optional, example `true`): Asset-first campaigns only: whether the page went out
    - `asset_url` (string or null, optional, example `"https://pages.example.com/p/abc123"`): Asset-first campaigns only: the personalised page that was sent
    - `complete` (boolean or null, optional, example `false`): `true` when the conversation has ended or should end, whether or not its goal was reached. When `agent_version` is `2`, it's `true` exactly when `conversation_status` is one of the `closed_` values.
    - `conversation_status` (string or null, optional, example `"awaiting_prospect"`): The conversation's state after this reply. `awaiting_prospect`: waiting for the prospect. `needs_human`: the AI Appointment Setter handed the conversation to your team. `human_owned`: someone on your team has taken it over. `closed_won`, `closed_lost`, `closed_no_response` or `closed_escalated`: the conversation has ended. A lead still on the older follow-up flow can show `awaiting_followup`. Handle values you don't recognize without failing.
    - `escalation_reason` (string or null, optional): Why the agent handed the conversation to a human, when it did
    - `first_message_mode` (string or null, optional, example `"asset"`): Asset-first campaigns only: how the first message was sent
    - `goal` (string or null, optional, example `"Schedule a demo"`): The campaign goal the responder is working toward, or the skip reason
    - `goal_status` (string or null, optional, example `"link_sent"`): Progress toward the meeting goal: 'not\_sent', 'link\_sent', 'soft\_commit', 'confirmed' or 'declined'
    - `out_of_office` (boolean or null, optional, example `false`)
    - `responder_message` (string or null, optional, example `"Thank you for your interest! I'd be happy to schedule a demo for you."`): The reply the responder sent, or null when nothing was sent
    - `sdr_brief` (string or null, optional, example `"Prospect expressed interest, recommend scheduling demo within 24 hours."`)
    - `sentiment` (string or null, optional, example `"positive"`): 'positive', 'neutral' or 'negative'
  - `campaign` (string or null, optional, example `"Q1 2024 Outbound Campaign"`): The campaign's name. The payload doesn't include the campaign's ID.
  - `conversation_owner` (string or null, optional, example `"victoria"`): Present only when the conversation has an owner: 'victoria' when Victoria's responder is handling replies, 'lp\_responder' when an external responder is. Receivers that reply to prospects themselves should stay out of conversations Victoria owns
  - `prospect_message` (string or null, optional, example `"Hi, I'm interested in learning more about your product."`): The prospect's reply, as received
  - `variation` (string or null, optional, example `"a"`): A/B arm the lead is in: 'a', 'b', or null when the lead has none
- `success` (boolean, optional, default `true`)

## Errors

Errors share one JSON body: `success`, `error`, `message`, optional `details`, and `request_id`. For example:

```json
{
  "success": false,
  "error": "UNAUTHORIZED",
  "message": "Invalid or inactive API key",
  "request_id": "734d11a1-54d4-414c-9e8d-4e1ada977db4"
}
```

| Status | Code | Meaning |
| --- | --- | --- |
| 401 | `UNAUTHORIZED` | The `Authorization` header is missing or malformed, or the API key is unknown or has been deactivated. |
| 401 | `API_KEY_EXPIRED` | The API key is past its expiry date. Create a new key in the Victoria AI app. |
| 403 | `INSUFFICIENT_SCOPE` | The API key doesn't have the scope this endpoint requires, such as `leads:write`. |
| 403 | `ORGANIZATION_DEACTIVATED` | The organization that owns this API key has been deactivated. |
| 429 | `RATE_LIMITED` | Too many requests for this API key: more than 100 a minute to one endpoint, or 600 a minute in total. Retry after the number of seconds in the `Retry-After` header. See [Rate limits](https://docs.versionseven.ai/guides/rate-limits). |
| 500 | `INTERNAL_ERROR` | Something failed on our side. The response never includes internal details; quote its `request_id` when you contact support. |
| 503 | `UPSTREAM_TIMEOUT` | A service the API depends on timed out. The request is safe to retry. |
| 503 | `AUTH_UNAVAILABLE` | The API key couldn't be checked because the authentication service was unavailable. The request is safe to retry. |

## Response headers

| Header | Description |
| --- | --- |
| `X-Request-ID` | Correlation ID for the request, also returned as `request_id` in error bodies. Send your own `X-Request-ID`, up to 128 letters, digits, `.`, `_`, `:` or `-`, and it's used instead. |
| `RateLimit-Limit` | Requests allowed to this endpoint per minute. |
| `RateLimit-Remaining` | Requests you can still send to this endpoint right now. |
| `RateLimit-Reset` | Seconds until the endpoint's full limit is available again. |
| `Retry-After` | On a `429`: seconds to wait before retrying. |
