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

# Receive Prophic Pipeline Events with Webhooks

> Subscribe an HTTPS endpoint to Prophic events, verify HMAC signatures, and react to quotation pipeline updates in real time.

Prophic webhooks push a lean JSON payload to your HTTPS endpoint every time a Quick Quote pipeline step finishes, so you can react without polling. You need the **Manage integrations** permission to configure endpoints.

<Info>
  **Lean payload.** Webhook bodies carry IDs and status only, never the full proposal document. After a notification, call the [integrations API](/integrations/api-reference) to fetch what you need.
</Info>

## Add a webhook endpoint

<Steps>
  <Step title="Open Account → Webhooks">
    You must hold **Manage integrations** to see this screen. Org admins have it by default.
  </Step>

  <Step title="Add your HTTPS URL">
    Enter the endpoint that will receive `POST` requests and give it a descriptive name.
  </Step>

  <Step title="Choose the events">
    Pick the event types you want to receive (see the [event catalog](#event-catalog) below). Most partners subscribe to `quotation.proposal.completed` and `quotation.failed`.
  </Step>

  <Step title="Pick a trigger mode">
    * **Headless only** (default): only notify when the quote was started with an API key. Recommended for partner integrations to avoid noise from UI activity.
    * **Always**: notify for both UI Quick Quotes and API-key runs.
  </Step>

  <Step title="Copy the signing secret">
    The `whsec_...` value is shown **once**. Store it securely; you will need it to verify signatures.
  </Step>

  <Step title="Send a test delivery">
    Use **Send test** to confirm your URL accepts deliveries. Check the delivery log for HTTP status codes and errors.
  </Step>
</Steps>

## Event catalog

| Event type                                     | When it fires                               |
| ---------------------------------------------- | ------------------------------------------- |
| `quotation.requirement_analysis.completed`     | Requirement analysis step finished          |
| `quotation.functional_specification.completed` | Functional specification finished           |
| `quotation.work_breakdown.completed`           | Work breakdown finished                     |
| `quotation.effort_estimation.completed`        | Effort estimation finished                  |
| `quotation.proposal.completed`                 | Proposal artifact is ready                  |
| `quotation.completed`                          | Full Quick Quote pipeline succeeded         |
| `quotation.failed`                             | Pipeline run failed (terminal for that run) |

## Payload shape

```json Lean webhook JSON theme={null}
{
  "id": "evt_<uuid>",
  "type": "quotation.proposal.completed",
  "created_at": "2026-09-01T12:00:00.000Z",
  "organization_id": "<uuid>",
  "data": {
    "quotation_id": "<uuid>",
    "proposal_id": "<uuid|null>",
    "step": "proposal",
    "status": "completed",
    "error_code": null,
    "generation_source": "api_key"
  }
}
```

For failures, `status` is `failed`, `error_code` may be set, and `step` is the failed step when known. Always deduplicate on `id` because delivery is at-least-once.

## Delivery headers

Every delivery includes these headers:

| Header                 | Purpose                                                 |
| ---------------------- | ------------------------------------------------------- |
| `Content-Type`         | `application/json`                                      |
| `X-Prophic-Event-Id`   | Same as payload `id`                                    |
| `X-Prophic-Event-Type` | Event type string                                       |
| `X-Prophic-Timestamp`  | Unix seconds when the delivery was signed               |
| `X-Prophic-Signature`  | `v1=<hmac-sha256-hex>` over `timestamp + "." + rawBody` |

## Verify signatures

Every request is signed with your endpoint's secret. Verify the signature before trusting the payload.

<Steps>
  <Step title="Keep the raw body bytes">
    Do not parse and re-serialize the JSON before checking the signature; whitespace differences will break the HMAC.
  </Step>

  <Step title="Compute HMAC-SHA256">
    Compute `HMAC-SHA256(secret, timestamp + "." + rawBody)` using the `whsec_...` value you stored when creating the endpoint.
  </Step>

  <Step title="Compare in constant time">
    Compare your hex digest against the value after `v1=` in `X-Prophic-Signature`. Use a constant-time comparison to prevent timing attacks.
  </Step>

  <Step title="Check the timestamp">
    Reject the request if `X-Prophic-Timestamp` is more than about five minutes from your server clock. This blocks replay attacks.
  </Step>

  <Step title="Deduplicate on event ID">
    Track processed `id` values so at-least-once retries do not double-process the same event.
  </Step>
</Steps>

### Example: Node.js verification

```javascript verify.js theme={null}
import crypto from "crypto";

function verifyProphicSignature(rawBody, headers, secret) {
  const timestamp = headers["x-prophic-timestamp"];
  const signature = headers["x-prophic-signature"];

  // Reject stale requests (5-minute window).
  const age = Math.floor(Date.now() / 1000) - Number(timestamp);
  if (Math.abs(age) > 300) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  const provided = signature.replace(/^v1=/, "");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(provided, "hex")
  );
}
```

## Delivery behavior

* **HTTPS only.** Prophic will not deliver to plain HTTP endpoints.
* **\~10 second timeout.** Return `2xx` quickly. Do the heavy work asynchronously.
* **Exponential backoff.** Failed deliveries retry up to 8 times.
* **`HTTP 410` is permanent.** Return `410 Gone` to stop future retries for a specific event.
* **At-least-once.** Deduplicate on `id`.

## Trigger modes

| Mode                      | Behavior                                             |
| ------------------------- | ---------------------------------------------------- |
| `headless_only` (default) | Fire only when the quote was started with an API key |
| `always`                  | Fire for both UI and API-key quotes                  |

## End-to-end checklist

* [ ] API key created and stored
* [ ] `POST /quotations` returns `202` and a `quotation_id`
* [ ] Webhook endpoint enabled with the events you care about
* [ ] Test event succeeds in the delivery log
* [ ] Signature verification works in your receiver
* [ ] `GET .../document-url` returns a working short-lived URL after `quotation.proposal.completed`

## Related

<CardGroup cols={2}>
  <Card title="API Reference" icon="code" href="/integrations/api-reference">
    Full contracts for managing endpoints and delivery logs.
  </Card>

  <Card title="API Keys" icon="key" href="/integrations/api-keys">
    Create the credentials that scope your headless quotes.
  </Card>
</CardGroup>


## Related topics

- [Integrations and Webhooks REST API Reference](/integrations/api-reference.md)
- [Connect Prophic to Your CRM, Portal, or Automation](/integrations/overview.md)
- [Create and Manage Prophic API Keys](/integrations/api-keys.md)
- [How Prophic's 5-Stage Pre-Sales Pipeline Works](/concepts/pre-sales-workflow.md)
