Compliance and Consent

If you are calling real people, this page matters as much as the API reference.

Saperly gives you disclosure, consent records, and audit logs. Use them deliberately.

Compliance is opt-in and off by default. Set compliance_enabled: true when creating a line to enable disclosure playback and consent checks. You can always turn it on later.

Liability shift when compliance_enabled is false. Saperly does NOT verify consent, play AI disclosures, or block outbound calls to numbers that have not opted in unless you explicitly enable compliance per line. With the flag off, compliance with TCPA, GDPR, CASL, the EU AI Act, and any other applicable telecom or privacy regulation is the customer’s responsibility. If you are placing outbound calls to consumers in regulated jurisdictions, turn compliance_enabled on and grant consent records via POST /v1/consent before dialing.

Disclosure

Saperly can play an AI disclosure at the start of a call.

Create one:

$curl -X POST https://saperly.com/api/v1/disclosures \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "message": "This call uses an AI assistant."
> }'

Outbound calls require recorded consent first.

Grant it:

$curl -X POST https://saperly.com/api/v1/consent \
> -H "Authorization: Bearer sk_live_..." \
> -H "Content-Type: application/json" \
> -d '{
> "line_id": "LINE_ID",
> "phone_number": "+14155551234",
> "consent_type": "explicit_outbound",
> "source": "web_form"
> }'

Check it:

$curl "https://saperly.com/api/v1/consent?phone_number=%2B14155551234&line_id=LINE_ID" \
> -H "Authorization: Bearer sk_live_..."

Revoke it:

$curl -X DELETE "https://saperly.com/api/v1/consent?phone_number=%2B14155551234&line_id=LINE_ID" \
> -H "Authorization: Bearer sk_live_..."

Two consent types exist:

  • explicit_outbound — required for outbound calls. Grant this via POST /api/v1/consent before placing an outbound call to a new number.
  • implied_inbound — automatically recorded the first time a number texts your line. This lets you reply to inbound SMS within a 24-hour window without granting consent manually.

The source field is free-text for your records (e.g., “signup_form”, “verbal_confirmation”, “email_opt_in”, “inbound_sms”).

Pre-call checks

When you place an outbound call, Saperly runs automatic checks:

1

Balance check

Is there enough balance (or a postpaid card on file) to start a call? Outbound calls reserve 13 cents of voice up front.
3

Disclosure check

If compliance is enabled, is a disclosure configured?

If any check fails, the call is blocked and a pre_call_check_blocked compliance event is recorded.

Audit trail

Use the compliance audit endpoints to answer “what happened?” later.

$curl "https://saperly.com/api/v1/compliance/audit?line_id=LINE_ID" \
> -H "Authorization: Bearer sk_live_..."

Events to watch

  • disclosure_played
  • consent_collected
  • consent_revoked
  • call_started
  • call_ended
  • pre_call_check_passed
  • pre_call_check_blocked

Test compliance flows

3

Verify audit trail

GET /api/v1/compliance/audit should show both the blocked and successful attempts.
4

Revoke and re-test

DELETE /api/v1/consent, try calling again. Expect 403.

Destination safety

Independently of compliance_enabled, Saperly applies a thin destination safety check on POST /v1/calls, POST /v1/calls/conversation, and POST /v1/messages. This is a small abuse-prevention net, not a geographic restriction.

Allowed: any valid E.164 destination, including international (UK +44, Israel +972, Mexico +52, China +86, etc.) and Caribbean +1 (Jamaica +1 876, Dominican Republic +1 809, Bermuda +1 441, etc.).

Blocked: only abuse-pure US destinations:

  • Premium-rate NPAs: 500, 900, 976
  • Carrier service code: 700
  • N11 service codes: 211, 311, 411, 511, 611, 711, 811, 911

Blocked destinations return 400 destination_not_allowed in the canonical envelope { error: { code, message, details: [{ field: "to_number", message: "<reason>" }] } }. The reason is one of blocked_premium or blocked_service. (Non-E.164 input is rejected earlier by schema validation as 422 validation_error, so it never reaches the allowlist.) The check runs before the consent and disclosure pre-call checks, so abuse traffic does not pollute your compliance audit trail.

Destination tiers are live as of v0.5.1.0 — see Voice zones and SMS zones for the full table.

Product advice

Do not bolt compliance on after the demo works.

Put consent collection in the real user flow early. Then confirm your audit trail is queryable before you start scale testing outbound traffic.