> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# DLT-India onboarding for A2P SMS

> Walk through India's TRAI DLT registration end-to-end: register on an operator DLT portal, then mirror your Principal Entity, Headers, content templates, and consent templates into Orbit so your India A2P traffic delivers.

# DLT-India onboarding for A2P SMS

India's TRAI DLT registration is a multi-step workflow spread across an
operator portal and your Orbit workspace. This guide walks it end-to-end:
what to register, on which portal, what to gather first, the one order
that works, and a worked example registering one transactional and one
promotional template. The [concept page](/compliance/dlt-india) covers
the same endpoints field-by-field; this guide covers the flow.

***

## Why registration is mandatory

Under India's TRAI DLT regime, telecom operators (Jio, Airtel, Vi, BSNL)
only deliver A2P SMS from registered senders. A message whose Sender ID,
template, or sender identity is not registered and consistent is rejected
by the operator before it reaches the handset: no delivery receipt, no
retry, no partial pass-through.

Four artifacts must be registered and mutually consistent:

* **Principal Entity (PE)**: your business identity (one PE under which
  everything else hangs).
* **Headers (Sender IDs)**: the 3–11 character sender labels your
  messages carry, each tied to your PE and a category.
* **Content templates**: every message body, with variable parts marked
  as `{#var#}` placeholders.
* **Consent templates**: the consent wording that backs your opt-ins,
  required for promotional sends.

You complete the underlying registration on a registrar's DLT portal.
Orbit then mirrors the artifacts: it records the registrar-issued IDs,
tracks each artifact's `status` (starting at `pending`, with optional
`rejection_reason` once a registrar responds), and nudges you when a
DLT-related rejection shows up on your India traffic. Orbit does not
approve anything: the registrar and operators do.

***

## Pick an operator portal

You register on a DLT portal run by (or operated for) one of the Indian
operators. Common registrars and their portal brands:

| Registrar (use this value in API calls) | Portal / operator               |
| --------------------------------------- | ------------------------------- |
| `vilpower`                              | Vodafone Idea (Vi)              |
| `trueconnect`                           | Airtel                          |
| `tanla`                                 | Airtel (alternative integrator) |
| `jio`                                   | Jio                             |
| `videocon`                              | Videocon                        |
| `bsnl`                                  | BSNL                            |

Pick one: most senders choose the operator that carries the majority of
their traffic. Your verifier on the registrar is only one of several;
what matters in Orbit is that every artifact you record carries the same
`registrar` value and the same PE ID so the four layers stay consistent.

The four artifact types map to Orbit endpoints one-to-one:

| Artifact          | Orbit endpoint (under `/api/v1/compliance/dlt-india`) |
| ----------------- | ----------------------------------------------------- |
| Principal Entity  | `principal-entities`                                  |
| Headers           | `headers`                                             |
| Content templates | `content-templates`                                   |
| Consent templates | `consent-templates`                                   |

***

## Gather the documents first

Have these in hand before you start on the portal: the registrar asks
for them in one sitting, and Orbit asks for the resulting IDs:

* **PE/KYC**: your registrar-assigned **PE ID** (8–20 characters), your
  legal name exactly as registered, and your **PAN or GSTN**.
* **Headers**: the exact 3–11 character Sender IDs you want (uppercase
  letters/digits), each with a category.
* **Per content template**: a sample message body with variable parts
  written as `{#var#}`, a template name, its category, and its type
  (`text`, `unicode`, `unicode_text`, or `otp`).
* **Per consent template**: the exact opt-in wording and a name.

Orbit enforces the same discipline the registrars do: template bodies up
to 2000 characters, up to 20 named variables, and category one of
`promotional`, `transactional`, `service_implicit`, or `service_explicit`.
A body whose variable markers don't match what the registrar approved is
rejected downstream: keep one canonical copy of each template.

<Note>
  Peeking ahead while you gather: the `GET` list endpoints and the
  `/nudge` endpoints are always open, so you can check current state even
  before registration writes are enabled.
</Note>

***

## The exact order

Register in dependency order: each artifact references the one above,
and a registrar will reject a Header or template whose parent PE is not
on file.

<Steps>
  <Step title="1. Principal Entity">
    Complete the PE application on the registrar portal and receive your
    PE ID. Record it in Orbit:

    ```bash theme={null}
    curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/principal-entities \
      -H "Authorization: Bearer $ORBIT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "registrar": "vilpower",
        "pe_id": "1101234567890123",
        "legal_name": "Acme Retail Pvt Ltd",
        "pan_or_gstn": "AAACA1234A",
        "entity_type": "private_limited"
      }'
    ```

    The response body's `data.id` is the Orbit-side ID every later
    artifact references as `principal_id`.
  </Step>

  <Step title="2. Headers">
    Register each Sender ID on the portal, then record it:

    ```bash theme={null}
    curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/headers \
      -H "Authorization: Bearer $ORBIT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "principal_id": "pe_internal_id",
        "header": "ACMERT",
        "category": "transactional"
      }'
    ```
  </Step>

  <Step title="3. Content templates">
    Register every message body on the portal under a Header, then
    record it (omit `template_id` until the registrar issues one: the
    draft is stored either way):

    ```bash theme={null}
    curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/content-templates \
      -H "Authorization: Bearer $ORBIT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "principal_id": "pe_internal_id",
        "header_id": "hdr_internal_id",
        "template_name": "Order shipped",
        "category": "transactional",
        "template_type": "text",
        "content": "Hi {#var#}, your order {#var#} has shipped.",
        "variables": ["name", "order_id"]
      }'
    ```
  </Step>

  <Step title="4. Consent templates">
    For promotional traffic, register the consent wording that backs
    your opt-ins:

    ```bash theme={null}
    curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/consent-templates \
      -H "Authorization: Bearer $ORBIT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "principal_id": "pe_internal_id",
        "consent_name": "Marketing opt-in",
        "consent_text": "I agree to receive promotional messages from Acme Retail."
      }'
    ```
  </Step>
</Steps>

Every `POST` sits at `pending` until the registrar clears it; read
status any time with the matching `GET` list endpoint. Poll the list, or
watch the nudge (below) for follow-up.

### Delivery nudges

If Orbit's DLR pipeline sees a DLT-related rejection on your India
traffic, it records a nudge for your tenant. `GET
/api/v1/compliance/dlt-india/nudge` returns the current state
(`failure_count`, `last_seen_at`, `dismissed_at`); `POST
/api/v1/compliance/dlt-india/nudge/dismiss` acknowledges it (a new
failure re-raises the banner). The nudge is observational: it tells you
a registration gap exists; it does not call the registrar.

***

## The 503 FEATURE\_DISABLED gate

Registration **writes** are off by default. The four `POST` endpoints
above return `503 FEATURE_DISABLED` until the deployment enables DLT
registration (`DEVOTEL_DLT_REGISTRATION_ENABLED=true` plus the registrar
credential pair). Reads: all `GET` list endpoints and both `nudge`
endpoints: stay open regardless, so existing rows remain visible and
delivery nudges still surface.

What to do when a write returns 503:

1. Record your registrar-side progress on the portal as usual: the
   portal flow is unaffected.
2. Contact support to have DLT registration enabled for your deployment,
   then replay the `POST` calls exactly as above.
3. While gated, use the `GET` endpoints to verify which artifacts are
   already on file before re-submitting.

The gate stays closed only while the registrar integration is parked;
previously recorded rows are never hidden.

***

## Worked example: one transactional, one promotional

Register `ACMER1` (transactional) and `ACMER2` (promotional) under one
PE, each with a template.

**Step 1: PE.** Complete the PE application on the VILPOWER portal and
receive PE ID `1101234567890123`. Record it, and capture the returned
`data.id` as `PE_ID`:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/principal-entities \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "registrar": "vilpower",
    "pe_id": "1101234567890123",
    "legal_name": "Acme Retail Pvt Ltd",
    "pan_or_gstn": "AAACA1234A",
    "entity_type": "private_limited"
  }'
```

**Step 2: Headers.** Register both Sender IDs on the portal, then
record them. Capture each `data.id`:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/headers \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_id": "'"$PE_ID"'",
    "header": "ACMER1",
    "category": "transactional"
  }'

curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/headers \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_id": "'"$PE_ID"'",
    "header": "ACMER2",
    "category": "promotional"
  }'
```

**Step 3: Content templates.** Register one transactional and one
promotional template, each under its Header. Attach the registrar-issued
`template_id` once the portal issues it (running the same call with the
ID updates the row):

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/content-templates \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_id": "'"$PE_ID"'",
    "header_id": "'"$TX_HDR_ID"'",
    "template_name": "Order shipped",
    "category": "transactional",
    "template_type": "text",
    "content": "Hi {#var#}, your order {#var#} has shipped.",
    "variables": ["name", "order_id"]
  }'

curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/content-templates \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_id": "'"$PE_ID"'",
    "header_id": "'"$PROMO_HDR_ID"'",
    "template_name": "Weekend offer",
    "category": "promotional",
    "template_type": "text",
    "content": "Hi {#var#}, get {#var#}% off this weekend at Acme Retail.",
    "variables": ["name", "discount"]
  }'
```

**Step 4: Consent template** (required for the promotional Header):

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/compliance/dlt-india/consent-templates \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_id": "'"$PE_ID"'",
    "consent_name": "Marketing opt-in",
    "consent_text": "I agree to receive promotional messages from Acme Retail."
  }'
```

**Step 5: Verify.** List all four kinds until every row shows
`approved`, and watch the nudge until your first India sends pass:

```bash theme={null}
curl -s https://api.orbit.devotel.io/api/v1/compliance/dlt-india/principal-entities \
  -H "Authorization: Bearer $ORBIT_API_KEY"

curl -s https://api.orbit.devotel.io/api/v1/compliance/dlt-india/nudge \
  -H "Authorization: Bearer $ORBIT_API_KEY"
```

Once the artifacts are approved and consistent, India traffic from the
`ACMER1` / `ACMER2` Headers stops being rejected at the operator.

***

## If it gets rejected

* **PE rejected**: the registrar's `rejection_reason` lands on the PE
  row; fix the legal name/PAN mismatch on the portal and re-record.
* **Header rejected**: most often the category is wrong for the sender
  pattern (a promotional-looking Header filed as `transactional`), or
  the string breaches the 3–11 character rule.
* **Template rejected**: the body or variable markers deviate from the
  registrar's canonical form; re-submit one canonical copy.
* **Delivery still failing after approval**: the template text you send
  must match the approved template exactly except inside `{#var#}`
  placeholders; the nudge count on `/nudge` tells you whether rejections
  are still being seen.

See [DLT gates troubleshooting](/troubleshooting/in-dlt-gates) for the
rejection side.

## Related guides

* [DLT-India concept reference](/compliance/dlt-india): field-by-field
  endpoint sketch.
* [10DLC registration](/guides/10dlc-registration): the US counterpart
  process.
* [Consent Management](/compliance/consent-management): DPDP consent
  receipts alongside DLT.
* [Go-live checklist](/guides/go-live-checklist): the broader launch
  sweep registration fits into.
