Μετάβαση στο κύριο περιεχόμενο

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:

ScopeEndpoints
campaigns:readΛίστα, λήψη, στατιστικά, παραλήπτες, εκδόσεις, ιστορικό
campaigns:writeΔημιουργία, ενημέρωση, αντιγραφή, αρχειοθέτηση, ετικέτες, rollback εκδόσεων
campaigns:sendΑποστολή, παύση, συνέχιση, ακύρωση, επανάληψη, δοκιμαστικές αποστολές, transactional αποστολή
campaigns:deleteΔιαγραφή, μαζική διαγραφή

Δείτε Κλειδιά API για τη διαχείριση scopes.


Δημιουργία καμπάνιας​

Endpoint​

POST /campaigns

Σώμα αιτήματος​

ΠεδίοΤύποςΑπαιτείταιΠεριγραφή
namestringΝαιΌνομα καμπάνιας (μέγιστο 255 χαρακτήρες)
descriptionstringΌχιΠεριγραφή (μέγιστο 1000 χαρακτήρες)
channelstringΝαιemail, sms, viber, push, webhook, whatsapp, in_app ή ai_optimized
variantsarrayΝαι*Παραλλαγές μηνύματος (απαιτούνται για κάθε κανάλι εκτός του in_app)
targetingobjectΌχιΚοινό: userIds, filterGroups, excludeFilterGroups, filterOperator, subscriptionPreference
sendTypestringΌχιimmediate, scheduled, triggered, intelligent, recurring ή ai_optimized
scheduledAtstringΌχιΗμερομηνία ISO 8601 για sendType: "scheduled"
scheduledTimezonestringΌχιΖώνη ώρας IANA στην οποία ερμηνεύεται η προγραμματισμένη ώρα (αποθηκεύεται με την καμπάνια), ή recipient_local: κάθε άτομο στην ώρα του scheduledAt στη δική του ζώνη (του χώρου εργασίας όσοι δεν έχουν)· η καμπάνια ξεκινά όταν η UTC+14 φτάσει σε αυτήν. Άγνωστα ονόματα απορρίπτονται με 400.
triggerConfigobjectΌχιΚανόνας εναύσματος για sendType: "triggered" (type, eventName, conditions, reEntry, cooldownHours)
recurringScheduleobjectΌχιΓια 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.
conversionTrackingobjectΌχιprimaryConversion / secondaryConversions (όνομα συμβάντος + συνθήκες ιδιοτήτων), conversionWindowHours, attributionModel (first_touch/last_touch/linear)
emailConfigIdstringΌχιΑποθηκευμένη ταυτότητα αποστολέα email (κανάλι email)
subscriptionCategoryIdstringΌχιΚατηγορία συγκατάθεσης (λίστα συνδρομών) υπό την οποία στέλνει η καμπάνια
sendVolumeLimitobjectΌχιenabled, maxSends, cadence (lifetime/per_send)

Περιεχόμενο in-app μηνύματος​

Κάθε in-app παραλλαγή φέρει το συντεταγμένο περιεχόμενό της στο customContent. Το mode καθορίζει ποια πεδία ισχύουν:

modeΠεδίαΑποδίδεται ως
nativetitle, body, imageUrl, buttons, closeButton, backdropDismissible, styleΤα ίδια τα στοιχεία της εφαρμογής - χωρίς web view
html (προεπιλογή)html, css, maxWidthΚώδικας του συντάκτη μέσα σε web view
drag_drophtml, 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 περιεχομένου, οπότε στείλτε ένα πεδίο μόνο όταν το χρειάζεται η καμπάνια.

ΠεδίοΤύποςΙσχύει σεΣημασία
backgroundColorstringweb, iOS, AndroidΦόντο κάρτας
textColorstringweb, iOS, AndroidΤίτλος και σώμα (το σώμα ελαφρώς απαλότερο)
primaryButtonColorstringweb, iOS, AndroidΓέμισμα του πρώτου κουμπιού
primaryButtonTextColorstringweb, iOS, AndroidΗ ετικέτα του. Αν παραλειφθεί, επιλέγεται μαύρο ή λευκό με βάση την αντίθεση
cornerRadiusnumberweb, iOS, Android0-48. Αγνοείται στο fullscreen, όπου οι στρογγυλεμένες γωνίες θα άφηναν την εφαρμογή να φαίνεται
fontSizenumberweb, iOS, Android10-32. Μέγεθος σώματος· ο τίτλος κλιμακώνεται από αυτό. Στο κινητό εφαρμόζεται επιπλέον η ρύθμιση μεγέθους κειμένου του χρήστη
titleWeightstringweb, iOS, Androidregular, medium, semibold, bold. Μόνο ο ΤΙΤΛΟΣ - το σώμα μένει κανονικό για αναγνωσιμότητα
textAlignstringweb, iOS, Androidauto (προεπιλογή), start, center, end. Το auto ακολουθεί τη γλώσσα του ίδιου του μηνύματος, ώστε τα εβραϊκά και τα αραβικά να διαβάζονται από δεξιά
fontFamilystringweb· στο κινητό κατά προσέγγισηΣτο κινητό ισχύει μόνο αν η εφαρμογή περιλαμβάνει τη γραμματοσειρά (iOS: καταχωρημένη· Android: res/font ή οικογένεια συστήματος). Αλλιώς κρατά τη δική της
customCssstringμόνο 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:

ΠεδίοΤύποςΑπαιτείταιΠεριγραφή
idstringΝαιId παραλλαγής
namestringΝαιΌνομα παραλλαγής
weightnumberΝαιΜερίδιο κίνησης, 0-100 (τα βάρη πρέπει να αθροίζονται σωστά κατά τους κανόνες του καναλιού)
messageobjectΌχιΜήνυμα καναλιού. 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
isControlGroupbooleanΌχιΕπισημαίνει την παραλλαγή ως παρακρατημένη ομάδα ελέγχου (ενεργοποιεί τη μέτρηση 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

Παράμετροι ερωτήματος​

ΠαράμετροςΤύποςΠροεπιλογήΠεριγραφή
sinceDaysnumber90Περίοδος αναδρομής για το ποιες καμπάνιες περιλαμβάνονται

Απόκριση​

ΠεδίοΤύποςΠεριγραφή
rankedarrayΚαμπάνιες των οποίων η μέτρηση ξεπέρασε το όριο στατιστικής σημαντικότητας
stillCollectingarrayΜετρήθηκαν αλλά δεν κατέληξαν. Ξεχωριστή λίστα σκόπιμα - δεν έχουν ετυμηγορία, και η τοποθέτησή τους κάτω από τους χαμένους θα έλεγε ότι έχασαν
noHoldoutnumberΚαμπάνιες χωρίς ομάδα ελέγχου. Η επίδρασή τους δεν μετριέται, οπότε μετρώνται αντί να παρατίθενται
noGoalnumberΚαμπάνιες με ομάδα ελέγχου αλλά χωρίς στόχο μετατροπής. Δεν υπάρχει τίποτα για σύγκριση, οπότε μετρώνται αντί να παρατίθενται
sinceDaysnumberΗ περίοδος που εφαρμόστηκε

Τι είναι εδώ μετατροπή. Κάθε γραμμή μετρά τον δικό στόχο μετατροπής της καμπάνιας (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​

ΠαράμετροςΤύποςΠροεπιλογήΠεριγραφή
statusstring-Φιλτράρισμα βάσει κατάστασης (χωρισμένες με κόμμα για πολλαπλές)
channelstring-Φιλτράρισμα βάσει καναλιού (χωρισμένα με κόμμα για πολλαπλά)
tagsstring-Φιλτράρισμα βάσει ετικετών (χωρισμένες με κόμμα)
qstring-Αναζήτηση ελεύθερου κειμένου
createdBy / editedBystring-Φιλτράρισμα βάσει δημιουργού / τελευταίου συντάκτη (ids χρηστών χωρισμένα με κόμμα)
createdFromstring-Μόνο καμπάνιες που δημιουργήθηκαν από αυτή την ημερομηνία ISO και μετά
pagenumber1Αριθμός σελίδας
limitnumber20Αποτελέσματα ανά σελίδα (μέγιστο 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): αναπηδήσεις με bounceType hard, 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

Σώμα αιτήματος​

ΠεδίοΤύποςΑπαιτείταιΠεριγραφή
userIdstringΝαιId χρήστη-στόχου
channelstringΝαιemail, sms, push ή viber
messageobjectΝαιsubject (email), body (απλό κείμενο), html (email). Μπορεί να είναι {} για viber - το σώμα του εγκεκριμένου προτύπου είναι το μήνυμα
viberTemplateIdstringΜόνο ViberΈνα εγκεκριμένο πρότυπο από το μητρώο προτύπων Viber. Η Rakuten Viber επιβάλλει προεγκεκριμένα πρότυπα για transactional/OTP μηνύματα (από τον Ιούλιο του 2026)· το μη εγκεκριμένο περιεχόμενο χρεώνεται με την προωθητική τιμή, οπότε το API αρνείται να στείλει χωρίς αυτό
variablesobjectΌχιΜόνο Viber - τιμές για τα δυναμικά πεδία του προτύπου (συγχωνεύονται στο πλαίσιο εξατομίκευσης)
triggerDataobjectΌχιΠλαίσιο διαθέσιμο στην εξατομίκευση (type, name, properties, metadata)
idempotencyKeystringΌχιΚλειδί 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.") ή αποστολή καμπάνιας που δεν είναι πλέον σε κατάσταση δυνατής αποστολής

Σχετικά​

Ένα API key δεν μπορεί να εγκρίνει

Η έγκριση απαιτεί συνδεδεμένο χρήστη. Καταγράφει ποιος έλεγξε την καμπάνια, και ο διαχωρισμός καθηκόντων κρίνεται συγκρίνοντας τον εγκρίνοντα με τον υποβάλλοντα - κανένα από τα δύο δεν είναι δυνατό για ένα key. Αίτημα με API key απορρίπτεται με 403.