# Webhook Events

## Overview

Spoke supports webhooks as a mechanism for notifying your systems when an event occurs. Webhooks are useful for listening to asynchronous events occurring on the Spoke platform, such as changes to a call's state over time; a change to the contact associated with a call; or a call recording becoming available.

To get started, you will need to configure a webhook in the Spoke [account portal](https://account.spokephone.com/developers/webhooks). Alternatively, you can use the [Webhook API](/api/webhooks#create-a-webhook) to configure a webhook. During configuration you will be given the option to specify event types you wish to receive notifications for. You will also be required to provide a valid, publicly routable `HTTPS` URL that accepts `POST` requests with the `application/json` content type.

Every Spoke event sent to your webhook is wrapped in the following standard wrapper that provides important information about the event, such as its type, a timestamp of when it was created, and the event data itself.

## Securing Your Webhooks

Once your application is configured to receive events, it will listen for any event sent to the endpoint. For security reasons, we strongly recommend that you ensure requests to your endpoint come from Spoke. The easiest method to validate that a request was sent via Spoke is to verify the signature, and timestamp sent in every request against the secret that was provided to you when you created your webhook.

### Verifying the signature

A request is considered valid based on the following conditions:
- The `x-spoke-timestamp` header is a valid UNIX timestamp, and represents a time sent within the last 5 minutes (using millisecond precision). This header allows the consumer to validate when a request was sent, to avoid [replay attacks](https://en.wikipedia.org/wiki/Replay_attack).
- The `x-spoke-signature` header is formatted as `sha256=<HMAC algorithm cipher text>`, and it contains the correct hash based on the hexadecimal representation of the SHA256 HMAC algorithm with the signing secret applied to `<x-spoke-timestamp header value>.<request body>`. The calculated hash includes the timestamp to ensure that an attacker cannot modify the timestamp without also invalidating the message signature.

A request can be validated via the following:

```js
const isValidSpokeRequest = (requestBody: string, signingSecret: string, spokeTimestamp: number, spokeSignature: string): boolean => {

  // Determine if timestamp is valid
  const isValidTimestamp = (Date.now() - spokeTimestamp) <= 300000; // 5 x 60 x 1000
  if (!isValidTimestamp) {
    return false;
  }

  // Determine if the signature is valid
  const [algorithm, cipher] = spokeSignature.split("=");
  const body = `${spokeTimestamp}.${requestBody}`

  const h = crypto.createHmac(algorithm, signingSecret);
  h.update(body);
  return h.digest("hex") === cipher;
}
```

## Delivery Attempts, Retries and Event Ordering

### Delivery Attempts

Spoke will attempt to deliver events to your webhooks 10 times, over the course of 24 hours with an exponential back off. For an event to be considered successfully delivered, your endpoint will need to respond with a valid `2XX` HTTP status code within 5 seconds of the HTTP request being received. In the Developers section of the [Account Portal](https://account.spokephone.com/developers/events), you can view all attempts to deliver an event to your endpoint.

### Retries

Spoke will retry delivering a webhook event if the request fails and your endpoint responds with any of the following status codes:

- Server-side errors: `5xx`
- Throttling errors: `429`
- Request timeout errors: `408`

Failed delivery attempts that respond with any other status codes will not be retried. For example, responses with a `400` status code (Bad Request) will not be retried, as it signals that repeating the same request will fail with the same error.

### Automatic Disabling of Webhooks

In order to manage system capacity across the platform, Spoke will automatically disable a webhook once more than consecutive 1000 events have failed to deliver.  The Spoke Administrator who created the webhook will be notified via email that the webhook has been disabled.

### Order of Events

Spoke does not guarantee delivery of events in the order in which they are generated. Your endpoint should not expect delivery of events in order, and should handle these accordingly.

## Example Timelines of Events

Below are some examples of when the above events might occur during the lifetime of some calls.

*Note: These are example timelines. While most of the events will fire in a similar order to the ones given below, this is not guaranteed. See [Order of Events](/webhook-events#delivery-attempts-retries-and-event-ordering) for more details on how event ordering might affect your webhook.*

### Example Timelines of Call and Availability Events


---

#### Example 1 - Basic Call Timeline with User Answered Call

<div class="timeline-headings">
  <h4>User Actions</h4>
  <h4>Events Fired</h4>
</div>
<div class="timeline">
  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-started">
        <code>call.started</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Customer Alice starts a call to Spoke User Bob. </h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-answered">
        <code>call.answered</code>
      </a><br />
      <a href="/events/user-events#user-availability-updated">
        <code>user.availability.updated</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob answers the call</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-hungup">
        <code>call.hungup</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>After talking for a while, Alice is satisfied with Bob's response and hangs up the call.</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-hungup">
        <code>call.hungup</code>
      </a><br />
      <a href="/events/user-events#user-availability-updated">
        <code>user.availability.updated</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob also hangs up the call</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-ended">
        <code>call.ended</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>The call has completed on the Spoke platform</h4>
    </div>
  </div>

</div>

---

#### Example 2 - Unanswered Call to Team

<div class="timeline-headings">
  <h4>User Actions</h4>
  <h4>Events Fired</h4>
</div>
<div class="timeline">
  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-started">
        <code>call.started</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Customer Alice starts a call to the Customer Support team</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-not-answered">
        <code>call.not_answered</code>
      </a><br />
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>No one is available to answer the call, and the call goes to voicemail</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-hungup">
        <code>call.hungup</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>After talking leaving a message, Alice hangs up the call.</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-ended">
        <code>call.ended</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>The call has completed on the Spoke platform</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-media-events#call-voicemail-available">
        <code>call.voicemail.available</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>The voicemail recording has finished processing, with the voicemail transcript sent to members of the Customer Support team</h4>
    </div>
  </div>

</div>

---

#### Example 3 - Contact Assignment and Recording Transcript

<div class="timeline-headings">
  <h4>User Actions</h4>
  <h4>Events Fired</h4>
</div>
<div class="timeline">
  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-started">
        <code>call.started</code>
      </a><br />
      <a href="/events/call-lifecycle-events#call-answered">
        <code>call.answered</code>
      </a><br />
      <a href="/events/user-events#user-availability-updated">
        <code>user.availability.updated</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Customer Alice starts a call to Bob. Alice has a new number that isn't in Bob's CRM so she shows up as an unknown caller to Bob. Bob answers the call</h4>
    </div>
  </div>
  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-contact-events#call-contact-assigned">
        <code>call.contact_assigned</code>
      </a>
    </div>
  </div>

  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob determines that the Unknown caller is actually Customer Alice</h4>
    </div>
  </div>
  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-annotation-events#call-highlight-created">
        <code>call.highlight.created</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob decides that this call is about Alice's money, and decides to highlight the current part of the call as "Money"</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-lifecycle-events#call-hungup">
        <code>call.hungup x 2 (Alice & Bob)</code>
      </a><br/>
      <a href="/events/user-events#user-availability-updated">
        <code>user.availability.updated</code>
      </a><br/>
      <a href="/events/call-lifecycle-events#call-ended">
        <code>call.ended</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Alice hangs up the call, Bob hangs up the call, and the call ends.</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-media-events#call-recording-available">
        <code>call.recording.available</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Call recording successfully completes processing</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/call-media-events#call-transcript-created">
        <code>call.transcript.created</code>
      </a><br/>
      <a href="/events/call-media-events#call-transcription-completed">
        <code>call.transcription_completed</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Call recording is transcribed successfully</h4>
    </div>
  </div>
</div>

### Example Timelines of Conversation Events

---

#### Example 1

<div class="timeline-headings">
  <h4>User Actions</h4>
  <h4>Events Fired</h4>
</div>
<div class="timeline">
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>User Alice wants to talk to Bob over SMS</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-message-created">
        <code>conversation.message.created</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Alice sends an SMS to Bob through the Spoke Phone app</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-message-created">
        <code>conversation.message.created</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob receives the SMS from Alice and replies</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-inactive">
        <code>conversation.inactive</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Alice finishes messaging with Bob. The conversation automatically goes into an inactive state after 30 minutes</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-closed">
        <code>conversation.closed</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>After a year of inactivity, the conversation gets closed automatically</h4>
    </div>
  </div>
</div>

---

#### Example 2

<div class="timeline-headings">
  <h4>User Actions</h4>
  <h4>Events Fired</h4>
</div>
<div class="timeline">
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Customer Bob wants to talk to user Alice over SMS</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-message-created">
        <code>conversation.message.created</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob sends an SMS to Alice</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-message-created">
        <code>conversation.message.created</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Alice receives the SMS from Bob through the Spoke Phone app and replies</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-inactive">
        <code>conversation.inactive</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Alice finishes messaging with Bob, neither party sends an SMS for 30 minutes. The conversation goes into an inactive state</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-message-created">
        <code>conversation.message.created</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob starts messaging Alice again in the conversation. The timer for both inactive state and the closed state gets reset</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-inactive">
        <code>conversation.inactive</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Bob finishes messaging with Alice, neither party sends an SMS for 30 minutes. The conversation goes into an inactive state</h4>
    </div>
  </div>

  <div class="timeline-container right">
    <div class="timeline-content">
      <a href="/events/conversation-events#conversation-closed">
        <code>conversation.closed</code>
      </a>
    </div>
  </div>
  <div class="timeline-container left">
    <div class="timeline-content">
      <h4>Alice manually closes the conversation</h4>
    </div>
  </div>
</div>
