# Consent and STOP

Texting someone needs their permission, and they can take it back with one word. Rasket keeps the record and handles the replies, so you only decide what to send.

## Transactional and marketing

- `transactional` is a text the person asked for by doing something: a code, a receipt, a delivery update. It needs their phone, not marketing consent.
- `marketing` is anything that promotes. It needs the contact's SMS consent, and it keeps to the rules below.

## Record consent with proof

SMS consent is its own fact. A contact subscribed to a topic has not agreed to texts. Record it with where and how the person agreed, and keep the words they saw.

Set a contact's SMS consent:

```sh
curl -X PATCH "https://api.rasket.com/contacts/e169aa45-1ecf-4183-9955-b1499d5701d3/sms-consent" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "subscribed",
  "proof": {
    "method": "form",
    "occurred_at": "2026-10-19T18:02:11.000Z",
    "page_url": "https://example.com/join",
    "disclosure_text": "By checking this box you agree to receive marketing texts from Acme."
  }
}'
```

```ts
const response = await fetch("https://api.rasket.com/contacts/e169aa45-1ecf-4183-9955-b1499d5701d3/sms-consent", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
    "User-Agent": "acme-billing/1.0",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    status: "subscribed",
    proof: {
      method: "form",
      occurred_at: "2026-10-19T18:02:11.000Z",
      page_url: "https://example.com/join",
      disclosure_text: "By checking this box you agree to receive marketing texts from Acme."
    }
  }),
});

const { id } = await response.json();
```

```python
import os

import requests

response = requests.patch(
    "https://api.rasket.com/contacts/e169aa45-1ecf-4183-9955-b1499d5701d3/sms-consent",
    headers={
        "Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
        "User-Agent": "acme-billing/1.0",
    },
    json={
    "status": "subscribed",
    "proof": {
      "method": "form",
      "occurred_at": "2026-10-19T18:02:11.000Z",
      "page_url": "https://example.com/join",
      "disclosure_text": "By checking this box you agree to receive marketing texts from Acme."
    }
  },
)

id = response.json()["id"]
```

Set `double_opt_in` to text a confirmation first: the contact is `pending` until they reply Y. We keep the proof for five years, even after the contact is erased.

## Replies we handle for you

| Reply | What happens |
| --- | --- |
| `STOP` | Stops every text from your team to that phone, transactional ones too. UNSUBSCRIBE, CANCEL, END and QUIT work the same way. |
| `START` | Undoes a STOP. Only the person can do this. |
| `HELP` | Gets your business name and how to stop, sent for you. |
| `Y` | Confirms a double opt-in. |

We read `stop`, `Stop.` and `opt out` the same way, and a short reply like “please stop” counts too. Keyword replies are listed under `/sms/received` but are not `sms.received` webhooks; an opt-out sends `contact.sms_unsubscribed` instead.

## Rules for marketing texts

- Sent between 8 am and 9 pm where the person is, or the shorter hours some states set. A text due outside them waits for the next morning. Nothing is dropped.
- At most one marketing text to a phone in any 16 hours, however it was sent.
- Each ends with “Reply STOP to opt out”, added for you.
- Public link shorteners are refused. Use your own short-link domain instead.

These rules are always on, and transactional texts skip them. Every text, of either kind, starts with your brand name; we add it when the text does not already.
