Home Blog SMS Verification API Guide for Developers - PapSMS
Developer

SMS Verification API Guide for Developers - PapSMS

PapSMS Team April 19, 2026 Updated April 19, 2026 12 min read

Modern applications require phone number verification to prevent fake accounts, reduce fraud, and secure user access. But building SMS verification infrastructure from scratch — carrier agreements, international routing, delivery tracking — takes months. An SMS verification API lets developers add phone verification to any app in minutes with a few lines of code. This guide covers everything you need to know about SMS verification APIs, from architecture to implementation, with working code examples.

What Is an SMS Verification API?

An SMS verification API is a RESTful (or gRPC) service that handles the entire phone verification flow programmatically. You send a request with a phone number, the API sends a verification code via SMS, and you verify the code the user enters against the API. No telecom contracts, no gateway setup, no international carrier negotiations.

A well-designed SMS verification API provides three core endpoints:

  • Request — Receive a virtual number and trigger SMS reception
  • Status — Poll for the incoming code or set up webhooks
  • Release/Cancel — Release the number back to the pool or cancel an unused verification

SMS Verification API vs Rolling Your Own

Capability SMS API (PapSMS) Build Yourself
Setup time15 minutes3-6 months
Upfront cost$0$50,000+
Per-SMS cost$0.10 - $3.00$0.005 - $0.05 (at scale)
Countries supported85+ out of the boxNegotiate each carrier
Delivery rate95%+ managedVaries, needs tuning
MaintenanceZeroDedicated team
Compliance (GDPR, TCPA)HandledYour responsibility
Best for<100k verifications/monthMillions/month at scale

For most applications, using an SMS verification API is the correct choice until you reach massive scale. Only companies sending millions of SMS per month see cost benefits from building internal infrastructure.

PapSMS API Overview

The PapSMS API provides programmatic access to virtual phone numbers for verification purposes. It is designed for developers building:

  • Testing frameworks — Automated testing of signup flows that require phone verification
  • QA pipelines — Verifying third-party integrations that send SMS
  • Multi-account managers — Applications managing multiple verified accounts across platforms
  • Bulk verification tools — Services that need to verify many accounts programmatically

Authentication

All API requests use an API key passed in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Get your API key from your account dashboard after signing up. Keys should be stored in environment variables, never committed to source control.

Base URL

https://papsms.com/api/v1/

Core API Endpoints

1. Purchase a Virtual Number

Request a virtual number for a specific service and country:

POST /api/v1/numbers/purchase
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "country": "us",
  "service": "whatsapp"
}

Response:

{
  "success": true,
  "data": {
    "activation_id": "12345678",
    "phone_number": "+14155550123",
    "country": "us",
    "service": "whatsapp",
    "expires_at": "2026-04-19T15:30:00Z",
    "cost": 0.80
  }
}

2. Check SMS Status

Poll for the incoming SMS code:

GET /api/v1/numbers/status/12345678
Authorization: Bearer YOUR_API_KEY

Response while waiting:

{
  "success": true,
  "data": {
    "status": "waiting",
    "sms": null
  }
}

Response after SMS received:

{
  "success": true,
  "data": {
    "status": "received",
    "sms": {
      "code": "847291",
      "full_text": "Your WhatsApp code: 847291",
      "received_at": "2026-04-19T14:35:22Z"
    }
  }
}

3. Cancel or Complete Activation

POST /api/v1/numbers/finish/12345678
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "status": "completed"
}

Use status: "completed" if the code was received and used successfully, or status: "cancelled" to cancel an unused activation and get a partial refund.

Code Examples

Python

import requests
import time
import os

API_KEY = os.environ["PAPSMS_API_KEY"]
BASE_URL = "https://papsms.com/api/v1"

def verify_phone(service: str, country: str = "us") -> str:
    """Request a virtual number and wait for SMS code."""
    headers = {"Authorization": f"Bearer {API_KEY}"}

    # 1. Purchase a number
    resp = requests.post(
        f"{BASE_URL}/numbers/purchase",
        json={"country": country, "service": service},
        headers=headers,
    )
    resp.raise_for_status()
    activation = resp.json()["data"]
    print(f"Got number: {activation['phone_number']}")

    # 2. Use the number in your signup flow
    # ... your code to submit the number to the target service ...

    # 3. Poll for the SMS code
    activation_id = activation["activation_id"]
    for _ in range(60):  # Poll for 60 seconds
        resp = requests.get(
            f"{BASE_URL}/numbers/status/{activation_id}",
            headers=headers,
        )
        data = resp.json()["data"]
        if data["status"] == "received":
            code = data["sms"]["code"]
            # 4. Mark as completed
            requests.post(
                f"{BASE_URL}/numbers/finish/{activation_id}",
                json={"status": "completed"},
                headers=headers,
            )
            return code
        time.sleep(2)
    raise TimeoutError("SMS code did not arrive")

# Usage
code = verify_phone(service="whatsapp", country="us")
print(f"Verification code: {code}")

Node.js

const axios = require("axios");

const API_KEY = process.env.PAPSMS_API_KEY;
const BASE_URL = "https://papsms.com/api/v1";
const client = axios.create({
  baseURL: BASE_URL,
  headers: { Authorization: `Bearer ${API_KEY}` },
});

async function verifyPhone(service, country = "us") {
  // 1. Purchase number
  const { data: purchase } = await client.post("/numbers/purchase", {
    country,
    service,
  });
  const { activation_id, phone_number } = purchase.data;
  console.log(`Got number: ${phone_number}`);

  // 2. Use number in signup flow...

  // 3. Poll for SMS
  for (let i = 0; i < 60; i++) {
    const { data: status } = await client.get(
      `/numbers/status/${activation_id}`
    );
    if (status.data.status === "received") {
      await client.post(`/numbers/finish/${activation_id}`, {
        status: "completed",
      });
      return status.data.sms.code;
    }
    await new Promise((r) => setTimeout(r, 2000));
  }
  throw new Error("SMS timeout");
}

// Usage
verifyPhone("whatsapp", "us").then(console.log);

PHP

<?php
$apiKey = getenv("PAPSMS_API_KEY");
$baseUrl = "https://papsms.com/api/v1";

function apiRequest($method, $endpoint, $data = null) {
    global $apiKey, $baseUrl;
    $ch = curl_init($baseUrl . $endpoint);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Authorization: Bearer $apiKey",
        "Content-Type: application/json",
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    }
    $response = curl_exec($ch);
    curl_close($ch);
    return json_decode($response, true);
}

// Purchase
$purchase = apiRequest("POST", "/numbers/purchase", [
    "country" => "us",
    "service" => "whatsapp",
]);
$activationId = $purchase["data"]["activation_id"];
echo "Number: " . $purchase["data"]["phone_number"] . PHP_EOL;

// Poll
for ($i = 0; $i < 60; $i++) {
    $status = apiRequest("GET", "/numbers/status/$activationId");
    if ($status["data"]["status"] === "received") {
        echo "Code: " . $status["data"]["sms"]["code"] . PHP_EOL;
        apiRequest("POST", "/numbers/finish/$activationId", [
            "status" => "completed",
        ]);
        break;
    }
    sleep(2);
}

Best Practices

Production Integration Tips

  • Use webhooks when possible — Polling wastes API calls. Configure webhook URLs to receive SMS events in real-time
  • Handle timeouts gracefully — Always set a maximum wait time (60-120 seconds) and release unused numbers
  • Store activation IDs — Keep track of active verifications in your database for debugging and recovery
  • Implement retry logic — If a number fails, try a different country or service-specific number
  • Cache country availability — Check /api/v1/countries once per hour rather than per request
  • Use environment variables — Never hardcode API keys. Use .env files and process environment
  • Monitor your usage — Track API calls and spending via the dashboard to catch anomalies

Security Considerations

  • API key rotation — Rotate keys every 90 days and immediately if suspected compromised
  • IP whitelisting — Restrict API key usage to your server IPs when possible
  • Rate limiting on your side — Prevent abuse by rate-limiting verification requests per user
  • Log for audit — Log all verification attempts for compliance and debugging
  • Handle errors safely — Do not expose API errors directly to end users — log internally and show generic messages

Common Use Cases

Automated QA Testing

QA teams testing signup flows that require phone verification can use the API to programmatically acquire verified accounts. This enables full end-to-end testing including the phone verification step, which would otherwise require manual intervention.

Test Account Provisioning

Development and staging environments need verified accounts that match production conditions. An SMS API provides fresh verified accounts on demand without needing real phone numbers for every developer.

Multi-Tenant Applications

SaaS applications offering "verified account" features to their customers can integrate PapSMS to provide verified accounts as a service. See our SMS verification service guide for business model examples.

Market Research Tools

Tools that analyze app signup flows, verification requirements, or regional availability differences use SMS APIs to programmatically interact with target services while maintaining clean account separation.

Pricing & Rate Limits

PapSMS API pricing is pay-as-you-go with no monthly commitment:

  • Per-verification — $0.10 to $3.00 depending on country and service
  • No API subscription fee — You only pay for successful verifications
  • Partial refunds — Cancelled verifications (no SMS received) are automatically refunded
  • Rate limits — 60 requests per minute default, higher limits available on request
  • Volume discounts — Custom pricing for >10,000 verifications/month

Start Building with PapSMS API

Free API key, 85+ countries, 5600+ services supported. Pay only for successful verifications.

Get Free API Access

Frequently Asked Questions

Is there a free tier for testing the API?

PapSMS does not offer free SMS (real verifications cost real money), but new accounts can test the API with a small deposit ($5) which is enough for 50+ verifications in cheaper countries like India or Indonesia. The documentation endpoints are freely accessible.

What is the API's uptime and reliability?

The PapSMS API targets 99.9% uptime with geographically distributed infrastructure. SMS delivery rates vary by country (85-95%+) and target service. The status page shows real-time availability and live statistics display current delivery rates per service.

Does the API support webhooks?

Yes. Instead of polling /status endpoint, configure a webhook URL in your account settings. The API will POST to your webhook when an SMS arrives, including the activation ID, code, and full message text. This reduces API calls and provides instant notifications.

Can I use the API for WhatsApp Business verification?

Yes. PapSMS supports WhatsApp, WhatsApp Business, and the WhatsApp Business API platform verifications. See our WhatsApp verification guide for details on country-specific success rates.

How do I handle rate limits in production?

The default rate limit is 60 requests/minute. Implement exponential backoff when you receive a 429 response. For high-volume applications (>1000 verifications/hour), contact support to increase your rate limit. Batch operations and webhooks reduce the need for high rate limits.

Share this article:

Ready to Get Started?

Create your free account and get a virtual number in 30 seconds.

Start Now — It's Free