Skip to content
A2PCheck
A2PCheck/API Docs

A2P 10DLC pre-scan API

Add A2P 10DLC campaign pre-scanning to your messaging workflows: validate descriptions, sample messages, opt-in flows, and policy URLs over JSON — one campaign per call, scripted across your pipeline — before they're registered through Twilio, Plivo, Vonage, or any other provider.

The API checks campaign readiness; registration itself always happens with your provider. New to the review process? Start with what A2P verification means, or try a one-off scan in the free scanner.

Machine-readable specs are published: /openapi.json (OpenAPI 3.1) and /llms-full.txt (full field reference for AI agents). Building an agent or coding harness? See the agent guide.

Wiring the API into a provider-specific flow? See what each provider's registration reviews before you script the submission: Twilio, Plivo, Vonage, or the full provider list. The API checks readiness; registration stays with your provider.

For agencies, consultants & platform teams

If you register A2P 10DLC campaigns on behalf of clients — or your product onboards businesses that do — use the API to pre-scan every campaign before it reaches Twilio / TCR. Common patterns: gate submission on a GREEN report, surface per-field findings inline in your onboarding form, or store the scan output for client audit trails.

Create a self-serve API key from your developer dashboard and pass it as a bearer token for headless / API access. Scans run against your account and spend the same credits as browser scans: one for Basic and two for Full. There is no separate key fee or API subscription. Compare public prices. Anonymous/basic validation still works without a key for low-volume checks.

Create an API key

Authentication

Bearer auth is optional for Basic only. Explicit Full without a key returns 401 AUTH_REQUIRED, not a downgrade. Authenticated Basic uses one credit; Full uses two. A human must approve tier, cost and total budget before any authenticated call. Create a self-serve key from your developer dashboard and send it as a bearer token to run full scans against your account's credits. The full key is shown once at creation — we store only a hash, so save it then.

Authorization: Bearer a2p_live_your_api_key_here

Endpoints

POST/api/agent/validate

Stable JSON endpoint for AI agents and coding harnesses. Body: { tier?, campaign, campaignName?, idempotencyKey? }. Omitted tier defaults to Basic; requesting Full requires auth. Success wraps the verdict under result.overallTier, with scanId, reused, and creditsSpent outside the report. Documented in /openapi.json.

NOTE/api/v1/scan · /api/v1/scan/quick

These are the underlying worker routes used by the hosted app. Agents should prefer /api/agent/validate, which keeps the payload stable and same-origin.

Campaign object

These fields belong inside the required campaign object, not directly at the top of the POST body. See the complete examples below. Exact use-case values, including TWO_FACTOR_AUTH, are listed in the OpenAPI contract.

{
  "useCaseType": "MARKETING",          // required
  "campaignDescription": "...",         // required
  "sampleMessages": ["msg1", "msg2"],   // required, 2-5 items
  "messageFlow": "...",                 // required
  "businessName": "Acme Inc",           // optional
  "privacyPolicyUrl": "https://...",    // optional
  "websiteUrl": "https://...",          // optional
  "termsOfServiceUrl": "https://...",   // optional
  "optInKeywords": ["START"],           // optional
  "optOutKeywords": ["STOP"],           // optional
  "helpKeywords": ["HELP"],             // optional
  "optInMessage": "...",                // optional
  "optOutMessage": "...",               // optional
  "helpMessage": "...",                 // optional
  "embeddedLinks": true,                // optional
  "embeddedPhoneNumbers": false,        // optional
  "ageGatedContent": false,             // optional
  "directLending": false,               // optional
  "numberPool": false                   // optional
}

Anonymous Basic example

Fictional request, not an approved campaign. Basic does not fetch external URLs.

curl --fail-with-body --max-time 75 -sS -X POST https://www.a2pcheck.com/api/agent/validate \
  -H "Content-Type: application/json" \
  -d '{
  "tier": "basic",
  "campaign": {
    "useCaseType": "MARKETING",
    "businessName": "Acme Coffee Co.",
    "campaignDescription": "Acme Coffee Co. sends weekly promotional offers and new-product announcements to customers who opt in at checkout or on our website. Messages link to acme.example.com and always include opt-out instructions.",
    "sampleMessages": [
      "Acme Coffee: 20% off all beans this week. Shop acme.example.com/sale. Msg&data rates may apply. Reply STOP to opt out, HELP for help.",
      "Acme Coffee: New single-origin just dropped. Browse acme.example.com/new. Reply STOP to unsubscribe."
    ],
    "messageFlow": "Customers opt in by checking an unchecked SMS-consent box at checkout on acme.example.com or by texting START to our number. Consent is not a condition of purchase.",
    "privacyPolicyUrl": "https://acme.example.com/privacy",
    "websiteUrl": "https://acme.example.com",
    "termsOfServiceUrl": "https://acme.example.com/terms",
    "optInKeywords": [
      "START"
    ],
    "optOutKeywords": [
      "STOP"
    ],
    "helpKeywords": [
      "HELP"
    ],
    "optInMessage": "Acme Coffee: You'"'"'re subscribed to weekly offers. Reply STOP to opt out, HELP for help. Msg&data rates may apply.",
    "optOutMessage": "Acme Coffee: You'"'"'re unsubscribed and won'"'"'t receive more messages. Reply START to rejoin.",
    "helpMessage": "Acme Coffee: For help, email [email protected]. Reply STOP to opt out.",
    "embeddedLinks": true,
    "embeddedPhoneNumbers": false
  }
}'

Authenticated Full example

Replace fictional facts/URLs before spending. Get explicit approval for one paid request; another scan needs renewed approval. Supply A2PCHECK_API_KEY securely from your environment. Set A2PCHECK_REQUEST_ID to a unique per-version ID (1–128 letters, digits, hyphens or underscores); the example sends it as idempotencyKey. Retain it only for the exact same campaign version/tier when retrying; successful same-key replays within 24 hours are not charged again. Failed/refunded scans can be billed again. Do not enable automatic paid retries. See the agent guide for the full workflow.

: "${A2PCHECK_API_KEY:?Set your API key securely before running a paid scan}"
: "${A2PCHECK_REQUEST_ID:?Set a unique ID for this exact campaign version; retain it only for retries}"
case "$A2PCHECK_REQUEST_ID" in
  *[!A-Za-z0-9_-]*) printf '%s\n' "Request ID must contain only letters, digits, underscores or hyphens." >&2; exit 1 ;;
esac
if [ "${#A2PCHECK_REQUEST_ID}" -gt 128 ]; then
  printf '%s\n' "Request ID must be at most 128 characters." >&2
  exit 1
fi
curl --fail-with-body --max-time 75 -sS -X POST https://www.a2pcheck.com/api/agent/validate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $A2PCHECK_API_KEY" \
  -d '{
  "tier": "full",
  "campaign": {
    "useCaseType": "MARKETING",
    "businessName": "Acme Coffee Co.",
    "campaignDescription": "Acme Coffee Co. sends weekly promotional offers and new-product announcements to customers who opt in at checkout or on our website. Messages link to acme.example.com and always include opt-out instructions.",
    "sampleMessages": [
      "Acme Coffee: 20% off all beans this week. Shop acme.example.com/sale. Msg&data rates may apply. Reply STOP to opt out, HELP for help.",
      "Acme Coffee: New single-origin just dropped. Browse acme.example.com/new. Reply STOP to unsubscribe."
    ],
    "messageFlow": "Customers opt in by checking an unchecked SMS-consent box at checkout on acme.example.com or by texting START to our number. Consent is not a condition of purchase.",
    "privacyPolicyUrl": "https://acme.example.com/privacy",
    "websiteUrl": "https://acme.example.com",
    "termsOfServiceUrl": "https://acme.example.com/terms",
    "optInKeywords": [
      "START"
    ],
    "optOutKeywords": [
      "STOP"
    ],
    "helpKeywords": [
      "HELP"
    ],
    "optInMessage": "Acme Coffee: You'"'"'re subscribed to weekly offers. Reply STOP to opt out, HELP for help. Msg&data rates may apply.",
    "optOutMessage": "Acme Coffee: You'"'"'re unsubscribed and won'"'"'t receive more messages. Reply START to rejoin.",
    "helpMessage": "Acme Coffee: For help, email [email protected]. Reply STOP to opt out.",
    "embeddedLinks": true,
    "embeddedPhoneNumbers": false
  },
  "idempotencyKey": "'"$A2PCHECK_REQUEST_ID"'"
}'

Error Codes

StatusCodeDescription
400BAD_REQUESTMalformed body / invalid tier / missing campaign
401INVALID_API_KEYAPI key is missing, unknown, or revoked
401AUTH_REQUIREDThis scan tier needs a signed-in account or key
402INSUFFICIENT_CREDITSAccount needs more scan credits
429ANON_SCAN_LIMITAnonymous per-IP daily limit hit
429RATE_LIMITEDScanner busy; respect the returned retry delay
400 / 5xxSCAN_FAILEDReport failure; confirm status and budget before a paid retry

Headless API access

Self-serve API keys are live. Create one from your developer dashboard and send it as a bearer token. The anonymous basic endpoint still works without a key for low-volume agent checks.

Create an API key