# Passthrough Parameters

## Overview

Passthrough parameters allow you to associate your own system's data with [Spoke Phone](https://www.getspoke.com/products/spoke-phone) calls and conversations, as well as [Spoke Enlighten](https://www.getspoke.com/products/spoke-enlighten) content analysis jobs.

Use them to carry context from your systems into the user's workflow in Spoke, and to associate everything Spoke creates from that call or conversation with the external contact, order or case it relates to in your systems.

Passthrough parameters are stored against the call or conversation record as key-value pairs. They are included in the call's or conversation's [webhook events](/webhook-events), as well as in any subsequent [data action](/data-action-concepts) request for that call or conversation. Parameters stored against a call can also be retrieved when [getting the call resource through the Spoke API](/api/calls#get-a-call).

Users with a Spoke Enlighten license have their calls automatically analysed by a content analysis job. Any passthrough parameters associated with the call are automatically associated with the analysis job, meaning the subsequent `content_analysis.completed` event contains those parameters.

Examples of passthrough parameters include:

* The contact and order identifiers from your CRM, attached to a call a user placed from a link in the CRM, so that the call data record, its recording and any notes created by the Spoke platform can be associated with that contact and order.
* Caller verification, IVR selections or account lookups performed by another Twilio application (such as Studio, Flex or your own custom application) during the initial phase of a call.
* The campaign, case or ticket a conversation was started for, so that replies can be routed back to it.

### Example workflow

```mermaid
sequenceDiagram
    participant User as User
    participant Spoke as Spoke
    participant You as Your endpoints

    User->>Spoke: Clicks link with spoke://dial with x-contactId
    Note over Spoke: x-contactId
    User->>Spoke: Transfer call to team
    Spoke->>You: Team call data action request
    You-->>Spoke: Returns x-teamId
    Note over Spoke: x-contactId, x-teamId
    User->>Spoke: End call
    Spoke->>You: content_analysis.completed
    Note over You: x-contactId, x-teamId
```

## Parameter Format

Passthrough parameters are stored as a `passthroughParameters` object:

```json
{
  "x-contactId": "HS12345",
  "x-orderId": "ORD12345"
}
```

* Each key must start with the prefix `x-` and each value must be a string. Parameters that do not meet both conditions are ignored.
* The `x-` prefix is part of the stored key. A parameter supplied as `x-orderId` is returned as `x-orderId`.
* The total length of all passthrough parameters, including parameter names and values, must not exceed 1000 bytes. What happens when the limit is exceeded depends on how the parameters were supplied, see [Size Limit](#size-limit).
* Parameter names and values are URL-decoded where they arrive in a query string, validated for safety, and stored as-is. No additional processing is performed.

[Spoke Enlighten](https://www.getspoke.com/products/spoke-enlighten) content analysis jobs also support passthrough parameters. See [Content Analysis](#content-analysis) for the differences.

## Passthrough Parameters on Calls

### Attaching Parameters to a Call

Passthrough parameters can be attached to a call at the point the call is placed or routed into Spoke, and can be added to or overridden later by a data action.

#### Deep Linking

Add each parameter to the query string of a [`spoke://dial` deep link](/deep-linking/dial#passthrough-parameters), prefixed with `x-`:

```
spoke://dial?contactNumber=%2B64221112222&callerId=%2B14341112222&x-contactId=HS12345&x-orderId=OR12345
```

Parameters are only stored if opening the deep link results in a call being made. If the app has to fall back to the dial pad, then any call the user subsequently places from the dial pad is stored without passthrough parameters. This happens if the passthrough parameters exceed the size limit, or if `contactNumber` or `callerId` is missing or invalid. It is important that the source system validates every parameter it puts in the deep link.

#### Spoke's Redirect Handler

Add each parameter to the `url` you redirect the Twilio call to:

```javascript
const client = require('twilio')();

client.calls('CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
  .update({
      method: 'POST',
      url: 'https://api.spokephone.com/telephony/redirect?extension={EXTENSION}&organisationId={SPOKE_ORG_ID}&x-contactId=HS12345&x-orderId=OR12345'
  });
```

**Important**: All the query parameters of the redirect handler `url` must be in alphabetical order. In the example above `x-contactId` must come before `x-orderId`.

#### Twilio Voice Application Connect

Add each parameter to the `<Application>` noun:

```javascript
application.parameter({ name: 'extension', value: '{EXTENSION}' });
application.parameter({ name: 'sourceAccountSid', value: client.accountSid });
application.parameter({ name: 'x-contactId', value: 'HS12345' });
application.parameter({ name: 'x-orderId', value: 'OR12345' });
```

Both of the mechanisms above are documented in full in [Routing Twilio Calls into Spoke](/routing-twilio-calls-into-spoke#setting-passthrough-parameters).

#### Data Actions

Return a `passthroughParameters` object from an [Outbound Call](/data-actions/outbound-call) or [Team Call](/data-actions/team-call) data action response. Parameters returned by a data action are merged with the parameters already stored against the call. If a key exists in both the response and the stored parameters, the value from the response overrides the stored value.

A Team Call data action is invoked every time a call is about to be offered to a team. This means that a call which is transferred or rolls over to a second team will result in more than one request, and the passthrough parameters can be updated in each of them. See the [example timelines](/data-actions/team-call) for when those requests are made.

### Reading Parameters Back from a Call

| Where | How they appear |
| --- | --- |
| [Call webhook events](/events/call-lifecycle-events) | `passthroughParameters` on the event's `call` object |
| [`GET /calls/{id}`](/api/calls#get-a-call) and [`GET /calls`](/api/calls#list-calls) | `passthroughParameters` on the call resource |
| [Outbound Call](/data-actions/outbound-call#outbound-call-request) and [Call Insights](/data-actions/insights#call-insights-request) data action requests | Flattened into the request's query string |
| [Team Call](/data-actions/team-call#team-call-request) data action request | `passthroughParameters` in the request body, an empty object if the call has none |

Passthrough parameters are included in every call event, including events that occur well after the call has ended such as `call.recording.available`, `call.transcript.created` and `call.tariffed`.

Because the Outbound Call and Call Insights data actions are sent as `GET` requests, the call's existing parameters are flattened into key-value pairs, URL-encoded, and then appended to the query string.

Example:

Given a call with the following passthrough parameters:

```json
{
  "x-customerName": "John Doe",
  "x-item": "Smartphone & Accessories"
}
```

The constructed data action request will be:

```
https://api.example.com/outboundCall?callerId=1234&contactNumber=%2B12178888888&vendorCallId=4321&x-customerName=John%20Doe&x-item=Smartphone%20%26%20Accessories
```

## Passthrough Parameters on Conversations

### Attaching Parameters to a Conversation

#### Sending a Message

Include a `passthroughParameters` object in the body of [`POST /conversationMessages`](/api/conversations#send-a-new-conversation-message):

```json
{
  ...
  "passthroughParameters": {
    "x-contactId": "HS12345",
    "x-orderId": "ORD12345"
  }
}
```

If the message creates a new conversation, the parameters are stored against it. If the message is added to an existing conversation that already has passthrough parameters, the new parameters are merged with the existing ones. If a key exists in both, the value from the request overrides the stored value.

#### Data Actions

Return a `passthroughParameters` object from an [Inbound Conversations](/data-actions/inbound-conversations) data action response. This data action is invoked when a message from an external participant creates a new conversation, which makes it the mechanism for attaching your own identifiers to conversations your customers start.

### Reading Parameters Back from a Conversation

The `conversation` object of every [conversation webhook event](/events/conversation-events) includes `passthroughParameters`. This includes `conversation.message.created`, which is generated for each message received or sent on the conversation.

## Content Analysis

[Content analysis](/api/content-analysis) jobs accept passthrough parameters so that an analysis can be traced back to the call or the system it came from. A job acquires them in one of two ways.

### Jobs your system creates.

Include a `passthroughParameters` object in the body of `POST /contentAnalysis`. These parameters are free-form. The `x-` prefix rule and the string-value rule do not apply, and Spoke returns the object exactly as you submitted it. They can only be set when the job is created, and there is no mechanism for adding to or overriding them afterwards.

### Jobs Spoke creates from a call.

Spoke Enlighten analyses a call by creating a content analysis job, and that job inherits the passthrough parameters stored against the call. These parameters follow the call rules rather than the free-form rules, so every key carries the `x-` prefix and every value is a string. You do not supply them to the analysis. To change what an analysis carries, change the parameters on the call before the analysis is created.

In both cases the parameters are returned by `GET /contentAnalysis/{id}` and on the `contentAnalysis` object of the `content_analysis.completed` webhook event.

## Size Limit

The total length of all passthrough parameters, including parameter names and values, must not exceed 1000 bytes. If this limit is exceeded, all passthrough parameters are discarded rather than being partially stored. Which parameters are discarded depends on where they came from:

| Mechanism | Behaviour when the limit is exceeded |
| --- | --- |
| [`spoke://dial` deep link](/deep-linking/dial#passthrough-parameters) | The call is not made. The app navigates to the dial pad, prefilled with the provided `contactNumber` and `callerId`. If the user then places the call from the dial pad, it is stored without passthrough parameters |
| [Spoke's redirect handler and Twilio Voice Application Connect](/routing-twilio-calls-into-spoke#setting-passthrough-parameters) | All passthrough parameters are discarded. The call proceeds |
| [Outbound Call](/data-actions/outbound-call) and [Team Call](/data-actions/team-call) data actions | The parameters from the response are discarded, and the parameters stored against the call are left unchanged |
| [Inbound Conversations](/data-actions/inbound-conversations) data action | The parameters from the response are discarded |
| [`POST /conversationMessages`](/api/conversations#send-a-new-conversation-message) | The stored passthrough parameters are not updated |

Where parameters are merged, the limit applies to the merged parameters and not to the parameters in the response or request on their own. This applies to both data actions on a call, and to sending a message to an existing conversation. Note that a data action which returns a new key on every request can take a call over the limit part way through the call. We recommend limiting passthrough parameters to identifiers rather than payloads, and overriding existing keys rather than adding new ones.
