npx skills add ...
npx skills add sentdm/sent-plugin --skill 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.
npx skills add sentdm/sent-plugin --skill 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.
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.
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.
Create with POST /v3/profiles. name is required. Current optional areas include:
icon, description, short_name;allow_contact_sharing, allow_template_sharing;inherit_contacts, inherit_templates, inherit_tcr_brand, inherit_tcr_campaign;billing_model, billing_contact, and ephemeral payment_details;whatsapp_business_account with waba_id, optional phone_number_id, and access_token;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.
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.inherit_tcr_campaign: false is a supported dedicated-campaign pattern.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.
There are three distinct paths:
whatsapp_business_account after the organization has a WABA.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.
Use a profile brand object for a dedicated brand. Manage campaigns at:
GET|POST /v3/profiles/{profileId}/campaignsPUT|DELETE /v3/profiles/{profileId}/campaigns/{campaignId}Use sms-10dlc-registration for the payload and policy layer.
Complete a profile with POST /v3/profiles/{profileId}/complete and a required webHookUrl:
Status is surface-specific:
incomplete.202 means processing started and does not contain a final status.200 currently demonstrates lowercase completed for an already-complete profile.COMPLETED, SUBMITTED, or failed.Do not assert a closed REST enum. Preserve unknown strings and record the endpoint/callback surface that produced them.
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.
Do not infer tenant ownership from account_id alone. Multiple tenant profiles can belong to one organization.
message_id and inbound-number mappings support webhook attribution.See references/sender-profile-data-model.md and references/profile-boundary-examples.md for implementation patterns.