sender-profile-architect

Designs Sent Sender Profile architecture for multi-tenant, multi-brand, and multi-channel systems. Use for API-key scoping, x-profile-id, isolation, inheritance, sharing, billing, WABA, 10DLC campaigns, webhooks, or tenant offboarding.

sentdm/sent-plugin2.0k installsMITSynced Aug 27

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: sender-profile-architect
description: Designs Sent Sender Profile architecture for multi-tenant, multi-brand, and multi-channel systems. Use for API-key scoping, x-profile-id, isolation, inheritance, sharing, billing, WABA, 10DLC campaigns, webhooks, or tenant offboarding.
license: MIT
---

# Sender Profile Architect

A Sender Profile is the operational boundary for tenant identity, channel configuration, inherited resources, billing, and credentials. Use this skill before provisioning when a poor boundary would mix brands, compliance posture, rate-limit impact, or webhook ownership.

## Recommended tenancy model

When tenants require isolation, recommend one Sent organization with one Sender Profile per tenant. A shared profile is appropriate only when the tenants genuinely share one brand, sender resources, compliance posture, billing/rate-limit expectations, and operational blast radius.

Do not recommend pooled-by-default architecture. Make the isolation decision explicit using [references/multi-tenancy-patterns.md](references/multi-tenancy-patterns.md).

## Authentication patterns

Sent v3 supports both:

| Pattern | Headers | Blast radius |
| --- | --- | --- |
| Profile-specific API key | `x-api-key` | Profile-scoped credentials and rate-limit context. Do not add `x-profile-id`. |
| Organization API key acting for a child | `x-api-key` plus `x-profile-id: <profile UUID>` | Organization credential can reach permitted child profiles; rate limits remain in the organization pool. |

Only organization keys may send `x-profile-id`. A profile key that sends it receives `403`. A profile outside the organization returns `404`. `X-Profile-Id` can be echoed in scoped responses.

`x-sender-id` is legacy v1/v2 terminology only. Do not use it for v3 authentication or routing.

Choose profile keys when tenant-level credential isolation and revocation are primary. Choose organization-key scoping for centrally controlled integrations that can protect a broader credential and deliberately accept a shared organization rate-limit pool.

## Profile creation model

Create with `POST /v3/profiles`. `name` is required. Current optional areas include:

- identity: `icon`, `description`, `short_name`;
- sharing: `allow_contact_sharing`, `allow_template_sharing`;
- inheritance: `inherit_contacts`, `inherit_templates`, `inherit_tcr_brand`, `inherit_tcr_campaign`;
- billing: `billing_model`, `billing_contact`, and ephemeral `payment_details`;
- dedicated WABA credentials: `whatsapp_business_account` with `waba_id`, optional `phone_number_id`, and `access_token`;
- a dedicated brand: `brand.contact`, `brand.business`, and `brand.compliance`.

Do not add a separate brand endpoint. A dedicated brand is created with the profile; campaigns are managed under `/v3/profiles/{profileId}/campaigns`.

### Inheritance rules

- `inherit_tcr_brand: true` means the profile uses the organization's brand and cannot submit its own `brand` object.
- `inherit_tcr_campaign: true` makes inherited campaigns read-only for that profile.
- An inherited brand with `inherit_tcr_campaign: false` is a supported dedicated-campaign pattern.
- Sharing flags expose a profile's contacts/templates; inheritance flags consume organization resources. Treat those directions separately.

### Billing and number references

`billing_model` currently supports `profile`, `organization`, and `profile_and_organization`. A profile or fallback billing model requires `billing_contact` when none exists. Card fields are forwarded to the payment processor and must not be logged or persisted.

Profile update can manage `sending_phone_number_profile_id`, `sending_whatsapp_number_profile_id`, `sending_phone_number`, `whatsapp_phone_number`, and `allow_number_change_during_onboarding`. Model reference IDs and direct numbers separately, and prevent cycles when one profile references another.

## WABA choices

There are three distinct paths:

1. Organization Embedded Signup in the dashboard.
2. Child profile inheritance by omitting `whatsapp_business_account` after the organization has a WABA.
3. Dedicated profile WABA using `waba_id` and `access_token`; `phone_number_id` is optional.

There is no public endpoint that starts organization Embedded Signup. Direct credentials on `POST /v3/profiles` are not an “Embedded Signup endpoint.” Use `waba-embedded-signup` for the operational flow.

## 10DLC and campaigns

Use a profile `brand` object for a dedicated brand. Manage campaigns at:

- `GET|POST /v3/profiles/{profileId}/campaigns`
- `PUT|DELETE /v3/profiles/{profileId}/campaigns/{campaignId}`

Use `sms-10dlc-registration` for the payload and policy layer.

## Completion and status handling

Complete a profile with `POST /v3/profiles/{profileId}/complete` and a required `webHookUrl`:

```json
{
  "webHookUrl": "https://example.com/webhooks/profile-complete",
  "sandbox": true
}
```

Status is surface-specific:

- Create response currently demonstrates lowercase `incomplete`.
- Completion `202` means processing started and does not contain a final status.
- Completion `200` currently demonstrates lowercase `completed` for an already-complete profile.
- Completion callbacks can report `COMPLETED`, `SUBMITTED`, or `failed`.
- REST guides and OpenAPI publish different profile status sets.

Do not assert a closed REST enum. Preserve unknown strings and record the endpoint/callback surface that produced them.

## Webhook attribution

Sent events do not contain your application tenant ID. Before sending, persist the returned `message_id` with the tenant and profile. Route outbound status events through that mapping. For inbound messages, map the receiving number/profile resource to the tenant.

```text
message_id -> tenant_id, profile_id, logical_send_id, channel
receiving_number -> tenant_id, profile_id
```

Do not infer tenant ownership from `account_id` alone. Multiple tenant profiles can belong to one organization.

## Design checklist

- [ ] Tenant/brand isolation decision is explicit.
- [ ] Credential pattern and rate-limit/blast radius are documented.
- [ ] Sharing and inheritance directions are intentional.
- [ ] Billing ownership is named.
- [ ] Number references cannot form cycles.
- [ ] WABA path is organization signup, inheritance, or dedicated credentials—not an invented hybrid.
- [ ] Dedicated brand/campaign paths are profile-based.
- [ ] `message_id` and inbound-number mappings support webhook attribution.
- [ ] Unknown profile statuses are tolerated.
- [ ] Tenant offboarding revokes credentials, disables sends, detaches resources safely, and retains audit evidence.

See [references/sender-profile-data-model.md](references/sender-profile-data-model.md) and [references/profile-boundary-examples.md](references/profile-boundary-examples.md) for implementation patterns.

More API Design skills

← All API Design skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY