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

# Connect your phone system

> Send finished calls from any dialer to Sales Ask, directly or through Zapier or Make.

Use this when your phone system isn't one of our [ready-made dialer integrations](/integrations/dialers/overview). Your dialer, or an automation tool such as Zapier or Make, sends one request per finished call, and Sales Ask files the call as a recording for the right rep.

```mermaid theme={null}
flowchart LR
    A[Call ends in your dialer] --> B[POST to your Sales Ask webhook URL]
    B --> C{Rep found by email or phone?}
    C -- Yes --> D[Recording filed and analyzed]
    C -- No --> E[Ignored, error shown in Settings]
```

## Set up Sales Ask

<Steps>
  <Step title="Get your API key">
    Go to **Settings → Organization** and generate an [organization API key](/build/api-keys) if you don't have one.
  </Step>

  <Step title="Copy your webhook URL">
    Go to **Settings → Integrations → Custom Dialer**, copy the webhook URL, and click **Enable**. The URL already contains your API key.
  </Step>

  <Step title="Check your reps">
    Every rep whose calls should come in must be an active member with either the email their dialer uses, or their dialer phone number, on their Sales Ask profile. Sales Ask matches by email first, then by phone number.
  </Step>
</Steps>

## Send each call

Send a `POST` request with a JSON body to the webhook URL as soon as a call ends.

```json theme={null}
{
  "call_id": "c_8f2a91",
  "recording_url": "https://recordings.example.com/c_8f2a91.mp3",
  "direction": "outbound",
  "from_number": "+15551234567",
  "to_number": "+15557654321",
  "contact_name": "Jordan Lee",
  "started_at": "2026-10-12T15:04:00Z",
  "duration_seconds": 312,
  "rep_email": "rep@yourcompany.com"
}
```

<ParamField body="call_id" type="string" required>
  Unique ID for the call. A repeated `call_id` is ignored, so retries are safe.
</ParamField>

<ParamField body="recording_url" type="string" required>
  Public link that returns the audio file directly, with no login and no expiry.
</ParamField>

<ParamField body="rep_email" type="string">
  The rep's email. The most reliable way to match a rep, so send it whenever your dialer knows the agent. Required if you don't send `direction`.
</ParamField>

<ParamField body="direction" type="string">
  `inbound` or `outbound`. Tells Sales Ask which number is the rep's: `to_number` on inbound, `from_number` on outbound.
</ParamField>

<ParamField body="from_number" type="string">
  Calling number. E.164 format (`+15551234567`) matches best. National formats match on the last ten digits.
</ParamField>

<ParamField body="to_number" type="string">
  Called number, in the same format.
</ParamField>

<ParamField body="contact_name" type="string">
  Name of the customer on the call.
</ParamField>

<ParamField body="started_at" type="string">
  Call start time.
</ParamField>

<ParamField body="duration_seconds" type="number">
  Call length in seconds.
</ParamField>

### With Zapier or Make

<Tabs>
  <Tab title="Zapier">
    1. **Trigger**: your dialer's app with an event such as **Call completed**, **Call ended**, or **New call recording**. Choose a sample call that has a recording.
    2. **Filter** (optional): continue only if the recording URL exists, so unanswered calls aren't sent.
    3. **Action**: **Webhooks by Zapier → POST**.
       * **URL**: the Sales Ask webhook URL
       * **Payload Type**: `json`
       * **Data**: map each field above from the trigger
       * **Wrap Request In Array**: No
       * **Headers**: none
    4. Test the action and check the response (see [Responses](#responses)).
    5. Publish the Zap.
  </Tab>

  <Tab title="Make">
    1. **Trigger module**: your dialer's watch-calls or call-ended module, or a custom webhook your dialer posts to.
    2. Add **HTTP → Make a request**:
       * **URL**: the Sales Ask webhook URL
       * **Method**: `POST`
       * **Body type**: Raw
       * **Content type**: JSON (application/json)
       * **Request content**: one JSON object with the fields above, mapped from the trigger
       * **Parse response**: Yes, so the response message appears in the run log
    3. Run the scenario once and check the response (see [Responses](#responses)).
    4. Schedule the scenario to run immediately on each event.
  </Tab>
</Tabs>

## Responses

| Response | Meaning |
| - | - |
| `200` with `Recording queued successfully` | The call was accepted and filed. |
| `400` | A required field is missing. The message names the field. |
| `User not found - ignored` | The `rep_email` or phone number didn't match an active rep. |

Accepted calls appear with the source **Custom Dialer** in the meetings filter.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Calls are ignored with “User not found”">
    Send `rep_email` whenever you can. If you rely on phone numbers, check `direction` is set and that the rep's number is on their Sales Ask profile with country code.
  </Accordion>

  <Accordion title="A call was accepted but has no audio">
    `recording_url` must return the audio file itself, without a login page or an expiring link.
  </Accordion>

  <Accordion title="Where to see errors">
    **Settings → Integrations → Custom Dialer** shows the last error, with the call ID, when a call was rejected or couldn't be matched to a rep.
  </Accordion>

  <Accordion title="Still stuck?">
    Email [support@salesask.com](mailto:support@salesask.com) with your organization name, the `call_id`, and the response you got.
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.