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

# Communication Delivery & Webhooks

> Jane receives an account update by email and SMS, then SendGrid and Twilio report what happened after the messages leave YouNegotiate.

## Real-World Example

ABC Collections updates Jane's pay-term offer during an import. The portal should not send that communication inside the upload screen. Instead, it queues the communication work, checks Jane's permissions, sends the email and SMS through the configured providers, records communication history, and listens for provider callbacks after delivery.

If Jane replies `STOP` by text, the Twilio inbound SMS webhook should update her opt-out state and cancel scheduled follow-up communications. If SendGrid later reports that a campaign email was delivered or opened, the tracking counts should update without requiring a creditor user to refresh or manually mark anything.

## Visual Flow

```mermaid placement="top-right" actions={true} theme={"system"}
flowchart TD
    A["Portal event happens"] --> B["Communication job is queued"]
    B --> C["Load consumer profile, permissions, and template"]
    C --> D{"Can this consumer receive messages?"}
    D -->|No| E["Skip safely and log reason"]
    D -->|Yes| F["Send email through configured mailer"]
    D -->|Yes| G["Send SMS through Twilio"]
    F --> H["Communication history is recorded"]
    G --> H
    F --> I["SendGrid sends delivery/open webhook"]
    G --> J["Twilio sends status webhook"]
    G --> K["Consumer can reply STOP or START"]
    I --> L["Campaign or EcoMail Hub / EcoPortal tracking updates"]
    J --> L
    K --> M["Opt-out or opt-in state updates"]
    classDef default fill:#F8FAFC,stroke:#64748B,stroke-width:1.5px,color:#0F172A;
    classDef actor fill:#E0F2FE,stroke:#0284C7,stroke-width:2px,color:#0C4A6E;
    classDef system fill:#F8FAFC,stroke:#64748B,stroke-width:1.5px,color:#0F172A;
    classDef decision fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#78350F;
    classDef risk fill:#FEE2E2,stroke:#DC2626,stroke-width:2px,color:#7F1D1D;
    classDef outcome fill:#DCFCE7,stroke:#16A34A,stroke-width:2px,color:#14532D;
    class A,K actor;
    class B,C,F,G,H,I,J system;
    class D decision;
    class E risk;
    class L,M outcome;
    linkStyle default stroke:#94A3B8,stroke-width:2px;
```

## What Starts Communication

| Source                  | Example                                                                                                        |
| ----------------------- | -------------------------------------------------------------------------------------------------------------- |
| Consumer import         | Add, Add + CFPB, Delete, or pay-term Update can queue consumer communication after processing.                 |
| Reminder jobs           | Offer expiration, upcoming payment, account expiration, and setup reminders are sent by scheduled commands.    |
| Payment and plan events | Paid off, processed payment, failed payment, skip, settlement, and negotiation outcomes can dispatch messages. |
| Campaigns               | Creditor, Super Admin, and EcoMail Hub / EcoPortal campaigns dispatch messages in background chunks.           |
| CFPB EcoLetters         | Secure CFPB EcoLetters create e-letter records and trigger delivery messages.                                  |
| Manual SMS              | Authorized users can send a direct SMS from supported consumer profile pages.                                  |

## Outbound Delivery

Most automated consumer messages flow through `TriggerEmailAndSmsServiceJob`.

1. The app finds the `CommunicationStatus` for the event code.
2. It loads the consumer, company, sub-account, unsubscribe state, and consumer profile.
3. It checks whether the consumer has updated communication preferences.
4. It checks email permission, SMS permission, opt-out state, and valid contact details.
5. Email content is rendered from the selected template and sent through the configured mailer.
6. SMS content is rendered from the selected template and sent through Twilio.
7. Communication history records status, destination, cost, SMS segment count, and source where applicable.

## SendGrid Email Events

SendGrid posts email event callbacks to:

```text theme={"system"}
POST /api/webhooks/sendgrid/email-events
```

The webhook should:

* Verify the SendGrid signature when signature validation is enabled.
* Accept a JSON array of provider events.
* Use the provider tracking key from `campaign_tracking_key` or `custom_args.campaign_tracking_key`.
* Update campaign tracking for `delivered` and `open` events.
* Update EcoMail Hub / EcoPortal campaign tracking when the tracking scope is `ecomailhub`.
* Ignore unknown or incomplete events without breaking the whole webhook request.

## Twilio SMS Webhooks

Twilio sends inbound SMS replies to:

```text theme={"system"}
POST /api/webhooks/twilio/sms
```

The inbound webhook should:

* Verify the Twilio signature when signature enforcement is enabled.
* Match the sender phone number to consumer account or consumer profile phone indexes.
* Treat `STOP`, `STOPALL`, `UNSUBSCRIBE`, `CANCEL`, `END`, and `QUIT` as opt-out messages.
* Treat `START`, `UNSTOP`, and `YES` as opt-in messages.
* Create or remove unsubscribe records as needed.
* Update the consumer profile text permission.
* Delete scheduled follow-up communications after opt-out.
* Return a successful response even when the phone number does not match a consumer, so Twilio does not retry a non-actionable message.

Twilio sends SMS delivery status callbacks to:

```text theme={"system"}
POST /api/webhooks/twilio/sms/status
```

The status webhook should mark SMS as delivered for campaign tracking when Twilio reports `delivered`. If the request has an EcoMail Hub / EcoPortal tracking scope, it updates EcoMail Hub / EcoPortal SMS recipient tracking instead.

## Campaign Delivery

Campaigns are backgrounded to avoid sending hundreds or thousands of messages in one request.

* `SendCampaignEmailSmsOrELetterJob` keeps consumer dispatches bounded in chunks.
* `SendSingleCampaignMessageJob` sends each individual email, SMS, or e-letter.
* Email campaign sends attach a provider tracking key so SendGrid delivery/open webhooks can update campaign counts.
* SMS campaign sends include Twilio's status callback URL so delivered messages can update tracking.

## Safety Rules

* Provider webhooks should be throttled and signature-verified.
* Consumer opt-out must stop future SMS and scheduled follow-up communication.
* A consumer with updated communication preferences should use the consumer profile contact details.
* A consumer without updated communication preferences should use the account-level imported contact details unless unsubscribed.
* Invalid or missing email/phone values should be skipped rather than sent blindly.
* Delivery/open callbacks should update tracking only when the provider tracking key is present.
* Webhook handlers should not expose sensitive phone numbers in logs.

## How It Should Work

* It should send communication from background jobs, not long page requests.
* It should respect consumer permissions, unsubscribe records, and valid contact checks.
* It should record communication history for billing and operational review.
* It should let SendGrid and Twilio update tracking after messages leave the app.
* It should keep campaign and EcoMail Hub / EcoPortal tracking separate.

## How It Should Not Work

* It should not send SMS after a consumer opts out.
* It should not mark messages delivered just because the app attempted to send them.
* It should not trust provider webhook payloads when signature validation is enabled.
* It should not let one malformed SendGrid event fail the entire batch.
* It should not mix EcoMail Hub / EcoPortal campaign tracking with creditor campaign tracking.

## Developer Notes

* Webhook routes are registered in `routes/api.php`.
* Webhook throttles are configured in `app/Providers/RouteServiceProvider.php`.
* Twilio transport should use the app's configured Twilio HTTP client.
* SendGrid webhook signature validation uses `services.sendgrid.event_webhook_public_key`.
* Twilio webhook signature validation uses `services.twilio.auth_token`.
* Automated and scheduled communication usually runs through `TriggerEmailAndSmsServiceJob`.

## Related App Areas

* `routes/api.php`
* `app/Jobs/TriggerEmailAndSmsServiceJob.php`
* `app/Services/TriggerEmailOrSmsService.php`
* `app/Services/TwilioService.php`
* `app/Http/Controllers/Webhooks/SendGridEmailWebhookController.php`
* `app/Http/Controllers/Webhooks/TwilioSmsWebhookController.php`
* `app/Http/Controllers/Webhooks/TwilioSmsStatusWebhookController.php`
* `app/Jobs/SendCampaignEmailSmsOrELetterJob.php`
* `app/Jobs/SendSingleCampaignMessageJob.php`
* `app/Services/CampaignRecipientTrackingService.php`
* `app/Services/EcoMailHubCampaignRecipientTrackingService.php`
