← SentCONTENT HISTORY

Update to Sent

Snapshot Sep 30, 2026 · 22:48 UTC · version 1.0.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "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.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 226
    },
    {
      "relative_path": "references/multi-tenancy-patterns.md",
      "size_in_bytes": 2662
    },
    {
      "relative_path": "references/profile-boundary-examples.md",
      "size_in_bytes": 2286
    },
    {
      "relative_path": "references/sender-profile-data-model.md",
      "size_in_bytes": 2588
    }
  ],
  "skill_md_contents": "---\nname: sender-profile-architect\ndescription: 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.\n---\n\n# Sender Profile Architect\n\nA 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.\n\n## Recommended tenancy model\n\nWhen 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.\n\nDo not recommend pooled-by-default architecture. Make the isolation decision explicit using [references/multi-tenancy-patterns.md](references/multi-tenancy-patterns.md).\n\n## Authentication patterns\n\nSent v3 supports both:\n\n| Pattern | Headers | Blast radius |\n| --- | --- | --- |\n| Profile-specific API key | `x-api-key` | Profile-scoped credentials and rate-limit context. Do not add `x-profile-id`. |\n| 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. |\n\nOnly 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.\n\n`x-sender-id` is legacy v1/v2 terminology only. Do not use it for v3 authentication or routing.\n\nChoose 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.\n\n## Profile creation model\n\nCreate with `POST /v3/profiles`. `name` is required. Current optional areas include:\n\n- identity: `icon`, `description`, `short_name`;\n- sharing: `allow_contact_sharing`, `allow_template_sharing`;\n- inheritance: `inherit_contacts`, `inherit_templates`, `inherit_tcr_brand`, `inherit_tcr_campaign`;\n- billing: `billing_model`, `billing_contact`, and ephemeral `payment_details`;\n- dedicated WABA credentials: `whatsapp_business_account` with `waba_id`, optional `phone_number_id`, and `access_token`;\n- a dedicated brand: `brand.contact`, `brand.business`, and `brand.compliance`.\n\nDo not add a separate brand endpoint. A dedicated brand is created with the profile; campaigns are managed under `/v3/profiles/{profileId}/campaigns`.\n\n### Inheritance rules\n\n- `inherit_tcr_brand: true` means the profile uses the organization's brand and cannot submit its own `brand` object.\n- `inherit_tcr_campaign: true` makes inherited campaigns read-only for that profile.\n- An inherited brand with `inherit_tcr_campaign: false` is a supported dedicated-campaign pattern.\n- Sharing flags expose a profile's contacts/templates; inheritance flags consume organization resources. Treat those directions separately.\n\n### Billing and number references\n\n`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.\n\nProfile 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.\n\n## WABA choices\n\nThere are three distinct paths:\n\n1. Organization Embedded Signup in the dashboard.\n2. Child profile inheritance by omitting `whatsapp_business_account` after the organization has a WABA.\n3. Dedicated profile WABA using `waba_id` and `access_token`; `phone_number_id` is optional.\n\nThere 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.\n\n## 10DLC and campaigns\n\nUse a profile `brand` object for a dedicated brand. Manage campaigns at:\n\n- `GET|POST /v3/profiles/{profileId}/campaigns`\n- `PUT|DELETE /v3/profiles/{profileId}/campaigns/{campaignId}`\n\nUse `sms-10dlc-registration` for the payload and policy layer.\n\n## Completion and status handling\n\nComplete a profile with `POST /v3/profiles/{profileId}/complete` and a required `webHookUrl`:\n\n```json\n{\n  \"webHookUrl\": \"https://example.com/webhooks/profile-complete\",\n  \"sandbox\": true\n}\n```\n\nStatus is surface-specific:\n\n- Create response currently demonstrates lowercase `incomplete`.\n- Completion `202` means processing started and does not contain a final status.\n- Completion `200` currently demonstrates lowercase `completed` for an already-complete profile.\n- Completion callbacks can report `COMPLETED`, `SUBMITTED`, or `failed`.\n- REST guides and OpenAPI publish different profile status sets.\n\nDo not assert a closed REST enum. Preserve unknown strings and record the endpoint/callback surface that produced them.\n\n## Webhook attribution\n\nSent 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.\n\n```text\nmessage_id -> tenant_id, profile_id, logical_send_id, channel\nreceiving_number -> tenant_id, profile_id\n```\n\nDo not infer tenant ownership from `account_id` alone. Multiple tenant profiles can belong to one organization.\n\n## Design checklist\n\n- [ ] Tenant/brand isolation decision is explicit.\n- [ ] Credential pattern and rate-limit/blast radius are documented.\n- [ ] Sharing and inheritance directions are intentional.\n- [ ] Billing ownership is named.\n- [ ] Number references cannot form cycles.\n- [ ] WABA path is organization signup, inheritance, or dedicated credentials—not an invented hybrid.\n- [ ] Dedicated brand/campaign paths are profile-based.\n- [ ] `message_id` and inbound-number mappings support webhook attribution.\n- [ ] Unknown profile statuses are tolerated.\n- [ ] Tenant offboarding revokes credentials, disables sends, detaches resources safely, and retains audit evidence.\n\nSee [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.\n"
}

SHA-256: 11e29a6bd5744e021826ccce9b798ca04ed264dd58345b687dce6b940b4ada66