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

# Integration Guide

> The canonical MRC texting integration: authenticate, send, handle consent, and track state — phone numbers only.

MRC is **compliance-grade texting**: every message is sent from an advisor's
MyRepChat number, consent rules are enforced server-side, and everything is
archived. Your integration only ever does what the advisor's own MyRepChat
app does — there is no separate "API behavior" to learn.

<Info>
  **Phone numbers are the only identifier you need.** Every MRC endpoint
  accepts phone numbers directly. Responses include a `memberId` (MRC's
  internal contact id) as convenience data you *may* store and reuse, but no
  flow requires it — you never have to create, look up, or manage contacts.
</Info>

## Prerequisites

1. **OAuth** — complete the [OAuth Integration Guide](/mrc/oauth/client-integration)
   (OAuth 2.1 Authorization Code + PKCE, one authorization per advisor). Your
   access token carries the advisor's identity and your granted scopes.

2. **Scopes** — the messaging surface uses two:

   | Scope                 | Grants                                                   |
   | --------------------- | -------------------------------------------------------- |
   | `mrc.messaging.write` | Send messages, send consent requests                     |
   | `mrc.messaging.read`  | Read consent status (and delivery status, when released) |

3. **API key** — every request also carries your usage-plan key in the
   `x-api-key` header, alongside the `Authorization: Bearer` token.

## The canonical flow

Send first; handle consent only when the platform tells you to. Most contacts
in an advisor's book have already consented, so the happy path is one call.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant You as Your app
    participant API as MRC API
    participant C as Contact's phone

    You->>API: POST /mrc/messaging/messages { phone, text }
    alt contact has consented (common case)
        API->>C: SMS delivered from the advisor's number
        API-->>You: 200 — successes: [{ messageId, memberId }]
    else consent required and not granted
        API-->>You: 200 — failures: ["… has not consented"]
        You->>API: POST /mrc/messaging/consent-requests { phoneNumbers: [phone] }
        API->>C: Consent request SMS ("Reply ACCEPT …")
        C-->>API: Contact replies
        loop poll (30s for 5 min, then every 5 min, stop at 24h)
            You->>API: GET /mrc/messaging/consents?phone=…
            API-->>You: { state: "pending" | "accepted" }
        end
        You->>API: POST /mrc/messaging/messages { phone, text }  — resend
        API->>C: SMS delivered
        API-->>You: 200 — successes: [{ messageId, memberId }]
    end
```

The three steps in words:

1. **[Send the message](/mrc/guides/send-a-text-message)** — `POST
   /mrc/messaging/messages`. A `200` with your recipient in `successes[]`
   means the platform accepted it for delivery. Done.
2. **If the recipient appears in `failures[]` with a consent message**, the
   advisor's account requires consent this contact hasn't granted —
   **[request consent](/mrc/guides/consent)** with `POST
   /mrc/messaging/consent-requests`, then **poll**
   `GET /mrc/messaging/consents?phone=…` until `state` is `accepted`.
3. **Resend** the original message. Nothing else changes.

## Reading responses

Send-type endpoints are **batch operations**: they return `200` with
per-recipient outcomes rather than failing the whole request when one
recipient can't receive.

```json theme={null}
{
  "successes": [{ "messageId": 535, "memberId": 24 }],
  "failures": ["Message for [Sam Client] not sent. Member has not consented"]
}
```

* `successes[]` — accepted for delivery; keep `messageId` for your records
  (it will drive delivery-status lookups when that endpoint releases).
* `failures[]` — human-readable, per-recipient reasons. Today these are
  strings; a structured `failureDetails` array with stable reason codes is
  planned and will be additive (the strings will not change shape).

## Error handling

Whole-request problems use real HTTP status codes with an
[RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) `application/problem+json`
body — never a `200` in disguise:

```json theme={null}
{
  "type": "https://connect.fmgsuite.com/problems/conflict",
  "title": "The request conflicts with the current state of the resource.",
  "status": 409,
  "code": "conflict",
  "traceId": "a1b2c3…",
  "retryable": false
}
```

| Status    | `code`                             | When                                                                                | Retry?                   |
| --------- | ---------------------------------- | ----------------------------------------------------------------------------------- | ------------------------ |
| 400       | `invalid_request`                  | Malformed body, missing identifiers, consent request for an already-accepted number | No — fix the request     |
| 401       | `unauthorized`                     | Missing/expired token                                                               | Refresh the token        |
| 403       | `forbidden`                        | Token lacks the required scope (the `detail` names it)                              | No                       |
| 404       | `not_found`                        | No contact owns that phone number on this advisor's account                         | No                       |
| 409       | `conflict`                         | The advisor's account isn't configured for consent collection                       | No — contact FMG         |
| 429       | `rate_limited`                     | Slow down                                                                           | Yes, honor `Retry-After` |
| 502 / 504 | `downstream_unavailable` / timeout | Transient platform issue                                                            | Yes, with backoff        |

Include the `traceId` in any support request. Unknown fields you send in
request bodies are ignored (stripped), so additive changes on your side are
safe.

## Behaviors worth knowing

* **Consent requests have no cooldown** — the API behaves exactly like the
  advisor's in-app "request consent" button. If you retry, throttle yourself.
* **Sending to an unknown phone number creates a contact** on the advisor's
  account (and may import from the advisor's CRM). Existing contacts are
  **never modified** by API traffic.
* **SMS only at launch.** Media/MMS is a fast-follow; the `mediaId` field in
  the spec is not yet available to partner applications.
* **Scheduled sends are supported** on the send call
  (`scheduleDelivery` + `deliveryDate` + `frequency`).
* **Delivery status endpoint is coming.** Until it releases, a `successes[]`
  entry means the platform and carrier pipeline accepted the message.

## Integration checklist

* [ ] OAuth flow completed per advisor; tokens refreshed server-side
* [ ] `x-api-key` on every request
* [ ] Send → check `failures[]` for consent → request consent → poll → resend
* [ ] Poll cadence: 30s for the first 5 minutes, then every 5 minutes, stop at 24h
* [ ] `429`/`5xx` retried with backoff; `traceId` logged
* [ ] Phone numbers in E.164 (`+12185551234`) — other common formats are
  accepted, E.164 is unambiguous
