---
title: "Enroll Contact For Sms"
method: POST
path: "/sites/contacts/{contact_id}/sms-enroll"
tags: ["sms-consent"]
---

# Enroll Contact For Sms

`POST /sites/contacts/{contact_id}/sms-enroll`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/sites/contacts/{contact_id}/sms-enroll`
- Auth: HTTP bearer

Enroll one site contact for SMS and send the ONE confirmation text.

Two steps, deliberately not one transaction: the enrollment commits first,
then the confirmation is sent against it. A provider failure therefore
leaves an open enrollment (re-sendable, and the send is idempotent per row)
rather than rolling back the record the idempotency depends on.

The contact must reply YES before this authorizes anything.

## Path parameters

- `contact_id` string, required

## Request body

- EnrollContactRequest
  - `slot` 'primary' | 'afterhours': Which of the contact's two numbers to enroll. The consent is bound to this exact (contact, slot) at creation, so it can never authorize a send to the other number.

## Response `200`

Successful Response

- SmsConsentResponse: One consent row as the operator console sees it. Deliberately NOT the whole row: `source_ip`, `user_agent`, `phone_raw` and the raw consent text are evidence for a compliance request, not console furniture, and an endpoint that returns them invites them into a UI (and a browser cache) they have no business being in.
  - `id` string, uuid, required: Unique identifier of the consent record.
  - `phone_number` string, required: Canonical E.164 number the consent covers.
  - `full_name` string, nullable: Name given at consent time, if any.
  - `email` string, nullable: Email given at consent time, if any.
  - `organization` string, nullable: Organization given at consent time.
  - `consent_version` string, required: Server-owned key for the exact text agreed to.
  - `consented_at` string, date-time, nullable: When consent actually occurred. NULL for a Rail A enrollment that is still waiting for its YES reply.
  - `source` string, required: How the consent was obtained.
  - `status` string, required: pending_confirmation | pending_review | linked | dismissed | revoked | unverifiable. Only `linked` with a bound contact authorizes a send.
  - `site_contact_id` string, uuid, nullable: Bound contact, if any.
  - `site_id` string, uuid, nullable: Bound site, if any.
  - `contact_slot` string, nullable: primary | afterhours.
  - `evidence_ref` string, nullable: What proves it — the inbound YES message id for Rail A.
  - `linked_at` string, date-time, nullable: When it was bound to a contact.
  - `revoked_at` string, date-time, nullable: When a STOP superseded it.
  - `dismissed_at` string, date-time, nullable: When it was dismissed or expired.
  - `confirmation_sent_at` string, date-time, nullable: When the Rail A confirmation text was sent. One, ever.
  - `confirmation_error` string, nullable: Last confirmation send failure, if any.
  - `created_at` string, date-time, nullable: Row creation time.
  - `updated_at` string, date-time, nullable: Row last-update time.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/00252d8227c1?raw)
