# Notify

`POST` `https://api.pushwoosh.com/messaging/v2/notify`

Erstellt und plant eine einzelne Nachricht.

<span id="request-structure" />

## Anfragestruktur

Der Anfragekörper ist eine `NotifyRequest` mit genau einer von zwei Arten:

- [`segment`](#notifysegment): Zielt auf ein Zielgruppensegment nach Segmentcode ab, oder – ohne zuerst ein Segment zu erstellen – auf einen [seglang](/de/developer/api-reference/segmentation-filters-api/segmentation-language/)-Ausdruck oder einen strukturierten Filterausdruck.
- [`transactional`](#notifytransactional): Sendet an eine explizite Liste von HWIDs, Benutzer-IDs, Push-Tokens oder Testgeräten.

```json title="Shape"
{
  "segment": { ... },      // ODER
  "transactional": { ... },
  "transaction_id": "unique-uuid"
}
```

| Feld | Typ | Beschreibung |
|---|---|---|
| `transaction_id` | string | Optional. Idempotenzschlüssel für die Anfrage – funktioniert sowohl mit `segment` als auch mit `transactional`. Ein wiederholter Aufruf mit derselben `transaction_id` innerhalb von 5 Minuten gibt den ursprünglichen `message_code` zurück, anstatt eine doppelte Nachricht zu senden. Verwenden Sie eine UUID oder einen anderen eindeutigen Wert pro logischem Sendevorgang. |

<Aside type="tip">
Übergeben Sie einen `X-Request-ID`-Header, um die erstellte Nachricht mit Ihrer Anfrage für eine durchgängige Nachverfolgung zu korrelieren – siehe [Request ID](/de/developer/api-reference/api-identifiers/#request-id).
</Aside>

<Aside type="caution" title="Nur der Schlüssel wird geprüft, nicht der Payload">
Die Deduplizierung erfolgt allein auf Basis der `transaction_id`. Wenn bei einem Wiederholungsversuch dieselbe `transaction_id` wiederverwendet wird, aber ein anderer `segment`- / `transactional`-Körper gesendet wird, wird dennoch der ursprüngliche `message_code` zurückgegeben und der neue Körper wird stillschweigend verworfen – er wird nicht mit der ersten Anfrage verglichen. Verwenden Sie eine `transaction_id` niemals für logisch unterschiedliche Nachrichten wieder.
</Aside>

<Aside type="tip">
Dies ist derselbe Deduplizierungsmechanismus wie `transactionId` in der veralteten [Messages API](/de/developer/api-reference/messages-api/), der dasselbe 5-minütige Speicherfenster teilt, sodass eine wiederholte Anfrage sowohl bei `/createMessage` als auch bei `Notify` dedupliziert wird. Er steht in keinem Zusammenhang mit dem `transaction_id`-Attribut bei [`PW_Conversion`](/de/product/audience-data-and-segmentation/events/conversion-events/#attributes-for-the-postevent-call)-Umsatzereignissen, das Pushwoosh unverändert speichert und nicht zur Deduplizierung verwendet.
</Aside>

## NotifySegment

Zielt auf Benutzer ab, die einem Zielgruppensegment oder einem Filterausdruck entsprechen. Legen Sie genau einen der Werte `code`, `expression` oder `filter_expression` fest. Für `expression` und `filter_expression` muss vorab kein Segment erstellt werden – der Ausdruck wird nur für diesen Sendevorgang inline ausgewertet.

<Aside type="note" title="Wahl zwischen Code und Inline-Ausdrücken">
Nur ein gespeichertes Segment, auf das mittels `code` verwiesen wird, kann die Vorkompilierung für die [High-Speed Delivery](/de/product/resources/high-speed-delivery/) nutzen. `expression` und `filter_expression` werden zur Sendezeit ausgewertet und niemals vorkompiliert.
</Aside>

| Feld | Typ | Beschreibung |
|---|---|---|
| `schedule` | [`Schedule`](#schedule) | Wann und wie gesendet werden soll. Erforderlich. |
| `application` | string | [Anwendungscode](/de/developer/api-reference/api-identifiers/#application-code). |
| `platforms` | array of [`Platform`](#platform-enum) | Plattformen, auf die die Nachricht abzielt. |
| `code` | string | [Segmentcode](/de/developer/api-reference/api-identifiers/#segment--filter-code) eines im Voraus gespeicherten Segments. Schließt sich gegenseitig mit `expression` und `filter_expression` aus. |
| `expression` | string | [Seglang](/de/developer/api-reference/segmentation-filters-api/segmentation-language/)-Ausdruck, der nur für diesen Sendevorgang ausgewertet wird – kein gespeichertes Segment erforderlich. Schließt sich gegenseitig mit `code` und `filter_expression` aus. |
| `filter_expression` | `FilterExpression` | Dieselbe Logik wie `expression`, jedoch als strukturiertes Objekt anstelle einer Seglang-Zeichenkette. Schließt sich gegenseitig mit `code` und `expression` aus. Das `FilterExpression`-Schema ist nicht öffentlich dokumentiert – fordern Sie es beim Pushwoosh-Support an, wenn Sie die strukturierte Form benötigen. |
| `payload` | [`Payload`](/de/developer/api-reference/messaging-api-v2/payload-reference/) | Push / SMS / Telegram / Kakao / LINE / WhatsApp / Viber / Facebook Messenger Payload. Schließt sich gegenseitig mit `email_payload` aus. |
| `email_payload` | [`EmailPayload`](/de/developer/api-reference/messaging-api-v2/email-payload-reference/) | E-Mail-Payload. |
| `campaign` | string | [Kampagnencode](/de/developer/api-reference/api-identifiers/#campaign-code), dem diese Nachricht zugeordnet werden soll. |
| `campaign_name` | string | Interner Name für diese Nachricht, wird als Zeilentitel in Message History und in deren Export angezeigt. Hat nichts mit `campaign` oben zu tun. Gruppiert keine Nachrichten und wirkt sich nicht auf die Zustellung aus. Maximal 255 Zeichen, wird gekürzt. Weglassen oder leer lassen, damit der Zeilentitel aus dem Inhalt des Payloads selbst stammt. |
| `frequency_capping` | [`FrequencyCapping`](#frequencycapping) | Frequenzbegrenzungen pro Benutzer. |
| `send_rate` | [`SendRate`](#sendrate) | Drosselung für den Sendevorgang. |
| `message_type` | [`MessageType`](#messagetype-enum) | `MESSAGE_TYPE_MARKETING` (Standard) oder `MESSAGE_TYPE_TRANSACTIONAL`. Steuert die Filterung der Kontrollgruppe. |
| `dynamic_content_placeholders` | map&lt;string, string&gt; | Ersetzt Platzhalter im Inhalt. |
| `meta_data` | object | Frei definierbare Metadaten, die an nachgelagerte Analysen weitergeleitet werden. |
| `use_latest_user_device` | bool | Wenn `true`, wird die Nachricht an das zuletzt aktive Gerät jedes Benutzers (das mit dem neuesten Last Application Open) zugestellt, anstatt an jedes vom Segment erfasste Gerät. Gilt für `platforms`: Nur Geräte auf diesen Plattformen werden berücksichtigt. Wenn keines davon Last Application Open-Daten hat, wird das erste passende Gerät verwendet, anstatt den Sendevorgang abzubrechen. Standard ist `false` (an jedes Gerät senden). |
| `control_group` | string | Code oder Name einer eigenen Holdout-Gruppe des Versands, die auf diese Nachricht angewendet wird. Sie schränkt nicht ein, welche [Kontrollgruppen](/de/product/audience-data-and-segmentation/control-groups/) gelten: Jede aktivierte Kontrollgruppe der Anwendung hält Benutzer von Marketing-Sendungen zurück, unabhängig davon, ob dieses Feld gesetzt ist. Schließt sich mit `holdout_percentage` gegenseitig aus. |
| `holdout_percentage` | uint32 | Zieht diesen Anteil des Segments, `1`–`20`, in eine Kontrollgruppe, die nur für diesen Versand gilt, zusätzlich zu den aktivierten Kontrollgruppen der Anwendung, um die Wirkung einer einzelnen Kampagne zu messen, ohne die gemeinsamen Kontrollgruppen aufzubrauchen. `0` (Standard) deaktiviert sie. Schließt sich mit `control_group` gegenseitig aus. |

<Aside type="caution" title="Wichtig">
Pushwoosh benennt die Holdout-Gruppe `__holdout_<campaign code>` (oder `__holdout_<message code>` bei einem Versand ohne `campaign`) und verwendet dieselbe Gruppe mit ihrem ursprünglichen Prozentsatz für jeden späteren Versand mit demselben Code wieder. Die Auswahl wird bei der ersten Erstellung festgeschrieben. Diese Gruppe erscheint nie unter **Einstellungen > Kontrollgruppen**, und das Ändern ihrer Größe, das Neumischen, Deaktivieren oder Löschen gibt `FailedPrecondition` zurück, weil eine Änderung während der Messung den Vergleich ungültig machen würde.
</Aside>

Geräte, die in die Holdout-Gruppe gezogen wurden, werden auf dieselbe Weise von der Zustellung ausgeschlossen wie durch die [Kontrollgruppen](/de/product/audience-data-and-segmentation/control-groups/#how-the-control-group-affects-message-delivery) der Anwendung. Sie erhalten die Nachricht nicht, und das Tracking-Log erfasst den Ausschluss als `Device is in control group`. Ein `message_type` von `MESSAGE_TYPE_TRANSACTIONAL` überspringt diesen Ausschluss vollständig, genau wie bei den Kontrollgruppen der Anwendung.

Wird `holdout_percentage` zusammen mit `control_group` gesetzt oder ist `holdout_percentage` größer als `20`, wird `400` zurückgegeben:

```json title="Invalid holdout_percentage"
{
  "code": 3,
  "message": "invalid argument",
  "details": [
    {
      "@type": "type.googleapis.com/google.rpc.BadRequest",
      "fieldViolations": [
        {
          "field": "holdout_percentage",
          "description": "holdout_percentage and control_group are mutually exclusive"
        }
      ]
    },
    {
      "@type": "type.googleapis.com/google.rpc.ErrorInfo",
      "reason": "InvalidHoldoutPercentage",
      "domain": "api.pushwoosh.com",
      "metadata": {}
    }
  ]
}
```

### Beispiel: An ein Segment senden

```bash
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "segment": {
      "application": "XXXXX-XXXXX",
      "platforms": ["IOS", "ANDROID"],
      "code": "active_users",
      "payload": {
        "content": {
          "localized_content": {
            "en": {
              "ios":     { "body": "Hello!" },
              "android": { "body": "Hello!" }
            }
          }
        }
      },
      "schedule": { "at": "2026-05-01T12:00:00Z" },
      "message_type": "MESSAGE_TYPE_MARKETING"
    }
  }'
```

## NotifyTransactional

Sendet an eine explizite Liste von Empfängern.

| Feld | Typ | Beschreibung |
|---|---|---|
| `schedule` | [`Schedule`](#schedule) | Erforderlich. |
| `application` | string | [Anwendungscode](/de/developer/api-reference/api-identifiers/#application-code). |
| `platforms` | array of [`Platform`](#platform-enum) | Plattformen, auf die die Nachricht abzielt. |
| `test_devices` | bool | Wenn `true`, nur an die Testgeräte der App senden. |
| `hwids` | `{ "list": [string, ...] }` | Nur an diese [HWIDs](/de/developer/pushwoosh-knowledge-hub/device-identifiers/#hwid) senden. |
| `users` | `{ "list": [string, ...] }` | Nur an diese [Benutzer-IDs](/de/developer/pushwoosh-knowledge-hub/users-userids/) senden. |
| `push_tokens` | `{ "list": [string, ...] }` | Nur an diese [Push-Tokens](/de/developer/pushwoosh-knowledge-hub/device-identifiers/#push-token) senden. |
| `payload` | [`Payload`](/de/developer/api-reference/messaging-api-v2/payload-reference/) | Push / SMS / Telegram / Kakao / LINE / WhatsApp / Viber / Facebook Messenger Payload. |
| `email_payload` | [`EmailPayload`](/de/developer/api-reference/messaging-api-v2/email-payload-reference/) | E-Mail-Payload. |
| `return_unknown_identifiers` | bool | Wenn `true`, listet `unknown_identifiers` in der Antwort die nicht gefundenen Kennungen auf. |
| `use_latest_user_device` | bool | Gilt nur, wenn Sie auf `users` abzielen. Gleiches Verhalten wie bei `NotifySegment` oben – stellt eine Nachricht pro Benutzer anstatt pro Gerät zu, beschränkt auf `platforms`. Standard ist `false`. |
| `campaign`, `campaign_name`, `frequency_capping`, `send_rate`, `message_type`, `dynamic_content_placeholders`, `meta_data` | | Siehe `NotifySegment` oben. |

`test_devices`, `hwids`, `users` und `push_tokens` schließen sich gegenseitig aus. Es muss genau einer festgelegt werden.

### Beispiel: Transaktional nach Benutzer-IDs

```bash
curl -X POST https://api.pushwoosh.com/messaging/v2/notify \
  -H "Authorization: Token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "transactional": {
      "application": "XXXXX-XXXXX",
      "platforms": ["IOS", "ANDROID"],
      "users": { "list": ["user-123", "user-456"] },
      "payload": {
        "content": {
          "localized_content": {
            "en": { "ios": { "body": "Your order has shipped." } }
          }
        }
      },
      "schedule": { "at": "2026-05-01T12:00:00Z" },
      "message_type": "MESSAGE_TYPE_TRANSACTIONAL",
      "return_unknown_identifiers": true,
      "use_latest_user_device": true
    }
  }'
```

<span id="response" />

## Antwort

```json
{
  "result": {
    "message_code": "XXXXX-XXXXX-XXXXX",
    "unknown_identifiers": []
  }
}
```

| Feld | Typ | Beschreibung |
|---|---|---|
| `message_code` | string | Eindeutiger [Nachrichtencode](/de/developer/api-reference/api-identifiers/#message-code). Verwenden Sie ihn mit [`/getMessageDetails`](/de/developer/api-reference/messages-api/#getmessagedetails) und den Endpunkten für Nachrichtenstatistiken. |
| `unknown_identifiers` | array of string | Kennungen, die im Konto nicht gefunden wurden. Wird nur gefüllt, wenn `return_unknown_identifiers: true` für die Art `transactional` festgelegt wurde. |

## Geteilte Typen

### Schedule

```json
{
  "at": "2026-05-01T12:00:00Z",
  "follow_user_timezone": true,
  "past_timezones_behaviour": "PAST_TIMEZONES_BEHAVIOUR_SEND_IMMEDIATELY"
}
```

| Feld | Typ | Beschreibung |
|---|---|---|
| `at` | timestamp | Absoluter Sendezeitpunkt (RFC 3339). Liegt er in der Vergangenheit, setzt Pushwoosh den Zeitpunkt des Anfrageeingangs ein. Ist `follow_user_timezone` nicht gesetzt oder `false`, wird die Nachricht damit sofort an alle gesendet. Zu `follow_user_timezone: true` siehe den Hinweis unten. Maximal 30 Tage in der Zukunft. |
| `after` | duration | Alternative zu `at`. Senden nach diesem Versatz von „jetzt“ (z. B. `"3600s"`). Maximal 30 Tage. |
| `follow_user_timezone` | bool | Wenn `true`, empfängt jedes Gerät die Nachricht zum Zeitpunkt `at` in seiner lokalen Zeitzone. |
| `past_timezones_behaviour` | enum | `PAST_TIMEZONES_BEHAVIOUR_SEND_IMMEDIATELY` (Standard), `PAST_TIMEZONES_BEHAVIOUR_DO_NOT_SEND` oder `PAST_TIMEZONES_BEHAVIOUR_NEXT_DAY`. Nur sinnvoll, wenn `follow_user_timezone` auf `true` gesetzt ist oder `best_time_to_send` gesetzt ist. |
| `best_time_to_send` | timestamp | Optional. Nur für Segment-Versände. Jedes Gerät erhält die Nachricht zu seiner eigenen besten Stunde innerhalb von 24 Stunden ab diesem Zeitpunkt. Geräte ohne beste Stunde erhalten sie zum Datum und zur Uhrzeit von `at` / `after` in ihrer lokalen Zeitzone. Siehe [Beste Sendezeit](#best-time-to-send). |

<Aside type="caution" title="Ein vergangener Sendezeitpunkt ist mit follow_user_timezone nicht für alle sofort">
Bei `follow_user_timezone: true` wird das ersetzte „jetzt“ weiterhin in lokale Zeitfenster pro Gerät aufgeteilt und nicht an alle Geräte gleichzeitig zugestellt. Zeitzonen hinter UTC haben diesen Moment lokal noch nicht erreicht und erhalten die Nachricht bis zu 12 Stunden später. Zeitzonen vor UTC haben diesen Moment lokal bereits überschritten und folgen daher `past_timezones_behaviour`: sofort gesendet, übersprungen (`DO_NOT_SEND`) oder zur selben Ortszeit um einen Tag verschoben (`NEXT_DAY`). Dieselbe Aufteilung gilt für den Fallback von [`best_time_to_send`](#best-time-to-send).
</Aside>

<span id="best-time-to-send" />

#### Beste Sendezeit

`best_time_to_send` ist das API-Gegenstück zur Option [Beste Zeit](/de/product/messaging-channels/push-notifications/send-push-notifications/one-time-push/#best-time-paid-subscription-required) im Control Panel. `at` / `after` legt den Fallback für Geräte fest, für die nicht genug Daten für eine beste Stunde vorliegen. Pushwoosh nimmt Datum und Uhrzeit von `at` / `after` in UTC und stellt den Fallback zu diesem Datum und dieser Uhrzeit in der lokalen Zeitzone jedes Geräts zu, wie bei `follow_user_timezone: true`. Das geschieht implizit: Lassen Sie `follow_user_timezone` ungesetzt, da `true` mit `BestTimeToSendWithUserTimezone` abgelehnt wird. Im folgenden Beispiel erhalten Geräte ohne beste Stunde die Nachricht am 1. Mai um 18:00 Uhr Ortszeit. Wo diese Ortszeit beim Start des Versands bereits verstrichen ist, gilt `past_timezones_behaviour`.

```json
{
  "at": "2026-05-01T18:00:00Z",
  "best_time_to_send": "2026-05-01T00:00:00Z"
}
```

Pushwoosh lehnt die Anfrage mit `400` ab, sofern nicht alle folgenden Bedingungen erfüllt sind:

- Die Anfrage verwendet die Art `segment`. `transactional`-Versände unterstützen `best_time_to_send` nicht.
- `follow_user_timezone` ist nicht gesetzt oder `false`.
- Der Sendezeitpunkt aus `at` / `after` liegt in der Zukunft. Ein vergangenes `at`, `after: "0s"` oder ein weggelassenes `after` gelten als „jetzt senden“ und werden abgelehnt.
- `best_time_to_send` liegt nicht vor der nächsten vollen Stunde und nicht mehr als 30 Tage in der Zukunft. Der Wert wird auf die volle Stunde abgerundet.
- Der Sendezeitpunkt aus `at` / `after` liegt nicht später als `best_time_to_send` plus 24 Stunden.

Der `reason` des Fehlers (im Detail `ErrorInfo`) nennt die fehlgeschlagene Prüfung:

| `reason` | Ursache |
|---|---|
| `BestTimeToSendWithUserTimezone` | `follow_user_timezone` ist `true`. |
| `BestTimeToSendTooEarly` | `best_time_to_send` liegt vor der nächsten vollen Stunde. |
| `BestTimeToSendTooFarInFuture` | `best_time_to_send` liegt mehr als 30 Tage in der Zukunft. |
| `SendDateAfterBestTimeToSend` | `at` / `after` liegt später als `best_time_to_send` plus 24 Stunden. |
| `BestTimeToSendNotAllowed` | `best_time_to_send` ist bei einem `transactional`-Versand gesetzt. |
| `BestTimeToSendWithSendNow` | `at` / `after` ergibt „jetzt“ (vergangenes `at` oder `after` gleich null). |

### FrequencyCapping

Frequenzbegrenzungen pro Benutzer für Marketing-Sendungen. Um die Begrenzung zu deaktivieren, lassen Sie `frequency_capping` ganz weg oder senden Sie `days: 0` zusammen mit `count: 0`.

```json
{ "days": 7, "count": 3, "exclude": false, "avoid": true }
```

- `days` (int, 1–30 oder `0` zum Deaktivieren der Begrenzung): Rückblickfenster. Muss zusammen mit `count` gesendet werden – wenn einer `0` ist, muss der andere ebenfalls `0` sein; das Senden eines Wertes als `0`, während der andere ungleich null ist, gibt `400` zurück.
- `count` (int, 1 oder höher, oder `0` zum Deaktivieren der Begrenzung): maximale Anzahl von Nachrichten, die innerhalb von `days` erlaubt sind. Dieselbe Koppelungsregel wie bei `days` oben.
- `exclude` (bool): schließt Benutzer, die das Limit bereits erreicht haben, hart aus.
- `avoid` (bool): vermeidet Benutzer, die das Limit bereits erreicht haben, weich (sie werden weiterhin für die Analytik gezählt).

<Aside type="caution" title="Wichtig">
Das Senden von `days` und `count` mit nicht übereinstimmenden Nullwerten (z. B. `{"days": 0, "count": 5}`) gibt `400` zurück. Diese Validierung ist eine Breaking Change für `Notify` – Clients, die sich zuvor darauf verlassen haben, dass eine einzelne `0` stillschweigend ignoriert wird, erhalten jetzt stattdessen einen Fehler.
</Aside>

### SendRate

```json
{ "value": 500, "bucket": "1s", "avoid": false }
```

Drosselt den Sendevorgang. `value` ist die Anzahl der Nachrichten pro `bucket`; ein typischer `bucket` ist `"1s"`.

### Platform-Enum

`IOS`, `ANDROID`, `OSX`, `WINDOWS`, `AMAZON`, `SAFARI`, `CHROME`, `FIREFOX`, `IE`, `EMAIL`, `HUAWEI_ANDROID`, `SMS`, `WEB`, `KAKAO`, `TELEGRAM`, `LINE`, `WHATS_APP`, `VIBER`, `FB_MESSENGER`.

### MessageType-Enum

- `MESSAGE_TYPE_UNSPECIFIED`: entspricht `MESSAGE_TYPE_MARKETING`.
- `MESSAGE_TYPE_MARKETING`: unterliegt der Filterung durch Kontrollgruppen und der Frequenzbegrenzung.
- `MESSAGE_TYPE_TRANSACTIONAL`: überspringt die Filterung durch Kontrollgruppen und die Frequenzbegrenzung. Verwenden Sie dies für Bestellbestätigungen, OTPs und ähnliche kritische Abläufe.

## Verwandte Themen

<CardGrid>
  <LinkCard title="Notify Batch" href="/developer/api-reference/messaging-api-v2/notify-batch/" />
  <LinkCard title="Abbrechen" href="/developer/api-reference/messaging-api-v2/cancel/" />
  <LinkCard title="Payload-Referenz" href="/developer/api-reference/messaging-api-v2/payload-reference/" />
  <LinkCard title="E-Mail-Payload-Referenz" href="/developer/api-reference/messaging-api-v2/email-payload-reference/" />
  <LinkCard title="Migration von v1" href="/developer/api-reference/messaging-api-v2/migration-from-v1/" />
</CardGrid>