Saperly logo

Integrate Saperly with your AI CRM

Saperly is the phone carrier for AI agents — phone numbers, voice, SMS, and compliance in one API.

Explore Triggers and Actions

Bind Connection to Number

Attach a connection (the AI persona / answering brain from SAPERLY_CREATE_CONNECTION) to a phone number, so inbound calls and SMS to that number — and outbound calls placed from it — are handled by that connection. A number without a bound connection cannot answer calls (and PLACE_CALL fails with 422 NumberHasNoConnection), so this is the wiring step that makes a number answerable. Get a connection id from SAPERLY_LIST_CONNECTIONS or create one with SAPERLY_CREATE_CONNECTION. Returns the updated number object. Free.

ActionTry it

Check Consent

Check whether a contact currently has active TCPA consent for one of your Saperly numbers, given numberId (your number) and peerNumber (the contact's E.164 number) as query params. Returns {hasConsent: boolean} and, when hasConsent is true, {type: '<consentType>'} (the 'type' key is ABSENT when hasConsent is false). Saperly REFUSES outbound SMS (SAPERLY_SEND_SMS) and voice calls (SAPERLY_PLACE_CALL) — both of which are paid, balance-metered — to a destination without active consent, so call this free, read-only check FIRST to decide whether you need SAPERLY_RECORD_CONSENT before spending on a paid send/call that would otherwise fail the compliance gate. No side effects.

ActionTry it

Create Connection

Create a connection: the AI 'brain' that answers calls and (optionally) SMS on a Saperly phone number. A phone number binds to a connection via SAPERLY_ASSIGN_NUMBER_CONNECTION in order to answer calls. Only `name` is required. mode 'hosted' (default) = an in-network STT->LLM->TTS voice assistant driven by `instructions` (the system prompt), `tts` voice (voiceId from SAPERLY_LIST_VOICES), and `language`; mode 'manual' = your own webhook brain (set `manualWebhookUrl`). complianceEnabled defaults true — Saperly then speaks a TCPA `disclosure` as the first uninterruptible utterance, auto-filling a standard org-named disclosure if you leave it empty. Returns the created connection (201). Free. (The 'backend' field is intentionally not exposed: only 'network' works; 'openai_realtime' is server-rejected.)

ActionTry it

Delete Connection

PERMANENTLY AND IRREVERSIBLY delete a connection (the AI answering brain / persona that handles calls and SMS) by its id. THIS CANNOT BE UNDONE — there is no restore. WARNING: any phone number currently bound to this connection will immediately STOP handling inbound calls and SMS (it has no answering brain) until you bind another connection to it. Before deleting, call SAPERLY_LIST_NUMBERS to check which numbers reference this connectionId, and rebind them with SAPERLY_ASSIGN_NUMBER_CONNECTION first. Returns { status: 'deleted' }. Free, but destructive.

ActionTry it

End Call

End an in-progress call by its id, hanging up and settling the metered cost. This is the safe, cheap, RECOMMENDED companion to SAPERLY_PLACE_CALL: placing a call starts per-minute billing, and this tool is how an agent stops that meter — call it as soon as you are done with the call. Ending is itself free (it ends spend rather than adding it). Returns the call object; durationSec and costCents may still be NULL if the call has not settled yet (null does NOT mean free — poll SAPERLY_GET_CALL afterwards for the final cost and duration). Only meaningful while a call is live; ending an already-ended call is a best-effort no-op.

ActionTry it

Get Call

Fetch a single call by its id, returning its status, per-minute rate, final duration (durationSec) and cost (costCents), and the hasRecording / hasTranscript flags. costCents and durationSec are NULL until the call settles (in progress / not yet billed) — null does NOT mean free, so this is the tool to poll after SAPERLY_PLACE_CALL to learn a call's final cost and duration. Check hasRecording / hasTranscript before calling SAPERLY_GET_CALL_RECORDING / SAPERLY_GET_CALL_TRANSCRIPT: those artefact endpoints 404 until the call has ended and been processed, and a 404 there means 'no artefact yet', not 'no such call'. Free, read-only.

ActionTry it

Get Call Recording

Get the audio recording for a call and return it as a downloadable file. The API answers with a 302 redirect to a signed download URL when a recording exists; the recording is fetched and returned as a file reference (under `content`). A recording exists only if the call's connection had recordingEnabled=true AND the call actually connected and completed — so for many calls there is simply no recording. The endpoint uses the same 404 response for an unknown call and a call without an artifact, so verify the id and check SAPERLY_GET_CALL.hasRecording=true before calling this. Free, read-only.

ActionTry it

Get Call Transcript

Fetch the transcript (conversation turns/segments) of a completed call by its id. Transcripts only exist AFTER a call connects, ends, and is processed. The endpoint uses the same 404 for an unknown call and a valid call whose transcript is not ready. Before calling this, poll SAPERLY_GET_CALL until the call has settled (durationSec / costCents are non-null) and hasTranscript is true. The returned payload is exposed under a 'transcript' key with call metadata and ordered role/text/timestamp turns. Free, read-only.

ActionTry it

Get Connection

Fetch a single connection (the AI answering brain / persona that handles calls and SMS) by its id, returning its full config: name, mode, backend, instructions, tts voice, language, compliance/disclosure settings, recordingEnabled, and manual webhook URL. Sensitive signing secrets are redacted. Use after SAPERLY_LIST_CONNECTIONS to inspect one connection. Free, read-only.

ActionTry it

Get Phone Number

Fetch a single phone number by its id, returning its E.164 phoneNumber, bound connectionId, webhookUrl, country, numberType, pricing and lifecycle fields. Use after SAPERLY_LIST_NUMBERS to inspect one number's current configuration. Free, read-only.

ActionTry it

Get Usage & Balance

Return the workspace usage summary and prepaid balance: calls {count, totalCostCents, totalDurationSec}, messages {count}, and balanceCents (the prepaid balance, in cents). ALWAYS call this before any paid action to check balanceCents: SAPERLY_PROVISION_NUMBER (~$2/mo), SAPERLY_SEND_SMS (~2c/segment) and SAPERLY_PLACE_CALL (~26c/min) all draw down this single balance, and a depleted (0) balance causes them to fail. This is also the best whoami / key check: a 200 confirms the connected key is valid and which workspace it maps to (prefer it over /health for that). Pass the optional 'since' (ISO-8601) to scope the usage window. Free, read-only, no pagination.

ActionTry it

List Calls

Return the full voice-call history (inbound + outbound) for the connected Saperly workspace. Each call carries its id, numberId, direction, to and from_number (E.164), status, rateCentsPerMin, durationSec, costCents, hasRecording and hasTranscript. Note: durationSec and costCents are null until the call settles (null means 'not yet settled', not 'free'). Use the id with SAPERLY_GET_CALL for full detail, and check hasRecording / hasTranscript before calling SAPERLY_GET_CALL_RECORDING / SAPERLY_GET_CALL_TRANSCRIPT (they 404 when the artifact does not exist yet). Read-only and free. Returns a bare array — there is no pagination and no filter parameter.

ActionTry it

List Connections

Return every connection (the AI persona / answering 'brain' that handles calls and SMS) in the connected Saperly workspace. Each carries id, name, mode (hosted|manual), backend, instructions, llm, tts voice, language, mcpServers, callControl, complianceEnabled, smsAutoReply, disclosure and recordingEnabled. Use this to find a connectionId to bind to a number or use on a call. Read-only and free. Returns a bare array (no pagination).

ActionTry it

List Consent Records

Return every TCPA consent record in the connected Saperly workspace, with each record's id, numberId (the Saperly number contact is authorized FROM), peerNumber (the contact's E.164 number), consentType (explicit_outbound or implied_inbound), source, grantedAt and revokedAt. Consent is Saperly's compliance gate: outbound SMS (SAPERLY_SEND_SMS) and calls (SAPERLY_PLACE_CALL) are only permitted to a destination that has an active consent record, and these records form an immutable TCPA audit trail. Use this to review or export the full consent log; to check a single contact instead, use SAPERLY_CHECK_CONSENT. Read-only and free. Returns a bare array (no pagination).

ActionTry it

List Languages

Return the spoken languages Saperly supports for voice connections, each as a {code, name} pair (about 42 entries, e.g. {'code':'en','name':'English'}). A language `code` is what you pass as a connection's `language` field, and as the `language` filter to SAPERLY_LIST_VOICES (that filter does a PREFIX match, so 'fr' also matches regional variants such as 'fr-CA'). Note this base-code set is narrower than the /voices language tags, which include regional variants. Read-only and free. Returns a bare array (no pagination).

ActionTry it

List Messages

Return SMS messages in the connected Saperly workspace (both inbound and outbound). Each message has id, numberId, direction, to, from_number, body, segments, status and createdAt. Pass `numberId` to filter to a single phone number's messages; `numberId` is the ONLY filter available. With no filter this returns the FULL message history, which may be large — there is no pagination. Free and read-only; returns a bare array.

ActionTry it

List Phone Numbers

Return every phone number provisioned in the connected Saperly workspace, with each number's id, phoneNumber (E.164), the connectionId (answering brain) bound to it, webhookUrl, country, numberType, monthlyPriceCents and lifecycle timestamps. Use this to discover a number's id before sending SMS, placing a call, or configuring the number. Read-only and free. Returns a bare array (no pagination).

ActionTry it

List Voices

List the text-to-speech voices available for Saperly connections. Each voice has an id, name, gender and language; a voice id is what you pass as tts.voiceId when creating or updating a connection (SAPERLY_CREATE_CONNECTION / SAPERLY_UPDATE_CONNECTION). ALWAYS pass `language` to filter — the unfiltered list is ~751 voices across 52 language tags, which is expensive to return in full. NOTE the filter is a PREFIX/family match, not exact: language='fr' returns both 'fr' and 'fr-CA'. Get language codes from SAPERLY_LIST_LANGUAGES. Read-only and free; returns a bare array (no pagination).

ActionTry it

Place Call

PAID / METERED — places a REAL outbound voice call that RINGS A REAL PHONE and BILLS PER MINUTE (~26¢/min); it keeps billing until hung up — end it with SAPERLY_END_CALL to stop the meter. Calls FROM a Saperly number (`fromNumberId` from SAPERLY_LIST_NUMBERS) TO an E.164 destination (`to`, e.g. +14155550123). The connection bound to the originating number answers; a number with NO bound connection cannot hold a conversation (bind one with SAPERLY_ASSIGN_NUMBER_CONNECTION). Optionally override the brain for this call with `connectionId` and/or a per-call `instructions` prompt. CONSENT GATE (TCPA): the destination MUST have active consent — call SAPERLY_RECORD_CONSENT first and SAPERLY_CHECK_CONSENT to verify, or it is rejected (403). Returns the call (201) with id + status; `durationSec`/`costCents` are NULL until the call settles (ends) — null does NOT mean it was free. Pass `idempotency_key` on retries to avoid double-dialing. May fail 402 (funds) or 422 (no connection).

ActionTry it

Provision Phone Number

PAID / METERED: provision (buy) a new phone number in a country. This SPENDS MONEY — it charges the workspace prepaid balance an upfront fee plus a RECURRING MONTHLY rent (US local ~ $1.79/mo, varies by country/type). Before calling this: (1) call SAPERLY_QUOTE_NUMBER_PRICE to get the live price and pass it as expectedMonthlyPriceCents / expectedUpfrontPriceCents to guard against price drift (a higher live price fails with 409 PriceChanged unless approveHigherPrice=true); (2) confirm sufficient funds by checking balanceCents via SAPERLY_GET_USAGE. Defaults country='US', numberType='local'. Pass an idempotency_key to avoid double-provisioning on retry. Fails 402 (InsufficientFunds / PaymentMethodRequired), 403 (CountryNotAvailable), 404 (NoNumbersAvailable), 409 (NumberQuotaExceeded / PriceChanged).

ActionTry it

Quote Number Price

READ-ONLY and FREE: quote the price to provision a phone number in a country/type, returning { customerMonthlyCents, customerUpfrontCents }. This DOES NOT provision, reserve, or charge anything — despite the name it has NO side effects. This is exactly the tool to call BEFORE the expensive SAPERLY_PROVISION_NUMBER (which spends ~$2/mo): (1) use it to size the cost and feed customerMonthlyCents / customerUpfrontCents straight into SAPERLY_PROVISION_NUMBER's expectedMonthlyPriceCents / expectedUpfrontPriceCents price-drift guards (the safe provisioning pattern); (2) compare against balanceCents from SAPERLY_GET_USAGE to confirm sufficient funds. Both country and numberType are required. Live-verified: US/local quoted 179 cents monthly and 179 cents upfront.

ActionTry it

Record Consent

Record TCPA consent for a contact so outbound SMS (SAPERLY_SEND_SMS) and calls (SAPERLY_PLACE_CALL) from your number are permitted. Saperly's compliance gate: for a cold contact call this BEFORE sending; confirm with SAPERLY_CHECK_CONSENT, revoke with SAPERLY_REVOKE_CONSENT. LEGAL ARTEFACT — DO NOT FABRICATE CONSENT: it writes to an IMMUTABLE audit trail asserting a real human gave consent to be contacted. Only record consent ACTUALLY obtained (an opt-in the contact gave, or an inbound message/call they initiated). Recording consent not truly obtained is a false compliance record and a legal violation; never do it merely to unblock a send. Requires numberId (your number, from SAPERLY_LIST_NUMBERS), peerNumber (the contact's E.164 number), consentType ('explicit_outbound' = opted in, or 'implied_inbound' = they contacted you first — legally distinct), and source (a note on how/where consent was obtained). Returns 201 with the record. Free.

ActionTry it

Release Phone Number

PERMANENTLY AND IRREVERSIBLY release a phone number back to the carrier. THIS CANNOT BE UNDONE: the number leaves the workspace, is returned to the carrier pool, and CANNOT be recovered or reclaimed. Inbound calls and SMS to it STOP IMMEDIATELY, and its monthly rent stops (releasedAt is set). Only call this to permanently decommission a number you are certain you no longer want — there is no undo. Free, but destructive.

ActionTry it

Revoke Consent

Revoke a contact's TCPA consent for a given Saperly number, blocking further outbound contact to them. CALL THIS WHEN A RECIPIENT SAYS 'STOP' / 'UNSUBSCRIBE' / 'do not contact me' — honoring an opt-out is a legal compliance obligation, and this is the primary legitimate use. OBSERVABLE EFFECT: once revoked, SAPERLY_SEND_SMS and SAPERLY_PLACE_CALL to this contact from this number are REFUSED (403 RecipientOptedOut) until consent is re-recorded with SAPERLY_RECORD_CONSENT. Consent records are an immutable audit trail: this does NOT delete the record — it marks it revoked by stamping a revokedAt timestamp, preserving the compliance history. Identify the contact by numberId (your number, from SAPERLY_LIST_NUMBERS) and peerNumber (the contact's E.164 number); no consentType is required. Pass idempotency_key to make retries safe. Returns { status: 'revoked' }. Free.

ActionTry it

Send SMS

PAID / METERED: send a single SMS from one of your Saperly numbers to an E.164 destination. This SPENDS REAL MONEY and sends a REAL text message to a REAL phone (~2 cents per 160-character segment; a long body is split into multiple segments, each billed). TCPA CONSENT GATE (required): the API refuses to send unless the recipient has an active consent record (or messaged you within the last 24h). For cold outbound you MUST first call SAPERLY_RECORD_CONSENT for the destination, and you can verify it with SAPERLY_CHECK_CONSENT — otherwise this fails with 403 RecipientOptedOut / compliance. Before sending, confirm sufficient funds via SAPERLY_GET_USAGE (balanceCents). Pass idempotency_key to prevent a double-send on retry. Returns 201 with the queued message (id, status, segments). NOTE the response echoes the sending number as 'numberId' and 'from_number' (not 'fromNumberId'). Fails 402 (InsufficientFunds / SpendLimitExceeded), 400 (DestinationNotSupported / invalid request).

ActionTry it

Set Number Caller ID Name

Set the outbound caller ID name / CNAM (1-15 characters: letters, digits, spaces) presented to recipients on outbound calls from a Saperly phone number, or pass callerIdName=null to CLEAR it. callerIdName is required — supply a name to set it, or null to unset it. Returns the updated number object. Note: CNAM display depends on the destination carrier and does not propagate instantly, so recipients may not see the change immediately. Free.

ActionTry it

Set Number SMS Sender ID

Set the alphanumeric SMS sender id (1-11 alphanumeric chars, e.g. a brand name) shown as the 'from' on outbound SMS from this number, or pass smsSenderId=null to CLEAR it. Returns the updated number object. NOTE: sender-id support and display vary by destination country/carrier (the US and Canada notably restrict alphanumeric sender ids). Free.

ActionTry it

Set Number Webhook

Set the HTTPS webhook URL that Saperly POSTs this number's events (inbound SMS/calls, status) to. The url is required and must be https://. Returns the updated number object. NOTE: this endpoint has no way to clear the URL back to null — once set it can only be changed to another URL, so set it deliberately. Free.

ActionTry it

Transfer Call

PAID / METERED — BLIND-transfers a LIVE, in-progress voice call to another destination `to` (an E.164 number like +15551230000, or a `sip:` URI). BLIND means the call is handed off UNCONDITIONALLY: there is NO confirmation from the transferee and the AI agent LOSES CONTROL of the call once transferred — treat it as a one-way, irrecoverable handoff. Only meaningful on a call that is actually connected/in-progress (identify it via SAPERLY_PLACE_CALL or SAPERLY_LIST_CALLS). The transferred leg KEEPS BILLING per minute, so this is not free — the meter runs on the new leg until the call ends. Returns the call object with its updated status; `durationSec` / `costCents` stay NULL until the call settles (null does NOT mean it was free). Pass `idempotency_key` on retries to avoid starting a second transfer leg. Fails 502 CallStartFailed if the transfer leg cannot be started, and 404 if the call id is unknown.

ActionTry it

Update Connection

Partially update a connection (the AI answering brain bound to a number). Send only the fields you want to change (name, mode, instructions, llm, tts, language, mcpServers, callControl, complianceEnabled, smsAutoReply, disclosure, manualWebhookUrl); every unset field is left untouched. Send mcpServers=[] to clear all tools, or manualWebhookUrl="" to clear it. Writing RE-SYNCS the carrier, so an update has side effects beyond the stored record. Returns 200 with the full updated connection. Free.

ActionTry it

How the Saperly integration works

The Saperly integration connects your Dench AI CRM directly to Saperly, so agents can read and act on your Saperly data as part of everyday work — answering questions in chat, keeping your CRM in sync, and running automations without anyone copying data between tools.

30 actions are available for agents to invoke on your behalf. Every call runs through Saperly's own authorization, scoped to the account you connect.

Set up Saperly in Dench

  1. 1

    Sign in to your Dench workspace and open Integrations.

  2. 2

    Find Saperly and click Connect — you'll authorize access through Saperly's own sign-in flow. No API keys or code required.

  3. 3

    Ask an agent to use Saperly in chat, or call it from an automation.

  4. 4

    Manage or disconnect the connection any time from workspace settings.

Frequently asked questions

How does the Saperly integration work with Dench?

The Dench Saperly integration connects your AI CRM to Saperly, so AI agents can work with your Saperly data as part of chats, automations, and CRM workflows. You connect your account once, and every agent in your workspace can use it — governed by your workspace permissions.

What actions can AI agents perform with Saperly via Dench?

The Saperly integration currently exposes 30 actions, including Bind Connection to Number, Check Consent, Create Connection, Delete Connection, End Call, and Get Call. Agents invoke them on your behalf from chat or from automations.

Do I need to write code to connect Saperly to Dench?

No. You connect Saperly from your Dench workspace using Saperly's own sign-in and authorization flow — no API keys to copy, no glue code to maintain.

Is the Saperly integration secure?

Connections are authorized through Saperly's own authentication flow, and Dench stores only the authorization needed to act on your behalf. You can review and disconnect the Saperly connection from your workspace settings at any time.

Saperly | Dench AI CRM