Skip to main content
If you’re an ISV, reseller, or SaaS platform sending messages on behalf of your customers, you need a partner campaign architecture — not a standard 10DLC registration. This guide covers everything from initial setup through production messaging.

Who needs this guide?

ScenarioYou are…Your architecture
SaaS platformBuilding messaging into your productPartner campaign (shared across customers)
Reseller / agencyManaging messaging for clientsOne brand + campaign per client, or shared
ISVOffering white-label messagingPartner campaign with downstream CSPs
Franchise systemCentral brand, many locationsOne brand, multiple campaigns per location
Direct customer? If you’re sending messages for your own business only, use the standard 10DLC quickstart instead.

Architecture overview

ISV/reseller 10DLC uses a shared campaign model where you register campaigns with your upstream CSP (Campaign Service Provider) and share them to Telnyx for number assignment and messaging.

Key concepts

Upstream CSP

The Campaign Service Provider where you register brands and campaigns with TCR. This could be Telnyx (if you register directly) or another CSP.

Downstream CSP

The messaging provider that sends traffic. Telnyx acts as your downstream CSP — you share campaigns to Telnyx for number assignment.

Shared / Partner Campaign

A campaign registered at one CSP and shared to another for traffic delivery. Required for ISV architectures.

Campaign Sharing

The TCR process of granting a downstream CSP access to send traffic for a campaign. Sharing must be accepted by the downstream CSP.

Native vs. partner campaigns

FeatureNative CampaignPartner (Shared) Campaign
RegistrationDirectly on TelnyxOn upstream CSP, shared to Telnyx
Brand ownershipYour Telnyx accountYour upstream CSP account
Campaign managementTelnyx APIUpstream CSP + Telnyx Partner API
Number assignmentStandardVia partner campaign endpoints
Use caseDirect customerISV, reseller, multi-tenant
Appeal processDirect APICSP nudge mechanism

Prerequisites

Before starting, ensure you have:
1

Telnyx account with messaging enabled

Sign up and complete account verification. You need a Level 2 verified account.
2

Upstream CSP account

An account with a CSP where you’ll register brands and campaigns (this can be Telnyx or another provider like Campaign Registry direct access).
3

Customer business information

For each customer: legal business name, EIN/tax ID, business address, website, authorized representative contact, and messaging use case details.
4

Phone numbers

10DLC-eligible long code numbers on your Telnyx account. Purchase numbers or use existing inventory.

Step-by-step ISV onboarding

Step 1: Register brands for each customer

Each of your customers needs their own brand registered with TCR. A brand represents a business entity.
If using Telnyx as your upstream CSP, register brands directly:
curl -X POST https://api.telnyx.com/v2/10dlc/brand \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "PRIVATE_PROFIT",
    "companyName": "Customer Corp LLC",
    "ein": "12-3456789",
    "einIssuingCountry": "US",
    "phone": "+12025551234",
    "street": "123 Main St",
    "city": "New York",
    "state": "NY",
    "postalCode": "10001",
    "country": "US",
    "email": "compliance@customercorp.com",
    "website": "https://customercorp.com",
    "vertical": "TECHNOLOGY",
    "displayName": "Customer Corp"
  }'

Step 2: Submit brand for vetting

Higher vetting scores unlock greater throughput. For ISV use cases, enhanced vetting is strongly recommended.
curl
curl -X POST https://api.telnyx.com/v2/10dlc/brand/{brandId}/vetting \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vettingClass": "ENHANCED"}'
Enhanced vetting costs a one-time fee and takes 1–7 business days. Brands with vetting scores above 75 get significantly higher throughput. See 10DLC Rate Limits for details.

Step 3: Create campaigns with the ISV use case

For ISV architectures, use the AGENTS_FRANCHISES use case type when registering campaigns:
curl -X POST https://api.telnyx.com/v2/10dlc/campaign \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brandId": "BRAND_ID",
    "usecase": "AGENTS_FRANCHISES",
    "description": "Platform notifications sent on behalf of Customer Corp customers",
    "sample1": "Hi {name}, your appointment is confirmed for {date} at {time}. Reply STOP to opt out.",
    "sample2": "Your order #{order_id} has shipped! Track at {url}. Reply STOP to unsubscribe.",
    "messageFlow": "Users opt in via web form at customercorp.com/sms-signup with clear consent language. STOP/HELP keywords are honored.",
    "helpMessage": "Customer Corp support: help@customercorp.com or call 1-800-555-0123. Reply STOP to opt out.",
    "optinKeywords": "START,YES,SUBSCRIBE",
    "optoutKeywords": "STOP,CANCEL,UNSUBSCRIBE,QUIT,END",
    "helpKeywords": "HELP,INFO",
    "numberPool": false,
    "subscriberOptin": true,
    "subscriberOptout": true,
    "subscriberHelp": true,
    "embeddedLink": true,
    "embeddedPhone": false
  }'
ISV-specific requirements:
  • Use case must be AGENTS_FRANCHISES for sending on behalf of clients
  • Sample messages must accurately reflect what your platform sends
  • Message flow must describe how end users (not your clients) consent to receive messages
  • Each campaign undergoes manual review by TCR — allow 5–10 business days

Step 4: Share campaign to Telnyx

Once your campaign is approved at your upstream CSP, share it to Telnyx. The sharing process depends on your CSP, but the result is a campaign visible in the Telnyx Partner Campaigns API. After sharing, verify the campaign appears on Telnyx:
# List all shared campaigns
curl -s https://api.telnyx.com/v2/10dlc/partner_campaigns \
  -H "Authorization: Bearer $TELNYX_API_KEY" | python3 -m json.tool

# Get a specific shared campaign
curl -s https://api.telnyx.com/v2/10dlc/partner_campaigns/{campaignId} \
  -H "Authorization: Bearer $TELNYX_API_KEY" | python3 -m json.tool

Step 5: Assign phone numbers to the shared campaign

Once the campaign is accepted by Telnyx, assign your 10DLC numbers to it:
curl -X POST https://api.telnyx.com/v2/10dlc/phone_number_campaigns \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+12025551234",
    "campaignId": "CAMPAIGN_ID"
  }'
Number-to-campaign assignment typically completes within minutes. A number can only be assigned to one campaign at a time. To reassign, remove the existing assignment first.

Step 6: Check sharing status

Monitor whether Telnyx has accepted the shared campaign:
curl
curl -s https://api.telnyx.com/v2/10dlc/partnerCampaign/{campaignId}/sharing \
  -H "Authorization: Bearer $TELNYX_API_KEY" | python3 -m json.tool
Possible sharing statuses:
StatusMeaning
PENDINGCampaign shared, awaiting Telnyx acceptance
ACCEPTEDTelnyx accepted — you can assign numbers and send traffic
DECLINEDTelnyx declined the sharing request

Step 7: Send messages

Once numbers are assigned to the accepted campaign, send messages using the standard Send Message API:
curl
curl -X POST https://api.telnyx.com/v2/messages \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+12025551234",
    "to": "+13035551234",
    "text": "Hi Jane, your appointment is confirmed for March 15 at 2:00 PM. Reply STOP to opt out.",
    "messaging_profile_id": "YOUR_MESSAGING_PROFILE_ID"
  }'

Managing customers at scale

Multi-tenant architecture patterns

Best for: SaaS platforms where all customers send similar message types.One brand (yours) with shared campaigns. All customers’ traffic flows through the same campaign.Trade-off: Simpler setup, but throughput is shared and one customer’s violations affect all.
Your Platform Account
└── Your Brand → Shared Campaign → Numbers [+1xxx, +1yyy, +1zzz]
    ├── Customer A traffic
    ├── Customer B traffic
    └── Customer C traffic

Bulk brand registration

For platforms onboarding many customers, automate brand registration:
Python
import telnyx
import os
import time

telnyx.api_key = os.environ["TELNYX_API_KEY"]

customers = [
    {
        "company_name": "Acme Corp LLC",
        "ein": "12-3456789",
        "email": "admin@acme.com",
        "website": "https://acme.com",
        "phone": "+12025550001",
    },
    {
        "company_name": "Widget Inc",
        "ein": "98-7654321",
        "email": "admin@widget.com",
        "website": "https://widget.com",
        "phone": "+12025550002",
    },
]

results = []
for customer in customers:
    try:
        brand = telnyx.Brand.create(
            entity_type="PRIVATE_PROFIT",
            company_name=customer["company_name"],
            ein=customer["ein"],
            ein_issuing_country="US",
            phone=customer["phone"],
            street="123 Main St",
            city="New York",
            state="NY",
            postal_code="10001",
            country="US",
            email=customer["email"],
            website=customer["website"],
            vertical="TECHNOLOGY",
            display_name=customer["company_name"].split()[0],
        )
        results.append({"customer": customer["company_name"], "brand_id": brand.id, "status": "created"})
        print(f"✓ {customer['company_name']}: Brand {brand.id}")
        time.sleep(0.5)  # Rate limit courtesy
    except Exception as e:
        results.append({"customer": customer["company_name"], "error": str(e)})
        print(f"✗ {customer['company_name']}: {e}")

print(f"\nRegistered {sum(1 for r in results if 'brand_id' in r)}/{len(customers)} brands")

Webhook monitoring for partner campaigns

Set up webhooks to track campaign status changes across all your customers:
Python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhooks/10dlc", methods=["POST"])
def handle_10dlc_webhook(self):
    event = request.json
    event_type = event.get("data", {}).get("event_type", "")

    if event_type == "campaign.status_update":
        campaign_id = event["data"]["payload"]["campaignId"]
        new_status = event["data"]["payload"]["campaignStatus"]
        print(f"Campaign {campaign_id}{new_status}")

        if new_status == "ACTIVE":
            # Campaign approved — notify customer, assign numbers
            activate_customer_messaging(campaign_id)
        elif new_status == "REJECTED":
            # Campaign rejected — notify customer with reason
            reason = event["data"]["payload"].get("rejectionReason", "Unknown")
            notify_customer_rejection(campaign_id, reason)

    elif event_type == "brand.status_update":
        brand_id = event["data"]["payload"]["brandId"]
        identity_status = event["data"]["payload"]["identityStatus"]
        print(f"Brand {brand_id}{identity_status}")

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

Partner campaign appeals

When a shared campaign is rejected, the appeal process differs from native campaigns. Partner campaigns use a CSP nudge mechanism:
1

Review the rejection reason

Check the campaign status and rejection details via your upstream CSP.
2

Fix the issue

Update the campaign details (description, samples, message flow) at your upstream CSP based on the rejection reason.
3

Trigger a CSP nudge

Your upstream CSP sends a CAMPAIGN_NUDGE event to TCR, which triggers a re-review.
The nudge mechanism is only available for partner campaigns. Native campaigns use the direct appeal API. See 10DLC Event Notifications for details.
4

Monitor for approval

Set up webhooks to receive campaign status updates automatically.

Troubleshooting

Cause: Telnyx hasn’t processed the sharing request yet, or there’s a data mismatch.Fix:
  1. Verify the campaign is fully approved at your upstream CSP
  2. Confirm you shared to the correct downstream CSP (Telnyx’s TCR ID)
  3. Contact Telnyx support with the TCR Campaign ID
Cause: Campaign sharing hasn’t been accepted, or numbers aren’t 10DLC-eligible.Fix:
  1. Check sharing status — must be ACCEPTED
  2. Verify numbers are long codes (not toll-free or short codes)
  3. Ensure numbers aren’t already assigned to another campaign
  4. Check that numbers are on the same Telnyx account
Cause: Message content doesn’t match registered campaign samples, or throughput exceeds campaign limits.Fix:
  1. Compare actual message content against registered samples
  2. Check 10DLC rate limits for your vetting score
  3. Ensure opt-out keywords (STOP, etc.) are properly handled
  4. Review the error code reference for specific guidance
Cause: Business information doesn’t match public records.Fix: See the 10DLC Troubleshooting Guide for detailed brand failure resolution steps.
Steps:
  1. Register a new brand for the customer (if not already done)
  2. Submit brand for vetting
  3. Create a new campaign under their brand
  4. Wait for campaign approval
  5. Reassign their phone numbers from the shared campaign to the new dedicated campaign
  6. Traffic switches immediately — no downtime required

Compliance checklist for ISVs

ISVs have additional compliance responsibilities because you’re sending on behalf of customers. TCR and carriers hold you accountable for your customers’ messaging practices.
  • Customer vetting — Verify your customers’ business legitimacy before registration
  • Content monitoring — Monitor message content for compliance with campaign use case
  • Opt-in verification — Ensure customers collect proper consent from end users
  • Opt-out processing — STOP/HELP keywords must work across all customer traffic
  • Volume management — Don’t exceed throughput limits for your campaign’s vetting score
  • Incident response — Have a process to quickly disable a customer’s messaging if they violate policies
  • Record retention — Keep opt-in records for at least 4 years per CTIA guidelines
  • Sample message accuracy — Registered samples must match actual production messages

Next steps