Skip to content

Update a topic

Change a topic's name, description or visibility.

http
PATCH /v1/topics/{id}

Requires a Full access API key.

Path parameters

ParameterTypeRequiredDescription
idstringYesThe topic id.

Body parameters

Send only the fields you want to change.

ParameterTypeRequiredDescription
namestringNoThe topic name. Max 120 characters. Renaming does not change the key.
descriptionstring | nullNoMax 255 characters. Send null to clear it.
visibilitystringNopublic or private.

key and default_subscription are immutable and rejected if sent — see below.

Example

bash
curl -X PATCH "https://api.sendgrail.com/v1/topics/$TOPIC_ID" \
  -H "Authorization: Bearer $SENDGRAIL_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Product news",
    "visibility": "private"
  }'
js
const res = await fetch(`https://api.sendgrail.com/v1/topics/${id}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.SENDGRAIL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Product news',
    visibility: 'private',
  }),
});

const topic = await res.json();

Response

json
{
  "object": "topic",
  "id": "7b2e6f90-3c11-4a5d-9b8e-1f0c4d6a2e59"
}

Fetch the updated object with Retrieve a topic.

Note that key is still product-updates after the rename. The key is generated once, from the name the topic had at creation, and then it stands on its own.

The key cannot be changed

key is what identifies the topic in an unsubscribe link — and those links are already sitting in inboxes, in mail you sent last month and cannot recall. Changing the key would break every one of them: a contact clicking "unsubscribe from Product updates" would land on a topic that no longer answers to that name, and their opt-out would silently fail. So the key is fixed.

Send it anyway and it is rejected, not ignored:

json
{
  "message": "The key cannot be changed — it is baked into unsubscribe links already sent.",
  "code": "validation_error",
  "errors": {
    "key": ["The key cannot be changed — it is baked into unsubscribe links already sent."]
  },
  "request_id": "8f2c1e64-1b17-4f8c-9f0e-3b6c1e0f5c31"
}

default_subscription cannot be changed either

default_subscription decides what a contact who never made a choice counts as: opt_out means they're in until they say otherwise, opt_in means they're out until they say so. Flipping it does not just change a setting — it changes the answer for every silent contact at once.

Turn opt_in into opt_out and you have just subscribed thousands of people who never asked to be. Turn opt_out into opt_in and you have unsubscribed thousands who never asked to leave. Neither is a change anyone can consent to after the fact, so SendGrail refuses to make it:

json
{
  "message": "The default subscription cannot be changed after the topic is created.",
  "code": "validation_error",
  "errors": {
    "default_subscription": ["The default subscription cannot be changed after the topic is created."]
  },
  "request_id": "8f2c1e64-1b17-4f8c-9f0e-3b6c1e0f5c31"
}

A 200 here would be worse than a 422: you'd believe the default had changed when it hadn't, or worse, you'd have changed it without realising who it moved.

If you genuinely need a different default, create a new topic — accepting that it gets a new key, and that contacts start out with no choice recorded against it.

Changing visibility is safe

visibility is the one property that can move. A private topic is not offered on the public preference page unless the contact is already subscribed to it — useful for a category you enrol people in deliberately rather than advertising. Flipping between public and private changes what the preference page shows; it does not change anybody's subscription.

Changing subscriptions

This endpoint edits the topic, not who is on it. To subscribe or unsubscribe a contact, go through the contact:

http
PATCH /v1/contacts/{id}/topics

See Contact topics.

Transactional email on your own domain.