Campaigns API
Δημιουργήστε, εκκινήστε και παρακολουθήστε καμπάνιες προγραμματιστικά.
Όλα τα endpoints αυτής της σελίδας είναι σχετικά ως προς το βασικό URL: https://api-eu1.joryio.com/api - δείτε Επισκόπηση API.
Έλεγχος ταυτότητας
Όλα τα αιτήματα απαιτούν έλεγχο ταυτότητας με κλειδί API:
Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json
Το κλειδί σας πρέπει να φέρει το scope που απαιτεί κάθε endpoint:
| Scope | Endpoints |
|---|---|
campaigns:read | Λίστα, λήψη, στατιστικά, παραλήπτες, εκδόσεις, ιστορικό |
campaigns:write | Δημιουργία, ενημέρωση, αντιγραφή, αρχειοθέτηση, ετικέτες, rollback εκδόσεων |
campaigns:send | Αποστολή, παύση, συνέχιση, ακύρωση, επανάληψη, δοκιμαστικές αποστολές, transactional αποστολή |
campaigns:delete | Διαγραφή, μαζική διαγραφή |
Δείτε Κλειδιά API για τη διαχείριση scopes.
Δημιουργία καμπάνιας
Endpoint
POST /campaigns
Σώμα αιτήματος
| Πεδίο | Τύπος | Απαιτείται | Περιγραφή |
|---|---|---|---|
name | string | Ναι | Όνομα καμπάνιας (μέγιστο 255 χαρακτήρες) |
description | string | Όχι | Περιγραφή (μέγιστο 1000 χαρακτήρες) |
channel | string | Ναι | email, sms, viber, push, webhook, whatsapp, in_app ή ai_optimized |
variants | array | Ναι* | Παραλλαγές μηνύματος (απαιτούνται για κάθε κανάλι εκτός του in_app) |
targeting | object | Όχι | Κοινό: userIds, filterGroups, excludeFilterGroups, filterOperator, subscriptionPreference |
sendType | string | Όχι | immediate, scheduled, triggered, intelligent, recurring ή ai_optimized |
scheduledAt | string | Όχι | Ημερομηνία ISO 8601 για sendType: "scheduled" |
scheduledTimezone | string | Όχι | Ζώνη ώρας IANA στην οποία ερμηνεύεται η προγραμματισμένη ώρα (αποθηκεύεται με την καμπάνια), ή recipient_local: κάθε άτομο στην ώρα του scheduledAt στη δική του ζώνη (του χώρου εργασίας όσοι δεν έχουν)· η καμπάνια ξεκινά όταν η UTC+14 φτάσει σε αυτήν. Άγνωστα ονόματα απορρίπτονται με 400. |
triggerConfig | object | Όχι | Κανόνας εναύσματος για sendType: "triggered" (type, eventName, conditions, reEntry, cooldownHours) |
recurringSchedule | object | Όχι | Για sendType: "recurring": frequency (daily/weekly/monthly/custom), cron, dayOfWeek, dayOfMonth, timeOfDay, timezone, endDate, maxOccurrences. Το endCondition (never/date/after) κρατά μόνο το τέλος που ορίζει: το never αφαιρεί τα endDate και maxOccurrences, το date αφαιρεί το maxOccurrences, το after αφαιρεί το endDate και αποθηκεύει maxOccurrences ίσο με 10 όταν λείπει. Χωρίς dayOfWeek (0 = Κυριακή) ένα εβδομαδιαίο πρόγραμμα τρέχει τη Δευτέρα· χωρίς dayOfMonth ένα μηνιαίο τρέχει την 1η του μήνα. Το timeOfDay είναι HH:MM σε 24ωρη μορφή (09:00, 17:30)· οποιαδήποτε άλλη τιμή απορρίπτεται με 400. |
conversionTracking | object | Όχι | primaryConversion / secondaryConversions (όνομα συμβάντος + συνθήκες ιδιοτήτων), conversionWindowHours, attributionModel (first_touch/last_touch/linear) |
emailConfigId | string | Όχι | Αποθηκευμένη ταυτότητα αποστολέα email (κανάλι email) |
subscriptionCategoryId | string | Όχι | Κατηγορία συγκατάθεσης (λίστα συνδρομών) υπό την οποία στέλνει η καμπάνια |
sendVolumeLimit | object | Όχι | enabled, maxSends, cadence (lifetime/per_send) |
Περιεχόμενο in-app μηνύματος
Κάθε in-app παραλλαγή φέρει το συντεταγμένο περιεχόμενό της στο customContent. Το mode καθορίζει ποια πεδία ισχύουν:
mode | Πεδία | Αποδίδεται ως |
|---|---|---|
native | title, body, imageUrl, buttons, closeButton, backdropDismissible, style | Τα ίδια τα στοιχεία της εφαρμογής - χωρίς web view |
html (προεπιλογή) | html, css, maxWidth | Κώδικας του συντάκτη μέσα σε web view |
drag_drop | html, css, grapejsData, maxWidth | Όπως το html· το grapejsData είναι η κατάσταση του οπτικού επεξεργαστή |
Το mode μπορεί να παραλειφθεί, οπότε σημαίνει html.
Το maxWidth (λειτουργίες HTML, μόνο σε καμπάνιες modal και slideup) είναι το μέγιστο πλάτος του μηνύματος σε px: ακέραιος από 240 έως 1200. Παραλείψτε το για την προεπιλογή της διάταξης - 600 για modal, 400 για slide-up. Το SDK δίνει στο μήνυμα το μικρότερο ανάμεσα στο maxWidth και στο πλάτος της οθόνης μείον ένα περιθώριο πριν διαταχθεί το περιεχόμενο, οπότε τα media queries του μηνύματος βλέπουν το πραγματικό του πλάτος. Δείτε Μέγιστο πλάτος και responsive HTML.
{
"name": "Weekend offer",
"channel": "in_app",
"channelConfig": { "type": "modal", "triggers": [] },
"variants": [
{
"id": "v1",
"name": "Native",
"weight": 100,
"customContent": {
"mode": "native",
"title": "Weekend only",
"body": "Hi {{ firstName }}, members get 20% off through Sunday.",
"imageUrl": "https://cdn.example.com/weekend.png",
"buttons": [
{ "id": "cta", "text": "See offer", "action": "url", "url": "https://example.com/offer" },
{ "id": "later", "text": "Not now", "action": "dismiss" }
],
"closeButton": true,
"backdropDismissible": true,
"style": {
"backgroundColor": "#0A1240",
"textColor": "#FFFFFF",
"primaryButtonColor": "#00C8B7",
"cornerRadius": 18
}
}
}
]
}
Τα native πεδία είναι κείμενο, όχι markup. Παραδίδονται στην εφαρμογή χωρίς escaping, επειδή η εφαρμογή τα αποδίδει σε στοιχεία κειμένου, οπότε το A & B φτάνει ως A & B και όχι ως A & B. Η εξατομίκευση Liquid λειτουργεί στα title, body και στα text και url των κουμπιών.
Το buttons περιορίζεται σε 3. Το action είναι ένα από dismiss, url ή deep_link· για τα δύο τελευταία απαιτείται url.
style - προαιρετικές παρακάμψεις εμφάνισης
Κάθε πεδίο είναι προαιρετικό και ένα πεδίο που λείπει σημαίνει κληρονόμηση - το χρώμα επιφάνειας της εφαρμογής, το χρώμα κειμένου της, η απόχρωση έμφασης και η γραμματοσειρά της. Αυτή η κληρονόμηση είναι το νόημα του native περιεχομένου, οπότε στείλτε ένα πεδίο μόνο όταν το χρειάζεται η καμπάνια.
| Πεδίο | Τύπος | Ισχύει σε | Σημασία |
|---|---|---|---|
backgroundColor | string | web, iOS, Android | Φόντο κάρτας |
textColor | string | web, iOS, Android | Τίτλος και σώμα (το σώμα ελαφρώς απαλότερο) |
primaryButtonColor | string | web, iOS, Android | Γέμισμα του πρώτου κουμπιού |
primaryButtonTextColor | string | web, iOS, Android | Η ετικέτα του. Αν παραλειφθεί, επιλέγεται μαύρο ή λευκό με βάση την αντίθεση |
cornerRadius | number | web, iOS, Android | 0-48. Αγνοείται στο fullscreen, όπου οι στρογγυλεμένες γωνίες θα άφηναν την εφαρμογή να φαίνεται |
fontSize | number | web, iOS, Android | 10-32. Μέγεθος σώματος· ο τίτλος κλιμακώνεται από αυτό. Στο κινητό εφαρμόζεται επιπλέον η ρύθμιση μεγέθους κειμένου του χρήστη |
titleWeight | string | web, iOS, Android | regular, medium, semibold, bold. Μόνο ο ΤΙΤΛΟΣ - το σώμα μένει κανονικό για αναγνωσιμότητα |
textAlign | string | web, iOS, Android | auto (προεπιλογή), start, center, end. Το auto ακολουθεί τη γλώσσα του ίδιου του μηνύματος, ώστε τα εβραϊκά και τα αραβικά να διαβάζονται από δεξιά |
fontFamily | string | web· στο κινητό κατά προσέγγιση | Στο κινητό ισχύει μόνο αν η εφαρμογή περιλαμβάνει τη γραμματοσειρά (iOS: καταχωρημένη· Android: res/font ή οικογένεια συστήματος). Αλλιώς κρατά τη δική της |
customCss | string | μόνο web | Χειρόγραφο CSS, έως 20000 χαρακτήρες. Το web SDK ξαναγράφει κάθε επιλογέα ώστε να ισχύει μέσα στο μήνυμα πριν την εισαγωγή, άρα κανένας κανόνας δεν φτάνει στη σελίδα, και το @import απορρίπτεται. Τα κινητά δεν έχουν μηχανή CSS |
Τα χρώματα περνούν όπως γράφτηκαν - hex, rgb() ή λέξη-κλειδί CSS. Μια τιμή που
δεν μπορεί να αναλυθεί επιστρέφει στην κληρονομημένη, αντί να αποτύχει το μήνυμα.
Στο customCss μπορείτε να στοχεύσετε την ίδια την κάρτα, h2, p,
button.primary και button.secondary, ενώ τα παραπάνω πεδία εκτίθενται και ως
μεταβλητές CSS: --joryio-inapp-bg, --joryio-inapp-fg,
--joryio-inapp-primary, --joryio-inapp-primary-fg, --joryio-inapp-radius
και --joryio-inapp-font.
Το περιεχόμενο HTML απαιτεί ρητή συγκατάθεση της εφαρμογής. Τα SDK για κινητά και web αρνούνται τα in-app μηνύματα HTML εκτός αν η εφαρμογή ορίσει allowHtmlJsInAppMessages κατά την αρχικοποίηση, επειδή ένα τέτοιο μήνυμα εμφανίζεται σε web view μέσα στην εφαρμογή. Τα scripts που γράφονται στο μήνυμα δεν εκτελούνται εκεί· η γέφυρα του ίδιου του SDK χειρίζεται τα κουμπιά και τις φόρμες του. Το native περιεχόμενο εμφανίζεται πάντα. Δείτε τους οδηγούς Android, iOS και Web.
| sendRateLimit | object | Όχι | enabled, maxPerMinute |
| quietTimeOverride | object | Όχι | Παράκαμψη ωρών ησυχίας ανά καμπάνια |
| utmSettings | object | Όχι | Παράκαμψη UTM/επισήμανσης συνδέσμων ανά καμπάνια |
| channelConfig | object | Όχι | Ρύθμιση ειδική ανά κανάλι (η μορφή εξαρτάται από το κανάλι) |
| stoConfig / abTestConfig | object | Όχι | Ρύθμιση βελτιστοποίησης ώρας αποστολής / δοκιμής A/B |
| resendPolicy | string | Όχι | Πολιτική επαναποστολής για το «Αποστολή ξανά» μιας εφάπαξ καμπάνιας: only_new (προεπιλογή), everyone ή cooldown |
| resendCooldownDays | number | Όχι | Παράθυρο πρόσφατης επαφής (ημέρες) για resendPolicy: "cooldown"· με cooldown, τιμή που λείπει ή είναι 0 αποθηκεύεται ως 30 |
| tags | string[] | Όχι | Ετικέτες |
| status | string | Όχι | draft, scheduled, active, paused, completed ή cancelled |
Δομή παραλλαγής
Κάθε στοιχείο στο variants:
| Πεδίο | Τύπος | Απαιτείται | Περιγραφή |
|---|---|---|---|
id | string | Ναι | Id παραλλαγής |
name | string | Ναι | Όνομα παραλλαγής |
weight | number | Ναι | Μερίδιο κίνησης, 0-100 (τα βάρη πρέπει να αθροίζονται σωστά κατά τους κανόνες του καναλιού) |
message | object | Όχι | Μήνυμα καναλιού. Email: subject, preheader, from, fromName, html ή templateId, text. SMS: body, from, shortenLinks· σε λογαριασμό Delivyr (μόνο εγκεκριμένα πρότυπα) smsTemplateId και variableMapping αντί για body - δείτε Πρότυπα SMS. Push: title, body, icon, image, data. WhatsApp: messageType (template/reply), templateId, wabaId, variableMapping, replyText. Webhook: url, method, headers, body, auth, bodyType |
isControlGroup | boolean | Όχι | Επισημαίνει την παραλλαγή ως παρακρατημένη ομάδα ελέγχου (ενεργοποιεί τη μέτρηση uplift) |
Παράδειγμα αιτήματος
curl -X POST https://api-eu1.joryio.com/api/campaigns \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "July Newsletter",
"channel": "email",
"sendType": "scheduled",
"scheduledAt": "2026-07-20T10:00:00.000Z",
"scheduledTimezone": "America/New_York",
"variants": [
{
"id": "variant-a",
"name": "Variant A",
"weight": 100,
"message": {
"subject": "Your July update",
"from": "[email protected]",
"fromName": "Example",
"html": "<h1>Hello {{ user.firstName }}</h1>"
}
}
],
"targeting": {
"filterGroups": [
{
"filters": [
{ "type": "attribute", "field": "plan", "operator": "equals", "value": "premium" }
],
"operator": "AND"
}
]
}
}'
Απόκριση
Επιστρέφει το αντικείμενο της καμπάνιας που δημιουργήθηκε:
{
"id": "8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b",
"name": "July Newsletter",
"channel": "email",
"status": "scheduled",
"sendType": "scheduled",
"scheduledAt": "2026-07-20T14:00:00.000Z",
"variants": [ ... ],
"targeting": { ... },
"tags": [],
"createdAt": "2026-07-12T09:00:00.000Z",
"updatedAt": "2026-07-12T09:00:00.000Z"
}
Απόδοση καμπανιών
Ποιες καμπάνιες προκάλεσαν πραγματικά μετατροπές, μετρημένο έναντι της ομάδας ελέγχου κάθε καμπάνιας - των παραληπτών στους οποίους σκόπιμα δεν στάλθηκε μήνυμα.
Κατάταξη με βάση τις επιπλέον μετατροπές, όχι τα έσοδα, ώστε να έχει νόημα και για έναν χώρο εργασίας που βελτιστοποιεί για εγγραφή ή ενεργοποίηση αντί για παραγγελίες. Τα έσοδα εμφανίζονται δίπλα όπου υπάρχουν παραγγελίες.
Endpoint
GET /campaigns/performance
Παράμετροι ερωτήματος
| Παράμετρος | Τύπος | Προεπιλογή | Περιγραφή |
|---|---|---|---|
sinceDays | number | 90 | Περίοδος αναδρομής για το ποιες καμπάνιες περιλαμβάνονται |
Απόκριση
| Πεδίο | Τύπος | Περιγραφή |
|---|---|---|
ranked | array | Καμπάνιες των οποίων η μέτρηση ξεπέρασε το όριο στατιστικής σημαντικότητας |
stillCollecting | array | Μετρήθηκαν αλλά δεν κατέληξαν. Ξεχωριστή λίστα σκόπιμα - δεν έχουν ετυμηγορία, και η τοποθέτησή τους κάτω από τους χαμένους θα έλεγε ότι έχασαν |
noHoldout | number | Καμπάνιες χωρίς ομάδα ελέγχου. Η επίδρασή τους δεν μετριέται, οπότε μετρώνται αντί να παρατίθενται |
noGoal | number | Καμπάνιες με ομάδα ελέγχου αλλά χωρίς στόχο μετατροπής. Δεν υπάρχει τίποτα για σύγκριση, οπότε μετρώνται αντί να παρατίθενται |
sinceDays | number | Η περίοδος που εφαρμόστηκε |
Τι είναι εδώ μετατροπή. Κάθε γραμμή μετρά τον δικό στόχο μετατροπής της καμπάνιας (conversionGoal, το όνομα του στόχου, για παράδειγμα email_clicked) - την ίδια αύξηση που δείχνει η σελίδα της καμπάνιας: και οι δύο ομάδες ελέγχονται για το αν το άτομο έφτασε στον στόχο μέσα στο παράθυρο μετατροπής της καμπάνιας αφού του στάλθηκε (ή θα του στελνόταν) μήνυμα, χωρίς μοντέλο απόδοσης, γιατί η ομάδα ελέγχου δεν έχει μήνυμα να πιστωθεί. Το incrementalRevenue προέρχεται από παραγγελίες - έσοδα αγορών στο παράθυρο κάθε ομάδας - όποιος κι αν είναι ο στόχος. Μέχρι τις 2026-10-14 τα incrementalConversions, conversionRateLift και significance μετρούσαν αγοραστές για κάθε καμπάνια, όποιος κι αν ήταν ο στόχος της.
Αυτά τα νούμερα δεν αθροίζονται
Δεν υπάρχει σύνολο, σκόπιμα. Κάθε καμπάνια μετριέται έναντι μιας ομάδας ελέγχου που έλαβε όλα τα υπόλοιπα που στείλατε, οπότε οι επιδράσεις επικαλύπτονται - η άθροιση των γραμμών μετράει την ίδια μετατροπή σε περισσότερες από μία καμπάνιες. Η απόκριση περιλαμβάνει totalsAreNotSummable: true.
Γιατί έχει σημασία η σημαντικότητα εδώ
Μια καμπάνια με μικρή ομάδα ελέγχου μπορεί να δείξει τεράστια άνοδο από την αγορά ενός μόνο ατόμου. Κατατάσσονται μόνο καμπάνιες με τουλάχιστον minConvertersPerArm μετατροπές σε κάθε σκέλος. Το τεστ τρέχει στο ποσοστό μετατροπής, που είναι αναλογία και ελέγχεται σωστά· τα έσοδα ανά παραλήπτη έχουν βαριά ουρά και αναφέρονται ως συμφραζόμενα, όχι ως απόδειξη.
curl -X GET "https://api-eu1.joryio.com/api/campaigns/performance?sinceDays=90" \
-H "Authorization: Bearer YOUR_API_KEY"
Λίστα καμπανιών
Endpoint
GET /campaigns
Παράμετροι query
| Παράμετρος | Τύπος | Προεπιλογή | Περιγραφή |
|---|---|---|---|
status | string | - | Φιλτράρισμα βάσει κατάστασης (χωρισμένες με κόμμα για πολλαπλές) |
channel | string | - | Φιλτράρισμα βάσει καναλιού (χωρισμένα με κόμμα για πολλαπλά) |
tags | string | - | Φιλτράρισμα βάσει ετικετών (χωρισμένες με κόμμα) |
q | string | - | Αναζήτηση ελεύθερου κειμένου |
createdBy / editedBy | string | - | Φιλτράρισμα βάσει δημιουργού / τελευταίου συντάκτη (ids χρηστών χωρισμένα με κόμμα) |
createdFrom | string | - | Μόνο καμπάνιες που δημιουργήθηκαν από αυτή την ημερομηνία ISO και μετά |
page | number | 1 | Αριθμός σελίδας |
limit | number | 20 | Αποτελέσματα ανά σελίδα (μέγιστο 100) |
Παράδειγμα αιτήματος
curl -X GET "https://api-eu1.joryio.com/api/campaigns?status=active&channel=email&limit=50" \
-H "Authorization: Bearer jry_live_your_api_key"
Απόκριση
{
"data": [
{ "id": "8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b", "name": "July Newsletter", "channel": "email", "status": "active" }
],
"pagination": {
"total": 23,
"page": 1,
"limit": 50,
"offset": 0,
"totalPages": 1,
"hasMore": false
}
}
Λήψη καμπάνιας
GET /campaigns/:campaignId
curl -X GET https://api-eu1.joryio.com/api/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b \
-H "Authorization: Bearer jry_live_your_api_key"
Επιστρέφει το πλήρες αντικείμενο της καμπάνιας. Η κατάσταση καμπάνιας είναι μία από τις: draft, scheduled, active, paused, completed, cancelled, archived, failed (μόνιμο σφάλμα αποστολής - δείτε failureReason).
Ενημέρωση καμπάνιας
PUT /campaigns/:campaignId
Το σώμα δέχεται τα ίδια πεδία με τη Δημιουργία καμπάνιας - όλα προαιρετικά· ενημερώνονται μόνο τα πεδία που παρέχονται.
curl -X PUT https://api-eu1.joryio.com/api/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "July Newsletter v2" }'
Οι triggered και recurring καμπάνιες παραμένουν active σε όλη τη ζωή τους. Η επεξεργασία μιας active καμπάνιας δεν αλλάζει αυτό που αποστέλλεται τη δεδομένη στιγμή - οι αλλαγές αποθηκεύονται προσωρινά ως εκκρεμές προσχέδιο. Καλέστε POST /campaigns/:campaignId/publish για να εφαρμοστούν ατομικά στην τρέχουσα καμπάνια, ή POST /campaigns/:campaignId/discard-draft για να απορριφθούν. Οι καμπάνιες-προσχέδια ενημερώνονται επιτόπου (χωρίς βήμα δημοσίευσης).
Διαγραφή καμπάνιας
DELETE /campaigns/:campaignId
Επιστρέφει 204 No Content. Μόνο προσχέδια που δεν εκτελέστηκαν ποτέ διαγράφονται οριστικά· καμπάνιες με ιστορικό αποστολών πρέπει αντ' αυτού να αρχειοθετούνται (POST /campaigns/:campaignId/archive), κάτι που σταματά την αποστολή διατηρώντας τα αναλυτικά στοιχεία.
Κύκλος ζωής καμπάνιας
| Μέθοδος | Διαδρομή | Περιγραφή |
|---|---|---|
POST | /campaigns/:campaignId/send | Εκκίνηση της καμπάνιας (ξεκινά την αποστολή / ενεργοποιεί μια triggered καμπάνια) |
POST | /campaigns/:campaignId/pause | Παύση καμπάνιας σε εξέλιξη |
POST | /campaigns/:campaignId/resume | Συνέχιση καμπάνιας σε παύση |
POST | /campaigns/:campaignId/publish | Ατομική εφαρμογή των προσωρινών αλλαγών σε ενεργή καμπάνια (400 αν δεν εκκρεμούν) |
POST | /campaigns/:campaignId/discard-draft | Απόρριψη των προσωρινών αλλαγών ενεργής καμπάνιας (χωρίς αποτέλεσμα αν δεν υπάρχουν) |
POST | /campaigns/:campaignId/cancel | Ακύρωση καμπάνιας |
POST | /campaigns/:campaignId/resend | Επαναποστολή («Αποστολή ξανά») μιας ολοκληρωμένης εφάπαξ καμπάνιας σύμφωνα με το resendPolicy της |
POST | /campaigns/:campaignId/retry | Επανάληψη μιας failed καμπάνιας (την επαναφέρει σε scheduled) |
POST | /campaigns/:campaignId/preview-launch | Σύνοψη πριν την εκκίνηση (μέγεθος κοινού, έλεγχοι) χωρίς αποστολή |
POST | /campaigns/:campaignId/duplicate | Αντιγραφή καμπάνιας ως νέο πρόχειρο: αντιγράφεται κάθε ρύθμιση (αποστολέας, ζώνη ώρας προγραμματισμού, επαναλαμβανόμενο πρόγραμμα, trigger, ρυθμίσεις A/B), μηδενίζεται η κατάσταση εκτέλεσης (status, στατιστικά, εγκρίσεις, scheduledAt). Το duplicatedFrom του αντιγράφου περιέχει τα campaignId, name, scheduledAt, scheduledTimezone και scheduledLocalAt της πηγής |
POST | /campaigns/:campaignId/archive | Αρχειοθέτηση (σταματά την αποστολή, διατηρεί το ιστορικό) |
POST | /campaigns/:campaignId/unarchive | Επαναφορά σε κατάσταση μη αποστολής (συνεχίστε ρητά για να σταλεί ξανά) |
POST | /campaigns/:campaignId/stop-recurring | Διακοπή μελλοντικών επαναλήψεων μιας recurring καμπάνιας |
curl -X POST https://api-eu1.joryio.com/api/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b/send \
-H "Authorization: Bearer jry_live_your_api_key"
Μια ολοκληρωμένη εφάπαξ καμπάνια μπορεί να επανασταλεί με POST /campaigns/:campaignId/resend. Το ποιος τη λαμβάνει διέπεται από το resendPolicy της καμπάνιας:
only_new(προεπιλογή) - παραλείπεται όποιος την έχει ήδη λάβει (τη λαμβάνουν μόνο χρήστες που δεν είχαν προσεγγιστεί ποτέ).everyone- επαναποστολή σε όλο το κοινό, συμπεριλαμβανομένων των προηγούμενων παραληπτών.cooldown- επαναποστολή σε όλους εκτός από όσους έλαβαν μήνυμα τις τελευταίεςresendCooldownDaysημέρες.
Η συγκατάθεση και η καταστολή επιβάλλονται πάντα. Τα όρια συχνότητας ακολουθούν τη σημαία ignoreTouchingRules της καμπάνιας. Οι triggered καμπάνιες χρησιμοποιούν το triggerConfig.reEntry αντ' αυτού· οι recurring καμπάνιες επαναποστέλλουν βάσει του προγράμματός τους. Επιστρέφει 400 για αυτούς τους τύπους, για in-app, ή για καμπάνια που δεν έχει ολοκληρώσει την αποστολή.
Στατιστικά καμπάνιας
GET /campaigns/:campaignId/stats
Παράμετροι query: startDate, endDate (προαιρετικά). Μια τιμή μόνο με ημερομηνία (2026-07-20) σημαίνει ολόκληρη την ημέρα στη ζώνη ώρας του χώρου εργασίας σας· μια πλήρης ISO ημερομηνία-ώρα λαμβάνεται ως η ίδια η χρονική στιγμή, και αυτό είναι που κάνει πραγματικά τα παράθυρα «πρώτη 1 ώρα / 6 ώρες / 24 ώρες» στη σελίδα καμπάνιας.
Απόκριση
{
"campaignId": "8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b",
"name": "July Newsletter",
"channel": "email",
"status": "completed",
"stats": {
"queued": 1200,
"recipients": 1180,
"sent": 1180,
"delivered": 1150,
"failed": 30,
"opened": 640,
"uniqueHumanOpened": 590,
"clicked": 210,
"uniqueHumanClicked": 180,
"bounced": 12,
"hardBounced": 9,
"softBounced": 3,
"otherBounced": 0,
"autoReplied": 7,
"unsubscribed": 4,
"deliveryRate": 97.46,
"openRate": 51.3,
"clickRate": 15.65,
"clickToOpenRate": 30.51,
"rateBasis": "recipients",
"rateOf": "delivered",
"messageOpens": null,
"messageClicks": null
},
"conversionStats": { ... },
"revenue": { ... },
"uplift": null,
"storeConnected": false,
"conversionTracking": { ... },
"startedAt": "2026-07-20T14:00:00.000Z",
"completedAt": "2026-07-20T14:12:00.000Z",
"createdAt": "2026-07-12T09:00:00.000Z"
}
Το storeConnected είναι true όταν ο χώρος εργασίας έχει συνδεδεμένη ενσωμάτωση καταστήματος (Shopify, WooCommerce ή Magento), false όταν δεν έχει, και null όταν αυτό δεν ήταν δυνατό να προσδιοριστεί.
Τα conversionStats και revenue συμπληρώνονται όταν έχει ρυθμιστεί παρακολούθηση μετατροπών· το uplift συμπληρώνεται μόνο όταν μια παραλλαγή έχει επισημανθεί με isControlGroup.
Δύο πράγματα να διαβάσετε προσεκτικά στο stats:
- Ένα ποσοστό είναι
null, ποτέ0, όταν το κανάλι δεν μπορεί να το μετρήσει. ΤοopenRateείναιnullσεsms,push,in_app,webhookκαιwallet· ταclickRateκαιclickToOpenRateείναιnullσεwebhook. Τοnullσημαίνει «δεν μετριέται», που είναι διαφορετικός ισχυρισμός από το «κανείς δεν το άνοιξε» - αποδώστε το ανάλογα. - Το
rateBasisονομάζει τον παρονομαστή. Το"recipients"(καμπάνια που στάλθηκε μία φορά) διαιρεί μοναδικά άτομα με τα μηνύματα που παραδόθηκαν. Το"messages"(επαναλαμβανόμενη, ενεργοποιούμενη ή επαναποστολή - οτιδήποτε στάλθηκε πάνω από μία φορά) είναι το ποσοστό ανά μήνυμα σταθμισμένο ως προς την αποστολή, και ταmessageOpens/messageClicksφέρουν τους αριθμητές του. Υπό το"recipients"αυτά τα δύο είναιnullκαι ταuniqueHumanOpened/uniqueHumanClickedείναι τα ειλικρινή πλήθη. - Το
rateOfδηλώνει επί τίνος υπολογίζονται ταopenRateκαιclickRate(προστέθηκε τον Οκτώβριο 2026· για το email τα ποσοστά δεν άλλαξαν). Κάθε ποσοστό ανοίγματος και κλικ είναι μοναδικά άτομα επί τωνdeliveredγια email, SMS, WhatsApp και Viber· επί τωνsentγια push, όπου οι αποδείξεις παράδοσης έρχονται από τη συσκευή και υποεκτιμούν στο iOS, και για κάθε καμπάνια χωρίς αναφερθείσα παράδοση. Ο πίνακας ελέγχου, η σελίδα της καμπάνιας και αυτό το API χρησιμοποιούν τον ίδιο κανόνα, άρα μία καμπάνια έχει ένα ποσοστό παντού - δείτε Πώς υπολογίζονται τα ποσοστά ανοίγματος και κλικ. - Τα
hardBounced,softBounced,otherBouncedχωρίζουν τοbounced(προστέθηκε τον Οκτώβριο 2026): αναπηδήσεις μεbounceTypehard, soft και χωρίς καταγεγραμμένο τύπο, μετρημένες με τον ίδιο κανόνα με τοbounced, οπότε τα τρία αθροίζουν σε αυτό. ΤοautoRepliedείναι ο αριθμός των μηνυμάτων που απαντήθηκαν με απάντηση εκτός γραφείου ή άλλη αυτόματη απάντηση: παραδομένη αλληλογραφία, ποτέ μέρος τουbouncedή ποσοστού αναπηδήσεων. Είναιnullόταν η διαχείριση επιστρεφόμενης αλληλογραφίας είναι ανενεργή και η καμπάνια δεν έχει καμία - δεν μετρήθηκε, που είναι διαφορετικός ισχυρισμός από το0· ένας αριθμός που καταγράφηκε όσο ήταν ενεργή επιστρέφεται κανονικά.
Σχετικά endpoints στατιστικών
| Μέθοδος | Διαδρομή | Περιγραφή |
|---|---|---|
GET | /campaigns/:campaignId/variant-stats | Στατιστικά A/B ανά παραλλαγή με στατιστική σημαντικότητα (startDate/endDate) |
GET | /campaigns/:campaignId/links | Στατιστικά κλικ συνδέσμων (startDate/endDate) - σε καμπάνια in-app οι γραμμές είναι τα ονομαστικά κλικ του μηνύματος (action, url = η διεύθυνση που πατήθηκε ή το όνομα) ανά παραλλαγή |
GET | /campaigns/:campaignId/failure-reasons | Αποτυχίες παράδοσης ομαδοποιημένες κατά κωδικό σφάλματος DLR ([{ code, reason, count }]) |
GET | /campaigns/:campaignId/skip-reasons | Ανάλυση Δεν στάλθηκε: άτομα στα οποία η αποστολή σκόπιμα δεν έστειλε μήνυμα, μία γραμμή ανά άτομο με την αιτία της τελευταίας παράλειψης ({ total, reasons: [{ reason, count }] }· αιτίες όπως control_group, global_control, frequency_cap, channel_unsubscribed, quiet_time, missing_contact). Τα άτομα πίσω από μία αιτία: /campaigns/:campaignId/recipients?skipReason=<reason> |
GET | /campaigns/:campaignId/unsubscribe-reasons | Απεγγραφές ανά αιτία: μία γραμμή ανά άτομο που απεγγράφηκε μέσω των συνδέσμων αυτής της καμπάνιας, με την αιτία της τελευταίας απεγγραφής του, χωρίς κενά και σε πεζά ({ total, reasons: [{ reason, count }], others }). Εμφανίζονται οι 8 κορυφαίες αιτίες και οι υπόλοιπες αθροίζονται στο others· reason: null σημαίνει ότι δεν δόθηκε αιτία. Απεγγραφές που καταγράφηκαν πριν η αιτία αποθηκευτεί στο συμβάν αναλυτικών (Οκτώβριος 2026) μετρώνται ως null |
GET | /campaigns/:campaignId/time-to-engage | Πόσο χρόνο χρειάστηκαν οι παραλήπτες για το πρώτο άνοιγμα ή κλικ, σε ομάδες - μετριέται ανά παραλήπτη από τη ΔΙΚΗ ΤΟΥ αποστολή, οπότε έχει νόημα για καμπάνιες με trigger |
GET | /campaigns/:campaignId/conversion-timing | Πότε έγιναν οι αποδιδόμενες μετατροπές (granularity = day ή hour· τα startDate/endDate περιορίζουν την αποστολή όπως στο /stats). Ίδιος στόχος, παράθυρο, μοντέλο και ερώτημα με το conversionStats, χωρισμένα ανά ημέρα ή ώρα της μετατροπής στη ζώνη ώρας του χώρου εργασίας· τα buckets αθροίζουν στον αριθμό μετατροπών που επιστρέφει το /stats για το ίδιο εύρος. Επιστρέφει { configured, granularity, total, buckets: [{ date, conversions }], majorityWithinHours } - το majorityWithinHours είναι σε πόσες ώρες από την αποδιδόμενη αποστολή είχαν μετατραπεί περισσότεροι από τους μισούς· configured: false όταν η καμπάνια δεν έχει στόχο μετατροπής |
GET | /campaigns/:campaignId/engagement-timing | Αποστολές, ανοίγματα και κλικ ανά day ή hour (granularity) στη ζώνη ώρας του χώρου εργασίας, για το εύρος γεγονότων startDate/endDate όπως στο /stats. Μετρώνται με τους κανόνες του /stats: το count=people (προεπιλογή) βάζει κάθε άτομο μία φορά στο διάστημα του πρώτου ανοίγματος / κλικ του, οπότε τα διαστήματα αθροίζουν στα μοναδικά ανοίγματα / κλικ· το count=events μετρά κάθε άνοιγμα και κλικ. Το includeBots=true προσθέτει ανοίγματα / κλικ από bots και σαρωτές (εξ ορισμού εξαιρούνται). Τα κλειδιά των διαστημάτων ταιριάζουν με το conversion-timing. Επιστρέφει { granularity, count, includeBots, buckets: [{ date, sent, opened, clicked }], totals: { sent, opened, clicked } } |
GET | /campaigns/:campaignId/recovered-carts | Τα εγκαταλελειμμένα καλάθια που ανέκτησε η καμπάνια - η λίστα πίσω από το revenue.recoveredCarts στο /stats, από το ίδιο ερώτημα, οπότε το total ισούται με αυτή τη μέτρηση για τα ίδια startDate/endDate (καλάθια που ανακτήθηκαν στο εύρος· ένα τέλος μόνο με ημερομηνία περιλαμβάνει όλη την ημέρα, ζώνη ώρας χώρου εργασίας). limit 1-100 (προεπιλογή 25), offset· οι νεότερες πρώτα. Γραμμές: orderNumber (του καταστήματος), placedAt, recoveredAt, match (recovery_link, order = ίδιο καλάθι, reported), cartValue/cartCurrency, creditedRevenue/creditedCurrency (καθαρά από επιστροφές), contact (ο κάτοχος του καλαθιού) και buyer (μόνο όταν η παραγγελία καταχωρίστηκε σε άλλο άτομο)· τα ονόματα επαφών κρύβονται χωρίς pii:view. Επιστρέφει { data, total, limit, offset, summary } |
GET | /campaigns/:campaignId/send-occurrences | Ανάλυση ανά αποστολή για επαναλαμβανόμενη καμπάνια, με κλειδί την ημερομηνία αποστολής - η αλληλεπίδραση αποδίδεται στην αποστολή που προηγήθηκε |
GET | /campaigns/:campaignId/recipients | Σελιδοποιημένοι παραλήπτες, μία γραμμή ανά άτομο με το πιο μακρινό στάδιο που έφτασε (furthestStatus). Φιλτράρισμα με status (sent, delivered, opened, clicked, failed, bounced, unsubscribed, skipped)· σελιδοποίηση με limit (μέγιστο 200) και offset. Ταξινόμηση με sortBy - reached (πιο μακρινό στάδιο), lastActivity ή events - και sortOrder (asc / desc, προεπιλογή desc)· χωρίς sortBy προηγείται το νεότερο πρώτο συμβάν, και κάθε ταξινόμηση τελειώνει στο αναγνωριστικό του ατόμου ώστε οι σελίδες να μην επαναλαμβάνουν ούτε να παραλείπουν κανέναν. Το includeBots=true μετρά ανοίγματα και κλικ από bots, σαρωτές και μηχανές ως του ατόμου· από προεπιλογή μένουν εκτός σταδίου και eventCount, ο ίδιος κανόνας με τα ποσοστά ανοίγματος και κλικ |
GET | /campaigns/:campaignId/recipients/:userId | Χρονολόγιο συμβάντων μηνυμάτων ανά χρήστη για αυτή την καμπάνια. Σε καμπάνια webhook επιστρέφει επίσης webhookResponse ({ status, contentType, body, truncated, at }) όταν η τελευταία αποτυχημένη κλήση προς αυτό το άτομο (εκτός 2xx) έχει αποθηκευμένη απάντηση: με αποκρυμμένα μυστικά, τα πρώτα 2 KB του σώματος, διατηρείται 30 ημέρες. Επιστρέφεται μόνο σε καλούντα που μπορεί να βλέπει προσωπικά δεδομένα (pii:view· ένα κλειδί API μόνο με αυτό το δικαίωμα). Απουσιάζει όταν δεν έχει αποθηκευτεί τίποτα ή όταν το προσωπικό του Joryio απενεργοποίησε την αποθήκευση απαντήσεων για τον οργανισμό |
GET | /campaigns/:campaignId/in-app-stats | Στατιστικά εμφάνισης in-app (in-app καμπάνιες). Περιλαμβάνει το displayFrequency - την κατανομή εμφανίσεων ανά χρήστη ως { tailBucket, buckets: [{ displays, users, impressions }], maxPerUser }. Οι τιμές από tailBucket και πάνω συμπτύσσονται σε έναν κάδο, οπότε displays === tailBucket σημαίνει "τόσες ή περισσότερες"· για τον μέσο όρο χρησιμοποιήστε το impressions κάθε κάδου (όχι displays * users), και το maxPerUser για τον χρήστη με τις περισσότερες εμφανίσεις |
GET | /campaigns/:campaignId/impressions | Λίστα εμφανίσεων in-app (limit, offset, startDate, endDate) |
Αποστολή transactional μηνύματος
Στείλτε ένα μεμονωμένο μήνυμα σε έναν χρήστη χωρίς να δημιουργήσετε καμπάνια.
POST /campaigns/transactional/send
Σώμα αιτήματος
| Πεδίο | Τύπος | Απαιτείται | Περιγραφή |
|---|---|---|---|
userId | string | Ναι | Id χρήστη-στόχου |
channel | string | Ναι | email, sms, push ή viber |
message | object | Ναι | subject (email), body (απλό κείμενο), html (email). Μπορεί να είναι {} για viber - το σώμα του εγκεκριμένου προτύπου είναι το μήνυμα |
viberTemplateId | string | Μόνο Viber | Ένα εγκεκριμένο πρότυπο από το μητρώο προτύπων Viber. Η Rakuten Viber επιβάλλει προεγκεκριμένα πρότυπα για transactional/OTP μηνύματα (από τον Ιούλιο του 2026)· το μη εγκεκριμένο περιεχόμενο χρεώνεται με την προωθητική τιμή, οπότε το API αρνείται να στείλει χωρίς αυτό |
variables | object | Όχι | Μόνο Viber - τιμές για τα δυναμικά πεδία του προτύπου (συγχωνεύονται στο πλαίσιο εξατομίκευσης) |
triggerData | object | Όχι | Πλαίσιο διαθέσιμο στην εξατομίκευση (type, name, properties, metadata) |
idempotencyKey | string | Όχι | Κλειδί dedup που δίνει ο καλών - μια επανάληψη με το ίδιο κλειδί δεν παραδίδεται δύο φορές |
curl -X POST https://api-eu1.joryio.com/api/campaigns/transactional/send \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_123",
"channel": "email",
"message": {
"subject": "Your receipt",
"html": "<p>Thanks for your order, {{ user.firstName }}.</p>"
},
"idempotencyKey": "order-98421-receipt"
}'
Πρόσθετα endpoints
| Μέθοδος | Διαδρομή | Περιγραφή |
|---|---|---|
POST | /campaigns/preview | Προεπισκόπηση χρηστών που ταιριάζουν στα κριτήρια στόχευσης (σώμα: targeting, προαιρετικό limit μέγιστο 500, channel, webAppId, platforms για push - το channelConfig.platforms της καμπάνιας· τα targeting.tags είναι οι ετικέτες της καμπάνιας, που καθορίζουν τις εξαιρέσεις από λίστες αποκλεισμού όπως κατά την αποστολή) |
POST | /campaigns/spam-check | Έλεγχος spam του περιεχομένου email πριν την αποστολή |
GET | /campaigns/:campaignId/versions | Λίστα αποθηκευμένων στιγμιοτύπων εκδόσεων |
GET | /campaigns/:campaignId/versions/compare?v1=&v2= | Σύγκριση (diff) δύο εκδόσεων |
GET | /campaigns/:campaignId/versions/:versionId | Λήψη στιγμιοτύπου έκδοσης |
POST | /campaigns/:campaignId/versions/:versionId/rollback | Επαναφορά (rollback) σε μια έκδοση |
GET | /campaigns/:campaignId/history | Ιστορικό ελέγχου (audit log) (limit, μέγιστο 200) |
POST | /campaigns/bulk-delete / bulk-duplicate / bulk-archive / bulk-unarchive | Μαζικές ενέργειες· σώμα { "ids": [...] }, επιστρέφει { succeeded, failed } |
POST | /campaigns/bulk-tag | Μαζική προσθήκη ετικετών· σώμα { "ids": [...], "tags": [...] } |
POST | /campaigns/:campaignId/send-test-whatsapp / send-test-sms / send-test-push | Δοκιμαστικές αποστολές σε τηλέφωνο/χρήστη πριν την εκκίνηση |
POST | /campaigns/:campaignId/render-for-contact | Αποδίδει την καμπάνια για μία επαφή και επιστρέφει { html, css }. Δεν στέλνει τίποτα - το in-app βασίζεται σε άντληση, οπότε δεν υπάρχει συσκευή για παράδοση. Αντικαθιστά το send-test-in-app, που εξακολουθεί να λειτουργεί |
GET | /campaigns/:campaignId/sto-coverage | Κάλυψη βελτιστοποίησης ώρας αποστολής για το κοινό |
GET | /campaigns/:campaignId/recurring-status | Κατάσταση recurring καμπάνιας |
POST | /campaigns/:campaignId/retest-ab | Επαναφορά του νικητή A/B σε recurring καμπάνια νικήτριας παραλλαγής |
POST | /campaigns/:campaignId/launch-rl | Εκκίνηση σε λειτουργία AI-optimized (RL) |
GET | /campaigns/:campaignId/rl-stats | Στατιστικά dashboard AI-optimized καμπάνιας |
POST | /campaigns/:campaignId/pause-rl / resume-rl | Παύση / συνέχιση AI-optimized καμπάνιας |
POST | /campaigns/ml-path-warmth | Κατάσταση προθέρμανσης εξατομίκευσης για ids διαδρομών/παραλλαγών |
Έλεγχος αποστολής
Η επιφάνεια ελέγχου πριν την αποστολή (δείτε τον οδηγό Ελέγχου αποστολής). Ο ίδιος έλεγχος τρέχει μέσα στην αποστολή, οπότε ό,τι επιστρέφει είναι αυτό με το οποίο κρίνεται η αποστολή.
GET /campaigns/{campaignId}/launch-review
Εμβέλεια: campaigns:read.
{
"rulesVersion": "lr1",
"checkedAt": "2026-09-21T10:00:00.000Z",
"requireClean": true,
"blockers": [
{
"code": "merge_field_broken",
"severity": "blocker",
"scope": { "kind": "variant", "id": "v1", "name": "Variant A", "field": "subject" },
"params": { "field": "subject", "error": "output \"{{ user.firstName }\" not closed" },
"fix": { "action": "edit_content", "variantId": "v1", "field": "subject" }
}
],
"recommendations": [
{ "code": "subject_long", "severity": "recommendation", "scope": { "kind": "variant", "id": "v1", "name": "Variant A", "field": "subject" }, "params": { "length": 92, "max": 78 }, "fix": { "action": "edit_content", "variantId": "v1", "field": "subject" } }
],
"skipped": []
}
Κωδικοί: εμπόδια unsubscribe_missing, merge_field_broken, sender_not_verified, sender_not_found, link_unusable (εμπόδιο μόνο σε αποστολή με στόχο μετατροπής)· συστάσεις subject_long, subject_discount_words, subject_hype_adjective, preheader_repeats_subject, experiment_opportunity, plain_text_missing, audience_overlap, at_message_limit (άτομα στο όριο συχνότητάς τους: params.count, sampled, sharePct, bypassed, partial), quiet_hours_now (άτομα μέσα σε παράθυρο ησυχίας τη στιγμή της αποστολής: params.count, sampled, sharePct, behaviour, until, evaluatedAt, at, partial), quiet_hours_ignored, consent_bypassed, node_unreachable, και model_note (σημείωση από τον έλεγχο AI· params.title και params.detail). Η απόκριση φέρει επίσης ai: { status: 'ok' | 'skipped' | 'off', reason?, version, cached? } - το πέρασμα AI τρέχει μόνο σε αυτή τη διαδρομή, ποτέ μέσα στην πύλη αποστολής, και ένα αποτυχημένο πέρασμα είναι λόγος skipped, όχι σφάλμα. Το fix.action είναι ένα από edit_content, edit_audience, edit_delivery, edit_node, choose_sender, verify_domain, open_subscription_settings, open_quiet_time, open_frequency_rules, edit_journey.
Κάθε εύρημα έχει ένα key, σταθερό από έλεγχο σε έλεγχο (ένα model_note ταυτίζεται από το εύρος και τον τίτλο του). Όπου ένα εύρημα δείχνει κάτι συγκεκριμένο έχει και locator: images - κάθε εικόνα ως { src, index, bytes?, id? }, με src την ΠΛΗΡΗ τιμή του χαρακτηριστικού (το params.src μιας πρότασης κόβεται στους 120 χαρακτήρες), index τη θέση της ανάμεσα στις εικόνες περιεχομένου του email, bytes το μετρημένο βάρος της· words (οι λέξεις που αποφεύγει η φωνή της μάρκας και χρησιμοποιεί το μήνυμα) με fields (subject, preheader, html) όπου βρίσκονται· ή text, το μπλοκ που αφορά ένα εύρημα σχεδίασης. Ένα model_note για ένα μέρος του μηνύματος το κατονομάζει στα scope.field και fix.field. Οι προτάσεις AI (model_note, experiment_opportunity) που απέρριψε κάποιος στον πίνακα ελέγχου λείπουν από αυτή την απόκριση· τίποτε άλλο δεν απορρίπτεται. Λείπει επίσης ένα model_note που καλύπτουν οι προτιμήσεις ελέγχου του χώρου εργασίας (δημιουργούνται με το "Να μην προτείνεται ξανά"· εμφανίζονται στις Ρυθμίσεις → Έλεγχος εκκίνησης → Προτιμήσεις ελέγχου), και ένα model_note που έχει ήδη απορριφθεί σε τρεις ή περισσότερες διαφορετικές καμπάνιες ή διαδρομές τις τελευταίες 90 ημέρες έχει το params.dismissedOn, αυτόν τον αριθμό. Δείτε Έλεγχος εκκίνησης.
Το requireClean αντικατοπτρίζει τη ρύθμιση χώρου εργασίας settings.launchReview.requireClean (προεπιλογή true). Όταν είναι true και το blockers δεν είναι κενό, το POST /campaigns/{campaignId}/send απαντά:
{ "statusCode": 409, "code": "launch_review_blocked", "message": "Launch Review: 1 blocker: merge_field_broken (Variant A: subject)", "blockers": [ ... ] }
Μια προγραμματισμένη καμπάνια που απορρίφθηκε την ώρα αποστολής της καταλήγει σε κατάσταση failed με αυτό το μήνυμα ως failureReason.
Αποκρίσεις σφαλμάτων
Όλα τα σφάλματα μοιράζονται την τυπική μορφή - δείτε Απόκριση σφάλματος στην Επισκόπηση API για τη μορφή και την πλήρη λίστα κωδικών κατάστασης.
{
"statusCode": 404,
"message": "Campaign not found",
"timestamp": "2026-07-12T09:00:00.000Z",
"path": "/campaigns/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b"
}
| Κατάσταση | Πότε |
|---|---|
400 | Αποτυχία επικύρωσης (π.χ. μη έγκυρο channel, λείπει το weight παραλλαγής) - το σώμα προσθέτει πίνακα errors με ένα μήνυμα ανά πεδίο που απέτυχε |
401 | Κλειδί API που λείπει ή είναι μη έγκυρο |
403 | Το κλειδί API δεν έχει το απαιτούμενο scope campaigns:* |
404 | Η καμπάνια δεν βρέθηκε σε αυτόν τον χώρο εργασίας |
409 | Σύγκρουση κύκλου ζωής - π.χ. συνέχιση καμπάνιας που δεν είναι πλέον σε παύση ("Campaign is no longer paused.") ή αποστολή καμπάνιας που δεν είναι πλέον σε κατάσταση δυνατής αποστολής |
Σχετικά
- Δημιουργία καμπανιών
- Αναλυτικά στοιχεία καμπανιών
- Segments API - δημιουργήστε τα κοινά που στοχεύουν οι καμπάνιες
- Canvas API - journeys πολλαπλών βημάτων
Η έγκριση απαιτεί συνδεδεμένο χρήστη. Καταγράφει ποιος έλεγξε την καμπάνια, και ο διαχωρισμός καθηκόντων κρίνεται συγκρίνοντας τον εγκρίνοντα με τον υποβάλλοντα - κανένα από τα δύο δεν είναι δυνατό για ένα key. Αίτημα με API key απορρίπτεται με 403.