# Update a campaign

> Changes a campaign's name, message, channel, phone number, or pace while it's a draft or paused, and archives or unarchives it when it isn't running.

Source: https://www.bloomtext.com/developers/api/reference/update-campaign/

`PATCH /campaigns/{campaignId}`

Changes a campaign's name, message, channel, phone number, or pace while it's a draft or paused, and archives or unarchives it when it isn't running.

**Credentials:** [API key](https://www.bloomtext.com/developers/api/api-keys/) or an [org admin’s OAuth token](https://www.bloomtext.com/developers/api/oauth/) · **Scope:** `messages.write`

### Path parameters

- `campaignId` (UUID, required): ID of the campaign.

### Body parameters

Only the fields you send change.

- `name` (string): A name for staff.

- `body` (string): The message. Draft or paused campaigns only.

- `channel` (secure, sms): `secure` or `sms`. Draft or paused campaigns only.

- `from` (string): The phone number to send from. Draft campaigns only.

- `send_interval_seconds` (number): Seconds between messages.

- `archived` (boolean): Archive or unarchive the campaign. Not while it's running.

### Returns

Returns `200 OK` with the [Campaign object](https://www.bloomtext.com/developers/api/reference/campaign-object/).

### Errors

Failed requests return `application/problem+json` [problem details](https://www.bloomtext.com/developers/api/errors/). The errors specific to this endpoint:

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_request` | The request is malformed, such as invalid JSON. |
| 401 | `invalid_token` | The API key or access token is missing, expired, or revoked. |
| 403 | `insufficient_scope` | The credential doesn’t have the scope this endpoint needs. |
| 404 | `not_found` | The resource doesn’t exist, or isn’t visible to this credential. |
| 409 | `campaign_not_editable` | The campaign is running, completed, or stopped. Pause it to change the message; archive it only when it isn't running. |
| 422 | `validation_failed` | A field failed validation. See `field_errors`. |
| 429 | `rate_limited` | Too many requests. Retry after `Retry-After` seconds. |

```bash filename="Request"
curl -X PATCH "https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65" \
  -H "Authorization: Bearer $BLOOMTEXT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"send_interval_seconds":2}'
```

```js filename="Request"
const response = await fetch('https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.BLOOMTEXT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"send_interval_seconds":2}),
})

if (!response.ok) throw new Error(`BloomText API error: ${response.status}`)
const data = await response.json()
```

```python filename="Request"
import os

import requests

response = requests.patch(
    "https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65",
    headers={
        "Authorization": f"Bearer {os.environ['BLOOMTEXT_API_KEY']}",
    },
    json={"send_interval_seconds":2},
)
response.raise_for_status()
data = response.json()
```

```go filename="Request"
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	body := bytes.NewBufferString(`{"send_interval_seconds":2}`)
	req, err := http.NewRequest("PATCH", "https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("BLOOMTEXT_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.Status, string(out))
}
```

```ruby filename="Request"
require "net/http"
require "json"

uri = URI("https://api.bloomtext.com/v1/campaigns/c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65")
request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("BLOOMTEXT_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = { send_interval_seconds: 2 }.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
data = JSON.parse(response.body)
```

```json filename="Response · 200 OK"
{
  "id": "c4a7e2d1-9b3f-4e6a-8d2c-1f0e9b8a7c65",
  "name": "Flu shot reminders, October",
  "status": "draft",
  "channel": "secure",
  "body": "Flu shots are available at Example Clinic. Reply here to book a time.",
  "phone_number": {
    "number": "+15125550100",
    "team": "Front desk"
  },
  "sender": {
    "id": "b7e1c3a9-4d2f-4a8b-9c6e-0f1d2e3a4b5c",
    "name": "Reminder service",
    "kind": "api_key"
  },
  "send_interval_seconds": 2,
  "counts": {
    "recipients": 0,
    "pending": 0,
    "sent": 0,
    "delivered": 0,
    "failed": 0,
    "skipped": 0
  },
  "archived": false,
  "created_at": "2026-09-21T15:04:05Z",
  "started_at": null,
  "finished_at": null
}
```
