Notify
POST https://api.pushwoosh.com/messaging/v2/notify
Crée et planifie un message unique.
Structure de la requête
Anchor link toLe corps de la requête est un NotifyRequest avec exactement l’un des deux types :
segment: cible un segment d’audience par code de segment, ou — sans créer de segment au préalable — une expression seglang ou une expression de filtre structurée.transactional: envoie à une liste explicite de HWID, d’ID utilisateur, de jetons push ou d’appareils de test.
{ "segment": { ... }, // OU "transactional": { ... }, "transaction_id": "unique-uuid"}| Champ | Type | Description |
|---|---|---|
transaction_id | string | Optionnel. Clé d’idempotence pour la requête — fonctionne avec segment et transactional. Un appel répété avec le même transaction_id dans les 5 minutes renvoie le message_code original au lieu d’envoyer un message en double. Utilisez un UUID ou une autre valeur unique par envoi logique. |
NotifySegment
Anchor link toCible les utilisateurs qui correspondent à un segment d’audience ou à une expression de filtre. Définissez exactement l’un des champs suivants : code, expression ou filter_expression. Pour expression et filter_expression, aucun segment ne doit être créé au préalable — l’expression est évaluée en ligne pour cet envoi uniquement.
| Champ | Type | Description |
|---|---|---|
schedule | Schedule | Quand et comment envoyer. Requis. |
application | string | Code d’application. |
platforms | array of Platform | Plateformes ciblées par le message. |
code | string | Code de segment d’un segment enregistré à l’avance. Mutuellement exclusif avec expression et filter_expression. |
expression | string | Expression Seglang, évaluée pour cet envoi uniquement — aucun segment enregistré n’est requis. Mutuellement exclusif avec code et filter_expression. |
filter_expression | FilterExpression | La même logique que expression, sous forme d’objet structuré au lieu d’une chaîne seglang. Mutuellement exclusif avec code et expression. Le schéma FilterExpression n’est pas documenté publiquement — demandez-le au support de Pushwoosh si vous avez besoin de la forme structurée. |
payload | Payload | Payload Push / SMS / Telegram / Kakao / LINE / WhatsApp / Viber / Facebook Messenger. Mutuellement exclusif avec email_payload. |
email_payload | EmailPayload | Payload d’e-mail. |
campaign | string | Code de campagne auquel attribuer ce message. |
campaign_name | string | Nom interne de ce message, affiché comme le titre de la ligne dans Message History et dans son export. Sans rapport avec campaign ci-dessus. Ne regroupe pas les messages et n’affecte pas la livraison. Max 255 caractères, tronqué. Omettez-le ou laissez-le vide pour que le titre de la ligne provienne du contenu du payload lui-même. |
frequency_capping | FrequencyCapping | Limites de fréquence par utilisateur. |
send_rate | SendRate | Limitation du débit pour l’envoi. |
silent_hours | SilentHours | Facultatif. Envoie le message sans tenir compte des heures de silence de l’application. |
message_type | MessageType | MESSAGE_TYPE_MARKETING (par défaut) ou MESSAGE_TYPE_TRANSACTIONAL. Contrôle le filtrage du groupe de contrôle. |
dynamic_content_placeholders | map<string, string> | Remplace les placeholders dans le contenu. |
meta_data | object | Métadonnées de forme libre transmises aux analyses en aval. |
use_latest_user_device | bool | Si true, livre le message à l’appareil le plus récemment actif de chaque utilisateur (celui avec la dernière ouverture d’application la plus récente) au lieu de chaque appareil correspondant au segment. Limité aux platforms : seuls les appareils sur ces plateformes sont pris en compte, et si aucun n’a de données de dernière ouverture d’application, le premier appareil correspondant est utilisé au lieu d’annuler l’envoi. La valeur par défaut est false (envoyer à chaque appareil). |
geo_zone | GeoZone | Facultatif. Restreint l’audience aux appareils dont la dernière position enregistrée se trouve à l’intérieur d’un cercle que vous définissez dans cette requête. Il est combiné avec code, expression ou filter_expression par AND : un appareil doit correspondre au segment et se trouver dans le cercle. Les appareils sans position enregistrée sont ignorés. Non disponible dans NotifyTransactional. |
control_group | string | Code ou nom du groupe d’exclusion propre à un envoi à appliquer à ce message. Il ne restreint pas les groupes de contrôle qui s’appliquent : chaque groupe de contrôle activé de l’application exclut des utilisateurs des envois marketing, que ce champ soit défini ou non. Mutuellement exclusif avec holdout_percentage. |
holdout_percentage | uint32 | Prélève cette part du segment, de 1 à 20, dans un groupe de contrôle limité à cet envoi, en plus des groupes de contrôle activés de l’application, afin de mesurer l’impact d’une seule campagne sans puiser dans les groupes partagés. 0 (par défaut) le désactive. Mutuellement exclusif avec control_group. |
Les appareils tirés dans le groupe d’exclusion sont exclus de la livraison de la même manière qu’avec les groupes de contrôle de l’application. Aucun message ne leur est envoyé, et le journal de suivi enregistre l’abandon sous la forme Device is in control group. Un message_type égal à MESSAGE_TYPE_TRANSACTIONAL ignore entièrement cette exclusion, comme pour les groupes de contrôle de l’application.
Définir holdout_percentage en même temps que control_group, ou un holdout_percentage supérieur à 20, renvoie 400 :
{ "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": {} } ]}Exemple : Envoi à un segment
Anchor link tocurl -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
Anchor link toEnvoie à une liste explicite de destinataires.
| Champ | Type | Description |
|---|---|---|
schedule | Schedule | Requis. |
application | string | Code d’application. |
platforms | array of Platform | Plateformes ciblées par le message. |
test_devices | bool | Si true, envoie uniquement aux appareils de test de l’application. |
hwids | { "list": [string, ...] } | Envoyer uniquement à ces HWID. |
users | { "list": [string, ...] } | Envoyer uniquement à ces ID utilisateur. |
push_tokens | { "list": [string, ...] } | Envoyer uniquement à ces jetons push. |
payload | Payload | Payload Push / SMS / Telegram / Kakao / LINE / WhatsApp / Viber / Facebook Messenger. |
email_payload | EmailPayload | Payload d’e-mail. |
return_unknown_identifiers | bool | Si true, la liste unknown_identifiers de la réponse contient les identifiants qui n’ont pas été trouvés. |
registration_type | RegistrationType | Comportement pour les hwids qui ne sont pas encore enregistrés dans Pushwoosh. La valeur par défaut est REGISTRATION_TYPE_DEFAULT, qui les ignore. Définissez REGISTRATION_TYPE_FORCE pour enregistrer de nouvelles adresses e-mail ou de nouveaux numéros de téléphone et leur envoyer le message dans la même requête. |
use_latest_user_device | bool | S’applique uniquement lorsque vous ciblez des users. Même comportement que dans NotifySegment ci-dessus — livre un message par utilisateur au lieu d’un par appareil, limité aux platforms. La valeur par défaut est false. |
campaign, campaign_name, frequency_capping, send_rate, silent_hours, message_type, dynamic_content_placeholders, meta_data | Voir NotifySegment ci-dessus. |
test_devices, hwids, users et push_tokens sont mutuellement exclusifs. Un seul doit être défini.
Envoyer à de nouvelles adresses e-mail et de nouveaux numéros de téléphone
Anchor link toPour l’e-mail, les SMS, WhatsApp, LINE, Viber et Kakao, le hwid est la destination elle-même, par exemple l’adresse e-mail ou le numéro de téléphone. Pour envoyer à un hwid qui n’est pas encore enregistré, indiquez-le dans hwids et définissez registration_type sur REGISTRATION_TYPE_FORCE. Pushwoosh l’enregistre et livre le message dans la même requête : vous n’avez donc pas besoin d’appeler /registerDevice ou /registerEmail au préalable.
registration_type fonctionne uniquement avec hwids. Avec users, un ID utilisateur inconnu n’est pas créé, quelle que soit la valeur de registration_type.
Écrivez chaque hwid dans le format sous lequel /registerDevice le stocke pour ce canal :
| Canal | Format du hwid | Exemple |
|---|---|---|
| Adresse e-mail | new.customer@example.com | |
| SMS | Numéro de téléphone au format international | +14155552671 |
Numéro de téléphone avec le préfixe whatsapp: | whatsapp:+14155552671 | |
| Kakao | Numéro de téléphone avec le préfixe kakao: | kakao:+821012345678 |
| Viber | Numéro de téléphone avec le préfixe viber:. Pushwoosh ajoute le préfixe s’il est absent | viber:+14155552671 |
| LINE | ID utilisateur LINE | U4af4980629a1b2c3d4e5f6a7b8c9d0e1 |
Conservez les préfixes whatsapp: et kakao:. Sans eux, le numéro est interprété comme un hwid SMS. Si ce numéro est déjà enregistré pour les SMS, l’envoi trouve le hwid SMS, qui ne correspond pas à la plateforme ciblée, et le destinataire est ignoré.
Pushwoosh vérifie les numéros de téléphone uniquement avec return_unknown_identifiers: true. Dans ce cas, un hwid SMS, WhatsApp ou Kakao qui n’est pas un numéro de téléphone valide n’est pas enregistré et est renvoyé dans unknown_identifiers. Sans cet indicateur, la valeur est enregistrée telle quelle.
REGISTRATION_TYPE_FORCE n’enregistre pas de hwids sur les plateformes push, Telegram ou Facebook Messenger, car elles nécessitent un jeton fourni par le SDK ou la messagerie. Un hwid inconnu sur ces plateformes est ignoré sans avertissement. Il n’est pas renvoyé dans unknown_identifiers, et rien ne lui est envoyé.
Pour WhatsApp, l’enregistrement d’un numéro n’ouvre pas la fenêtre de service client de 24 heures. Un numéro qui ne vous a pas encore écrit ne peut recevoir qu’un modèle préapprouvé défini dans whatsapp.content_id, et non un whatsapp.content libre.
Exemple : Envoi à une nouvelle adresse e-mail
Anchor link tocurl -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": ["EMAIL"], "hwids": { "list": ["new.customer@example.com"] }, "registration_type": "REGISTRATION_TYPE_FORCE", "email_payload": { "subject": { "en": "Welcome aboard" }, "body": "<p>Thanks for signing up!</p>" }, "schedule": { "at": "2026-05-01T12:00:00Z" }, "message_type": "MESSAGE_TYPE_TRANSACTIONAL", "return_unknown_identifiers": true } }'Exemple : Transactionnel par ID utilisateur
Anchor link tocurl -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 } }'Réponse
Anchor link to{ "result": { "message_code": "XXXXX-XXXXX-XXXXX", "unknown_identifiers": [] }}| Champ | Type | Description |
|---|---|---|
message_code | string | Code de message unique. Utilisez-le avec /getMessageDetails et les points de terminaison de statistiques de message. |
unknown_identifiers | array of string | Identifiants non trouvés sur le compte. Rempli uniquement pour un envoi transactional avec return_unknown_identifiers: true ou avec un ciblage par push_tokens. Les identifiants enregistrés via REGISTRATION_TYPE_FORCE n’y figurent pas. |
/getMessageDetails ne trouve pas un message transactional envoyé immédiatement à moins de 10 utilisateurs et à moins de 10 appareils, car un tel message n’est pas stocké. Consultez Messages envoyés immédiatement à moins de 10 destinataires.
Aucun destinataire trouvé
Anchor link toAvec return_unknown_identifiers: true ou un ciblage par push_tokens, Pushwoosh recherche chaque destinataire avant de créer le message. Si aucun d’eux n’est enregistré, Notify renvoie HTTP 400 avec cette erreur, et aucun message n’est créé :
{ "code": 9, "message": "No recipients found", "details": [ ... ]}Si au moins un destinataire est trouvé, la requête aboutit et les autres sont listés dans unknown_identifiers. Pour envoyer plutôt à de nouvelles adresses e-mail ou de nouveaux numéros de téléphone, définissez registration_type sur REGISTRATION_TYPE_FORCE.
Pour l’e-mail, les adresses non valides et celles qui ont déjà généré un rebond sont retirées avant cette vérification, sans figurer dans unknown_identifiers. S’il ne reste aucune adresse après cela, Notify renvoie 200 avec un message_code, mais aucun message n’est créé et rien n’est envoyé.
Types partagés
Anchor link toSchedule
Anchor link to{ "at": "2026-05-01T12:00:00Z", "follow_user_timezone": true, "past_timezones_behaviour": "PAST_TIMEZONES_BEHAVIOUR_SEND_IMMEDIATELY"}| Champ | Type | Description |
|---|---|---|
at | timestamp | Heure d’envoi absolue (RFC 3339). Maximum 30 jours dans le futur. Avec follow_user_timezone non défini ou false, un at passé est remplacé par l’heure de réception de la requête : le message part donc immédiatement pour tout le monde. Avec follow_user_timezone: true, un at passé est conservé tel quel. Voir l’avertissement ci-dessous. |
after | duration | Alternative à at. Envoyer après ce décalage par rapport à “maintenant” (par ex. "3600s"). Maximum 30 jours. |
follow_user_timezone | bool | Si true, chaque appareil reçoit le message à l’heure at dans son fuseau horaire local. |
past_timezones_behaviour | enum | PAST_TIMEZONES_BEHAVIOUR_SEND_IMMEDIATELY (par défaut), PAST_TIMEZONES_BEHAVIOUR_DO_NOT_SEND, ou PAST_TIMEZONES_BEHAVIOUR_NEXT_DAY. N’a de sens que si follow_user_timezone est true ou si best_time_to_send est défini. |
best_time_to_send | timestamp | Facultatif. Envois à un segment uniquement. Chaque appareil reçoit le message à sa propre meilleure heure dans les 24 heures qui suivent ce moment. Les appareils sans meilleure heure le reçoivent à la date et à l’heure de at / after dans leur fuseau horaire local. Voir Meilleur moment d’envoi. |
Meilleur moment d’envoi
Anchor link tobest_time_to_send est l’équivalent API de l’option Meilleur moment du Control Panel. at / after définit l’envoi de repli pour les appareils qui n’ont pas assez de données pour déterminer une meilleure heure. Pushwoosh prend la date et l’heure UTC de at / after et livre l’envoi de repli à cette date et à cette heure dans le fuseau horaire local de chaque appareil, comme avec follow_user_timezone: true. Ce comportement s’applique implicitement : laissez follow_user_timezone non défini, car true est rejeté avec BestTimeToSendWithUserTimezone. Dans l’exemple ci-dessous, les appareils sans meilleure heure reçoivent le message à 18:00 heure locale le 1er mai. Là où cette heure locale est déjà passée au début de l’envoi, past_timezones_behaviour s’applique.
{ "at": "2026-05-01T18:00:00Z", "best_time_to_send": "2026-05-01T00:00:00Z"}Pushwoosh rejette la requête avec 400 sauf si toutes ces conditions sont remplies :
- La requête utilise le type
segment. Les envoistransactionalne prennent pas en chargebest_time_to_send. follow_user_timezonen’est pas défini ou vautfalse.- L’heure d’envoi issue de
at/afterest dans le futur. Unatpassé,after: "0s"ou unafteromis valent « envoyer maintenant » et sont rejetés. best_time_to_sendn’est pas antérieur à la prochaine heure pleine et ne se situe pas à plus de 30 jours dans le futur. Il est arrondi à l’heure pleine inférieure.- L’heure d’envoi issue de
at/aftern’est pas postérieure àbest_time_to_sendplus 24 heures.
Le reason de l’erreur (dans le détail ErrorInfo) indique la vérification qui a échoué :
reason | Cause |
|---|---|
BestTimeToSendWithUserTimezone | follow_user_timezone vaut true. |
BestTimeToSendTooEarly | best_time_to_send est antérieur à la prochaine heure pleine. |
BestTimeToSendTooFarInFuture | best_time_to_send se situe à plus de 30 jours dans le futur. |
SendDateAfterBestTimeToSend | at / after est postérieur à best_time_to_send plus 24 heures. |
BestTimeToSendNotAllowed | best_time_to_send est défini sur un envoi transactional. |
BestTimeToSendWithSendNow | at / after correspond à « maintenant » (at passé ou after nul). |
GeoZone
Anchor link toUn cercle ponctuel pour geo_zone, défini dans la requête elle-même. Il ne s’agit pas d’une géozone enregistrée : les campagnes géolocalisées et l’API Geozones ne sont pas utilisées, et rien n’est stocké dans l’application.
{ "lat": 40.7128, "lng": -74.006, "range": 500 }| Champ | Type | Description |
|---|---|---|
lat | double | Latitude du centre du cercle, en degrés. Obligatoire. |
lng | double | Longitude du centre du cercle, en degrés. Obligatoire. |
range | double | Rayon du cercle en mètres. Obligatoire. |
FrequencyCapping
Anchor link toLimites de fréquence par utilisateur pour les envois marketing. Pour désactiver la limitation, omettez entièrement frequency_capping, ou envoyez days: 0 avec count: 0.
{ "days": 7, "count": 3, "exclude": false, "avoid": true }days(int, 1–30, ou0pour désactiver la limitation) : fenêtre de temps à analyser. Doit être envoyé aveccount— si l’un est0, l’autre doit aussi être0; envoyer l’un à0alors que l’autre est non nul renvoie une erreur400.count(int, 1 ou plus, ou0pour désactiver la limitation) : nombre maximum de messages autorisés pendant la périodedays. Même règle de couplage quedaysci-dessus.exclude(bool) : exclure de manière stricte les utilisateurs qui ont déjà atteint la limite.avoid(bool) : éviter de manière souple les utilisateurs qui ont déjà atteint la limite (ils sont toujours comptabilisés dans les analyses).
SendRate
Anchor link to{ "value": 500, "bucket": "1s", "avoid": false }Limite le débit de l’envoi. value correspond au nombre de messages par bucket ; un bucket typique est "1s".
SilentHours
Anchor link to{ "avoid": true }Les messages marketing respectent par défaut les heures de silence de l’application : pendant la période de silence, ils sont retenus jusqu’à sa fin ou ne sont pas envoyés, selon les paramètres du canal. Définissez avoid sur true pour envoyer ce message même pendant la période de silence. Les messages dont le message_type est MESSAGE_TYPE_TRANSACTIONAL ne sont jamais retenus par les heures de silence et n’ont donc pas besoin de ce champ.
Énumération Platform
Anchor link toIOS, ANDROID, OSX, WINDOWS, AMAZON, SAFARI, CHROME, FIREFOX, IE, EMAIL, HUAWEI_ANDROID, SMS, WEB, KAKAO, TELEGRAM, LINE, WHATS_APP, VIBER, FB_MESSENGER.
Énumération RegistrationType
Anchor link toREGISTRATION_TYPE_DEFAULT: ignore les identifiants qui ne sont pas enregistrés dans Pushwoosh. Par défaut.REGISTRATION_TYPE_NONE: envoie à chaque hwid listé sans enregistrer d’appareil pour celui-ci.REGISTRATION_TYPE_FORCE: enregistre chaque hwid inconnu comme appareil sur le canal ciblé, puis lui envoie le message. S’applique à l’e-mail, aux SMS, à WhatsApp, LINE, Viber et Kakao.
Énumération MessageType
Anchor link toMESSAGE_TYPE_UNSPECIFIED: équivalent àMESSAGE_TYPE_MARKETING.MESSAGE_TYPE_MARKETING: soumis au filtrage du groupe de contrôle, à la limitation de fréquence et aux heures de silence.MESSAGE_TYPE_TRANSACTIONAL: ignore le filtrage du groupe de contrôle, la limitation de fréquence et les heures de silence. À utiliser pour les confirmations de commande, les OTP et autres flux critiques similaires.