Skip to main content
DTMF confirmation calls a phone number, plays a TTS prompt, and collects a single keypress (1) to confirm ownership. No verification code is generated — the keypress is the confirmation. The POST /verifications/{id}/actions/verify endpoint is not used. Verification completes on the call itself.
DTMF confirmation is unique to Telnyx — Twilio and Vonage Verify APIs only support code-based voice verification (read a code, then type it). Single-keypress confirmation reduces user friction and works on landlines.

Flow

OutcomeTriggerStatus
ConfirmedDigit 1 pressedaccepted
RejectedWrong digitinvalid
Timed outNo keypress (10s)expired
FailedCall not answerederror
Up to 3 attempts per call. After 3 wrong digits, the call ends with status invalid.

Use cases

Caller ID verification

Confirm ownership before allowing a number as outbound Caller ID.

Landline verification

Verify numbers that cannot receive SMS.

Accessibility

Single keypress instead of reading and typing a code.

Account recovery

Confirm phone ownership without code entry.

Create a verify profile

Create a profile with dtmf_confirm settings. This can be combined with other verification types (SMS, call) on the same profile.
curl -X POST https://api.telnyx.com/v2/verify_profiles \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -d '{
    "name": "caller-id-verification",
    "language": "en-US",
    "dtmf_confirm": {
      "default_timeout_secs": 300
    }
  }'
The returned id is required for verification requests.

Trigger verification

curl -X POST https://api.telnyx.com/v2/verifications/dtmf_confirm \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -d '{
    "phone_number": "+13035551234",
    "verify_profile_id": "YOUR_PROFILE_ID"
  }'

Response

{
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "phone_number": "+13035551234",
    "record_type": "verification",
    "status": "pending",
    "type": "dtmf_confirm",
    "timeout_secs": 300,
    "verify_profile_id": "YOUR_PROFILE_ID",
    "created_at": "2026-02-20T15:30:00.000000",
    "updated_at": "2026-02-20T15:30:00.000000"
  }
}
Default TTS prompt:
“This is a verification call to confirm that this phone number is going to be used as a Caller ID for outbound calls. If you did not request this verification, or if someone is asking you to accept this call, please ignore this message. If you did request this verification, please press 1.”
The TTS language is determined by the language field on the Verify Profile (default: en-US).

Handle the result

Verification completes on the call — no verify endpoint call needed. Receive the outcome via webhooks.

Accepted (digit 1 pressed)

{
  "data": {
    "event_type": "verification.complete",
    "payload": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "phone_number": "+13035551234",
      "status": "accepted",
      "type": "dtmf_confirm",
      "verify_profile_id": "YOUR_PROFILE_ID"
    }
  }
}

Failed (wrong digit, timeout, or call failure)

{
  "data": {
    "event_type": "verification.complete",
    "payload": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "phone_number": "+13035551234",
      "status": "invalid",
      "type": "dtmf_confirm",
      "verify_profile_id": "YOUR_PROFILE_ID"
    }
  }
}

Polling alternative

curl https://api.telnyx.com/v2/verifications/{verification_id} \
  -H "Authorization: Bearer $TELNYX_API_KEY"

Complete example

Full flow: create profile, trigger verification, handle webhook.
import os
import telnyx
from flask import Flask, request, jsonify

telnyx.api_key = os.environ["TELNYX_API_KEY"]
app = Flask(__name__)

# Create profile (once)
profile = telnyx.VerifyProfile.create(
    name="dtmf-verification",
    language="en-US",
    dtmf_confirm={"default_timeout_secs": 300},
)

# Trigger verification
verification = telnyx.Verification.create(
    phone_number="+13035551234",
    verify_profile_id=profile.id,
    type="dtmf_confirm",
)
print(f"Verification {verification.id}{verification.status}")


@app.route("/webhooks/verify", methods=["POST"])
def handle_webhook():
    payload = request.json["data"]["payload"]

    if payload["status"] == "accepted":
        print(f"✅ {payload['phone_number']} verified")
    else:
        print(f"❌ {payload['phone_number']} failed: {payload['status']}")

    return jsonify({"status": "ok"}), 200


app.run(port=5000)

Verification type comparison

FeatureSMSCallFlash CallDTMF Confirm
User actionType codeListen + type codeNonePress 1
Code generatedYesYesYes (caller ID)No
Verify endpointRequiredRequiredRequiredNot needed
Landline supportNoYesNoYes
Fraud riskSIM swap, interceptionLowLowLow
Competitor supportTwilio, VonageTwilio, VonageTwilioTelnyx only

Troubleshooting

Verification times out with status expired. Implement a retry with delay, or fall back to SMS.
Up to 3 attempts per call. After 3 failures, status is invalid. Trigger a new verification to retry.
Call was not answered and no webhook received. Verify the webhook URL is configured and reachable. Poll the status endpoint as fallback.
The prompt is fixed to the standard verification message. Voice and language are determined by the Verify Profile’s language setting. Custom prompt text is not yet supported.
Standard Verify API rate limits apply. Avoid triggering multiple concurrent verifications for the same phone number — the previous call must complete or time out first.

Next steps