---
title: "Edit a scheduled CRM email campaign"
method: PATCH
path: "/api/campaigns/{campaign_id}"
tags: ["crm-email"]
---

# Edit a scheduled CRM email campaign

`PATCH /api/campaigns/{campaign_id}`

Admin-only endpoint. Fully replaces a still-scheduled campaign's definition.

## Path parameters

- `campaign_id` string, uuid, required — Campaign UUID

## Request body

- CRMUpdateEmailCampaignRequest — Request model for editing a still-scheduled CRM email campaign.
  - `scheduled_at` string, date-time, required — When to send the campaign (timezone-aware).
  - `subject` string, required — Email subject.
  - `notes` string, nullable — Internal note on why the campaign is being sent; shown in the CRM only, never emailed.
  - `email_html` string, nullable — Composed HTML body (image placeholders already replaced by URLs).
  - `template_path` string, nullable — Storage path of the uploaded template under public/email/templates/.
  - `placeholder_images` object — Map of placeholder name -> image public URL used to compose email_html.
  - `patient_states` string[] — Stato paziente filters. Combined with registration_reasons per filter_match at send time.
  - `patient_filters` string[] — Deprecated alias of patient_states (kept for the current frontend payload).
  - `registration_reasons` string[] — Motivo iscrizione filters. Combined with patient_states per filter_match at send time.
  - `filter_match` 'any' | 'all' — How stato and motivo filters combine at send time: 'any' (OR, default) unions them; 'all' (AND) keeps only patients matching both a selected stato and motivo.
  - `recipient_emails` string[] — Explicit recipient email addresses (e.g. from an uploaded CSV). When present the campaign audience is this list. Capped at 50000 addresses.

## Response `200`

Successful Response

- CRMEmailCampaignDetail — Full definition of a single campaign, used to prefill the edit form.
  - `id` string, required — Campaign UUID.
  - `status` string, required — scheduled | sending | sent | failed | cancelled.
  - `scheduled_at` string, date-time, nullable — When the campaign is/was scheduled to send.
  - `subject` string, required — Email subject.
  - `notes` string, nullable — Internal note on why the campaign was sent; CRM-only.
  - `email_html` string, nullable — Composed HTML body (placeholders already replaced by URLs).
  - `template_path` string, nullable — Storage path of the uploaded template, if any.
  - `placeholder_images` object — Map of placeholder name -> image public URL used to compose email_html.
  - `audience_type` string, required — 'filters' or 'csv'.
  - `patient_states` string[] — Stato paziente filters (empty for a csv audience).
  - `registration_reasons` string[] — Motivo iscrizione filters (empty for a csv audience).
  - `filter_match` 'any' | 'all' — How stato/motivo filters combine ('any' or 'all').
  - `recipient_emails` string[] — Explicit recipient emails (only for a csv audience).
  - `created_at` string, date-time, required — When the campaign was created.

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/corabea/apis/corabea-api.md) · [All operations](https://skmtc.dev/corabea/apis/corabea-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/corabea/corabea-api/revisions/13c1bce1bdc4/schema)
