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

# Resubscribe Contact

> Reactivate a previously opted-out contact on a sending list, with consent proof and provider/carrier opt-out handling.

Resubscribes a contact who previously unsubscribed from a sending list. This reactivates their existing membership rather than creating a new one, and clears the opt-out across all three layers where it can be cleared automatically: your database, the SMS provider's opt-out list, and — where applicable — the carrier network.

Because resubscribing re-establishes messaging consent, `consent_method` is **required** and is validated against a fixed enum. Verbal consent is rejected for these lists (all sending lists default to marketing, and TCPA requires prior express written consent for marketing). Contacts who opted out via a STOP keyword are subject to a list-level cooling-off period and, once reactivated, return `carrier_status: "pending_start_keyword"` because only the consumer can clear a carrier-level block by texting START.

## Body Parameters

<ParamField body="phone_number" type="string" required>
  Contact phone number in E.164 format (e.g., `+14155559876`).
</ParamField>

<ParamField body="list_number" type="string" required>
  Sending list phone number in E.164 format (e.g., `+18005551234`). Must be an active list owned by your account.
</ParamField>

<ParamField body="consent_method" type="string" required>
  How the contact re-granted consent. Must be one of: `web_form`, `sms_keyword`, `mobile_app`, `written`, `api_with_proof`, `double_opt_in`. `verbal` is a recognized method but is **rejected** for these lists (see `verbal_not_valid_for_marketing`).
</ParamField>

<ParamField body="consent_source" type="string">
  Where the consent was captured (e.g., a form URL or page identifier). Maximum 2048 characters. Stored on the membership for compliance records.
</ParamField>

<ParamField body="ip_address" type="string">
  IP address of the contact at the time consent was re-granted. Must be a valid IPv4 or IPv6 address.
</ParamField>

<ParamField body="user_agent" type="string">
  Browser/device user agent captured at consent time. Maximum 500 characters.
</ParamField>

<ParamField body="consent_language" type="string">
  The exact consent language shown to the contact. Maximum 5000 characters.
</ParamField>

<ParamField body="use_journeys" type="boolean" default="false">
  When `true`, enroll the reactivated contact in matching Welcome Journeys. Enrollment only occurs when `carrier_status` resolves to `cleared` — a contact pending a START keyword is not enrolled because messages would fail at the carrier level.
</ParamField>

<ParamField body="skip_journey_if_exists" type="boolean" default="true">
  When `true`, skips journey enrollment if the contact is already in an active workflow. Only relevant when `use_journeys` is `true`.
</ParamField>

## Response Fields

<ResponseField name="success" type="boolean">
  `true` when the contact was reactivated.
</ResponseField>

<ResponseField name="resubscribed" type="boolean">
  Always `true` on a successful response.
</ResponseField>

<ResponseField name="consent_status" type="string">
  Consent state after reactivation. Always `re_opted_in`.
</ResponseField>

<ResponseField name="carrier_status" type="string">
  `cleared` when messaging can resume immediately, or `pending_start_keyword` when the prior opt-out was a STOP keyword and the contact must text START to clear the carrier-level block. When `pending_start_keyword`, `carrier_instructions` is also returned.
</ResponseField>

<ResponseField name="carrier_instructions" type="string">
  Present **only** when `carrier_status` is `pending_start_keyword`. Human-readable instruction telling the contact to text START to the list number before messages can be delivered.
</ResponseField>

<ResponseField name="provider_sync" type="object">
  Result of syncing the opt-out removal with the SMS provider.

  <Expandable title="provider_sync properties">
    <ResponseField name="provider" type="string">
      The list's provider/list type.
    </ResponseField>

    <ResponseField name="opt_out_removed" type="boolean">
      `true` when the provider removed the opt-out, `null` when the provider does not manage opt-out lists (no sync was attempted).
    </ResponseField>

    <ResponseField name="api_used" type="string">
      The provider API used to remove the opt-out (e.g., `consent_management`), or `null` when no sync was attempted.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="contact_id" type="string">
  Unique identifier of the Contact record.
</ResponseField>

<ResponseField name="list_contact_id" type="string">
  Unique identifier of the ListContact record (contact-on-list membership) that was reactivated.
</ResponseField>

<ResponseField name="journeys_enrolled" type="integer">
  Number of Welcome Journeys the contact was enrolled in on reactivation (`0` or `1`).
</ResponseField>

<ResponseField name="previous_unsub_reason" type="string">
  The unsubscribe reason recorded before reactivation. `null` if none was set.
</ResponseField>

<ResponseField name="previous_unsub_date" type="string">
  ISO 8601 UTC timestamp of the prior unsubscribe. `null` if none was recorded.
</ResponseField>

## Examples

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.tracklysms.com/api/v2/contacts/resubscribe" \
    -H "X-Api-Key: trk_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "phone_number": "+14155559876",
      "list_number": "+18005551234",
      "consent_method": "web_form",
      "consent_source": "https://example.com/preferences",
      "ip_address": "203.0.113.42",
      "user_agent": "Mozilla/5.0",
      "consent_language": "I agree to receive recurring marketing text messages."
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.tracklysms.com/api/v2/contacts/resubscribe",
      headers={
          "X-Api-Key": "trk_your_api_key_here",
          "Content-Type": "application/json"
      },
      json={
          "phone_number": "+14155559876",
          "list_number": "+18005551234",
          "consent_method": "web_form",
          "consent_source": "https://example.com/preferences",
          "ip_address": "203.0.113.42",
          "user_agent": "Mozilla/5.0",
          "consent_language": "I agree to receive recurring marketing text messages."
      }
  )

  data = response.json()
  print(f"Resubscribed: {data.get('resubscribed')}")
  print(f"Carrier status: {data.get('carrier_status')}")
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    "https://api.tracklysms.com/api/v2/contacts/resubscribe",
    {
      method: "POST",
      headers: {
        "X-Api-Key": "trk_your_api_key_here",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        phone_number: "+14155559876",
        list_number: "+18005551234",
        consent_method: "web_form",
        consent_source: "https://example.com/preferences",
        ip_address: "203.0.113.42",
        user_agent: "Mozilla/5.0",
        consent_language:
          "I agree to receive recurring marketing text messages.",
      }),
    }
  );

  const data = await response.json();
  console.log("Resubscribed:", data.resubscribed);
  console.log("Carrier status:", data.carrier_status);
  ```
</RequestExample>

<ResponseExample>
  ```json 200 - Resubscribed (carrier cleared) theme={null}
  {
    "success": true,
    "resubscribed": true,
    "consent_status": "re_opted_in",
    "carrier_status": "cleared",
    "provider_sync": {
      "provider": "twilio",
      "opt_out_removed": true,
      "api_used": "consent_management"
    },
    "contact_id": "665a1b2c3d4e5f6a7b8c9d0e",
    "list_contact_id": "665a1b2c3d4e5f6a7b8c9d0f",
    "journeys_enrolled": 0,
    "previous_unsub_reason": "manual",
    "previous_unsub_date": "2026-01-10T09:00:00Z"
  }
  ```

  ```json 200 - Resubscribed (STOP opt-out, carrier block pending) theme={null}
  {
    "success": true,
    "resubscribed": true,
    "consent_status": "re_opted_in",
    "carrier_status": "pending_start_keyword",
    "carrier_instructions": "Contact must text START to +18005551234 to clear carrier block. Messages will fail until then.",
    "provider_sync": {
      "provider": "twilio",
      "opt_out_removed": true,
      "api_used": "consent_management"
    },
    "contact_id": "665a1b2c3d4e5f6a7b8c9d0e",
    "list_contact_id": "665a1b2c3d4e5f6a7b8c9d0f",
    "journeys_enrolled": 0,
    "previous_unsub_reason": "replied stop",
    "previous_unsub_date": "2026-06-20T14:30:00Z"
  }
  ```

  ```json 400 - Missing consent method theme={null}
  {
    "error": "consent_method is required",
    "code": "missing_consent_method"
  }
  ```

  ```json 400 - Already active theme={null}
  {
    "error": "Contact is already active on this list",
    "code": "already_active"
  }
  ```

  ```json 400 - Cooling-off period theme={null}
  {
    "error": "Contact opted out via STOP keyword 12 days ago. 30-day cooling-off period applies.",
    "code": "cooling_off"
  }
  ```

  ```json 502 - Provider sync failed theme={null}
  {
    "error": "Provider consent sync failed: unknown error",
    "code": "provider_sync_failed"
  }
  ```
</ResponseExample>

## Error Codes

| HTTP Status | Error Code                       | Description                                                                                                |
| ----------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| 400         | `missing_phone_number`           | The `phone_number` field was not provided.                                                                 |
| 400         | `missing_list_number`            | The `list_number` field was not provided.                                                                  |
| 400         | `missing_consent_method`         | The `consent_method` field was not provided.                                                               |
| 400         | `invalid_consent_method`         | The `consent_method` is not one of the allowed values.                                                     |
| 400         | `verbal_not_valid_for_marketing` | `consent_method=verbal` is not accepted for marketing lists. Use `web_form`, `written`, or another method. |
| 400         | `invalid_phone`                  | The `phone_number` is not a valid E.164 phone number.                                                      |
| 400         | `invalid_list_number`            | The `list_number` is not a valid E.164 phone number.                                                       |
| 400         | `list_not_found`                 | No active sending list with the given `list_number` exists for this account.                               |
| 400         | `contact_not_found`              | The contact does not exist, or is not a member of the specified list.                                      |
| 400         | `already_active`                 | The contact is already subscribed (active) on this list.                                                   |
| 400         | `cooling_off`                    | The contact opted out via a STOP keyword and the list's cooling-off period has not elapsed.                |
| 400         | `invalid_ip_address`             | The `ip_address` is not a valid IPv4 or IPv6 address.                                                      |
| 400         | `field_too_long`                 | `consent_source`, `consent_language`, or `user_agent` exceeds its maximum length.                          |
| 400         | `invalid_input`                  | An input field contained disallowed characters.                                                            |
| 401         | `invalid_credentials`            | Missing or invalid `X-Api-Key` header.                                                                     |
| 403         | `account_suspended`              | Your account is suspended. Resolve outstanding billing or contact support.                                 |
| 429         | `rate_limited`                   | Request throttled; retry with exponential backoff after the window resets.                                 |
| 502         | `provider_sync_failed`           | The opt-out could not be removed at the SMS provider. The contact is **not** reactivated; retry later.     |
| 500         | `internal_error`                 | An unexpected server error occurred.                                                                       |

<Note>
  A `pending_start_keyword` carrier status means the contact still has a carrier-level block from their STOP reply. No API can clear this — the contact must text START to the list number. Messages sent before then will fail at the carrier.
</Note>

## Next Steps

<CardGroup cols={2}>
  <Card title="Create Contact" icon="user-plus" href="/api-reference/v2/contacts/create-contact">
    Add a contact to a sending list
  </Card>

  <Card title="Delete Contact" icon="user-minus" href="/api-reference/v2/contacts/delete-contact">
    Unsubscribe a contact from a list
  </Card>
</CardGroup>
