Update a sender profile
Changes a profile's own attributes: name, short_name and description.
Only those. A profile's identity, its markets and its compliance each have a sub-resource of their own, because each has its own validation and its own external consequences — a brand change may need re-registering, a market change provisions a sender. Folding them in here would give those fields two writers and no way to say which one wins.
Omitting a field leaves it alone; sending null clears it. Those are different requests, so {} changes nothing and is refused rather than silently accepted — a caller who misspelt every field would otherwise get a 200 and an unchanged profile.
name and short_name cannot be cleared: short_name is the SMS sender id, so a supplied value must be 3–11 characters of letters, numbers and spaces with at least one letter.
Returns the profile as GET /v3/sender-profiles/{id} would, so the result of the change needs no second call to see.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
curl -X PATCH "https://example.com/v3/sender-profiles/770e8400-e29b-41d4-a716-446655440002" \ -H "Idempotency-Key: req_abc123_retry1" \ -H "Content-Type: application/json" \ -d '{ "name": "Example Retail Renamed", "short_name": "EXMPL", "sandbox": false }'{
"success": true,
"data": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"organization_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Example Retail Renamed",
"short_name": "EXMPL",
"description": null,
"billing": {
"inherit": false
},
"channels": {
"sms": [
{
"country": "US",
"number_type": "TEN_DLC",
"sender_value": "+12125550100",
"status": "ACTIVE",
"note": "This market's sender is live and can carry traffic."
}
],
"whatsapp": null,
"rcs": null,
"mms": []
},
"compliance": {
"brand": {
"inherit": false,
"legal_name": "Example Retail Inc",
"entity_type": "PRIVATE_PROFIT",
"country": "US",
"website": "https://example.com"
},
"campaign": {
"inherit": false,
"description": "Order and delivery updates for customers who opted in at checkout."
},
"documents": [
{
"key": "senderid_registration_requirements",
"file_name": "sender-id-registration.pdf",
"document_id": "b792e8ae-2cb4-4209-85b9-32be4c2fcdd6"
}
]
},
"created_at": "2025-01-15T00:00:00+00:00"
},
"meta": {
"request_id": "req_9Z1bMq4kFy",
"timestamp": "2025-06-01T12:00:00+00:00",
"version": "v3"
}
}{
"success": false,
"data": null,
"error": {
"code": "VALIDATION_001",
"message": "Supply at least one field to change",
"details": null,
"doc_url": "https://docs.sent.dm/reference/api/error-catalog"
},
"meta": {
"request_id": "req_9Z1bMq4kFy",
"timestamp": "2025-06-01T12:00:00+00:00",
"version": "v3"
}
}{
"success": false,
"data": null,
"error": {
"code": "RESOURCE_014",
"message": "Sender profile not found",
"details": null,
"doc_url": "https://docs.sent.dm/reference/api/error-catalog"
},
"meta": {
"request_id": "req_9Z1bMq4kFy",
"timestamp": "2025-06-01T12:00:00+00:00",
"version": "v3"
}
}{
"success": true,
"error": {
"code": "string",
"message": "string",
"details": {
"property1": [
"string"
],
"property2": [
"string"
]
},
"doc_url": "string"
},
"meta": {
"request_id": "string",
"timestamp": "2019-08-24T14:15:22Z",
"version": "string"
}
}Create a sender profile POST
Creates a sender profile under your organization. A profile is a customer of yours: it sends under its own or your identity, and your customers never see Sent. ## The minimum `{ "name": "Example Retail", "short_name": "Example" }`. `short_name` is the SMS sender id and is required. Identity, inbox, opt-out list and billing come from your organization, so the profile is usable immediately with no compliance work. **A sender is not one of them.** The brand and the campaign can be inherited; a number cannot. A profile either has a sender of its own — `channels.sms` — or it has none and terminates through the shared routes for that country. ## Saying what a profile owns Every capability is one of three things, and there is no flag per state: - **Its own** — supply the capability's fields. Data is what owning looks like. - **The organization's** — `{ "inherit": true }`, with nothing else. - **None** — omit the block. There is no `"inherit": false` that also carries no data. A second way to say the same thing would let a request contradict itself. Inheriting needs no id. A customer has exactly one brand, so `brand` resolves without one. **The campaign has no block of its own.** It is only ever a registration, and every field of one is something a specific market demands — so it lives in `compliance`, alongside the rest of what that market asks for, and it says whose it is there too: `"compliance": { "inherit": true }` runs the profile on your organization's campaign and stops this call asking for any campaign field. Omitted, or `false`, gives the profile its own; inheriting takes *all* of your organization's, because inheritance resolves an owner rather than a single row. A profile with a `brand` of its own **cannot** inherit the campaign, and asking is refused with `400`: a campaign is filed against a brand registration, and your organization's campaign is filed against your organization's brand rather than this profile's. Inherit both, or own both. `channels.sms` is the market the profile starts in — one `country` and `number_type`. It decides what else this call asks for: the compliance catalog is keyed on that pair, and it determines which fields `brand` accepts and what `compliance` answers for. A profile is a tenant, not a market, so it can go on to send in several — but through `POST /v3/channels/sms` with the `x-profile-id` header, one market and its compliance at a time. Reads return every market as `channels.sms[]`, so the read shape is a list even where this one is not. `brand` is required when `number_type` is `TEN_DLC` — inherited or its own. A 10DLC registration has nothing to attach to without one, and no later call can supply it, so omitting it is refused with `400` rather than reported as outstanding. ## Use cases and volume A TCR campaign declares one to five `use_cases`, each with its own `sample_messages` — TCR attributes samples to the use case they illustrate, so they travel together. How that set registers is derived from `volume` and never declared. Below the low-volume threshold the campaign registers as `LOW_VOLUME` with every entry as a sub-use-case; above it, one entry registers as that use case outright and several register as `MIXED` with sub-use-cases. `MIXED` and `LOW_VOLUME` are therefore refused as `use_case` values: they describe the shape of a set, which is ours to work out. **Leaving `volume` out is accepted and costs more.** An absent value registers the campaign at the standard tier, which carries the higher fee — so say so when a campaign is low volume. Sole proprietor brands are the exception: their fee is fixed by entity type, and volume only decides the use case. ## Compliance `brand` is captured identically in every country. Everything a specific market demands on top of it — including every field of the campaign — goes in `compliance`, as key/value entries whose keys depend on the sender's country and type. US `TEN_DLC` registers with The Campaign Registry and asks for a substantial set; an alphanumeric sender may pre-register with documents, or need nothing at all. You do not have to know any of it. Omit `compliance` and the response lists exactly what is outstanding, with types and accepted values — or call `GET /v3/compliance/requirements` first. Anything Sent supplies on your behalf is never asked for, and is rejected if sent. Requirements can be conditional, and the condition is published as `required_when` so you can render a form from it rather than discover the rule by being rejected. Every US `TEN_DLC` campaign field carries `compliance.inherit != true` — send `"inherit": true` and none of them is asked for or accepted, because the profile is running on your organization's campaign. ## Uploading documents Send `application/json` for everything except a market that pre-registers a sender with supporting documents. For those, send `multipart/form-data` instead: put this entire document — unchanged — in a single field named `profile`, and attach each file under a field named after the compliance key it satisfies. Individual form fields per property are not read; the payload is always the one `profile` field. A pre-registration market has no `brand` and no `campaign` — those are asked for only where a regime registers one — so its `compliance` carries nothing at all, and the documents are the request: ```bash curl -X POST https://api.sent.dm/v3/sender-profiles \ -H 'x-api-key: YOUR_SECRET_TOKEN' \ -F 'profile={ "name": "Example Retail", "short_name": "EXAMPLE", "channels": { "sms": { "country": "XK", "number_type": "ALPHANUMERIC", "sender_value": "EXAMPLE" } } }' \ -F 'business_registration=@registration.pdf' \ -F 'letter_of_authorization=@loa.pdf' ``` `business_registration` and `letter_of_authorization` are illustrative. The real field names are whatever that market configures, so read them from `GET /v3/compliance/requirements`, which lists documents separately from the values — under `attachments`, each with the `field_name` to put the file under. A document has no JSON form, so naming one in `compliance` is refused with `400` rather than ignored: accepting it would report the requirement as satisfied while no file was ever stored. ## WhatsApp and RCS Neither can be inherited, so neither takes an `inherit`: the profile's WhatsApp account and RCS agent are its own or it has none. Sharing your organization's would share its inbox and its throughput, which makes the two indistinguishable to a recipient. `channels.whatsapp` names one of the accounts shared into your organization, and takes the two identifiers nothing else can supply: `waba_id`, because your organization holds one account per client, and `phone_number_id`, because an account may hold several numbers and choosing for you would decide which of your customer's numbers their traffic leaves from. Everything else is resolved from your organization — the Multi-Partner Solution the account arrived through, the client business portfolio that owns it, the access token and that token's expiry. None of them is accepted here: the first two are Meta's answer about provenance, so a value you sent could assert a partnership Meta disagrees with, and the token is minted per client business and rotates roughly every sixty days. `phone_number_id` is optional. Omit it to connect the account now and settle the number later — the channel reads as `provisioning` and the profile keeps sending from your organization's account until a number is named. `POST /v3/channels/whatsapp` connects an account to an existing profile and resolves the same fields the same way. An account of its own needs a sender of its own, so `channels.whatsapp` requires `channels.sms`. A profile sending SMS on your organization's sender shares that inbox and opt-out list, and is not a separate tenant to give an account to — asking is refused with `400`, before your organization is asked to resolve anything. `channels.rcs` records the RCS agent. RCS (Rich Communication Services) is the next-generation SMS standard built into Android — it lets you send branded messages with images, buttons and read receipts over the carrier network, with no app install required. Learn more in the [Google RCS documentation](https://developers.google.com/business-communications/rcs-business-messaging). All fields on the agent form are required except `opt_in_screenshot_url`. The full form must be submitted in one go so the carrier review has everything it needs. A carrier approval no API call can trigger is arranged offline, so the status reports `PROVISIONING` until it is. ## Responses `201` when the profile is complete on return — the fully-inherited case, where nothing needs registering. `202` when something is still provisioning, with per-capability status and outstanding requirements. `409` when the WhatsApp account supplied is already recorded. `400` covers a wrong value as well as a missing one: a missing brand under `TEN_DLC`, an unknown compliance key, a bad type, a sender id the market does not allow, or a `waba_id` that is not one of the accounts shared into your organization.
Delete a sender profile DELETE
Deletes one of your sender profiles and returns `204`. The delete is **soft**: the profile stops being usable and stops appearing in reads, and its message history is kept, because deleting a profile must not delete the record of what it sent. ## What it releases Anything the profile still held goes with it. A **phone number** returns to our inventory and can be given to whoever asks next — it does not stay reserved for you, and getting the same number back afterwards is not something we can promise. A **WhatsApp account of its own** is deregistered from Meta. Its routing rules stop being used, so nothing sends through the profile after this call. A profile that only inherits from its organization holds nothing of its own and releases nothing.