Coupons API
Ένα πρόγραμμα κουπονιών είναι η συνταγή από την οποία ένα μήνυμα εκδίδει προσωπικούς κωδικούς ({{ coupons.<slug>.code }}). Το Joryio δημιουργεί κάθε κωδικό στο συνδεδεμένο κατάστημα WooCommerce, Shopify, Magento ή PrestaShop (ή τον δημιουργεί και τον παρακολουθεί μόνο του όταν το πρόγραμμα δεν έχει κατάστημα) και αναγνωρίζει την παραγγελία που τον χρησιμοποίησε. Η συμπεριφορά των προγραμμάτων περιγράφεται στο Κωδικοί κουπονιών.
Όλα τα endpoints αυτής της σελίδας είναι σχετικά με το βασικό URL: https://api-eu1.joryio.com/api - δείτε Επισκόπηση API.
Δικαιώματα
| Δικαίωμα | Επιτρέπει |
|---|---|
campaigns:read | Λίστα και ανάγνωση προγραμμάτων, της αναφοράς και των συνδεδεμένων καταστημάτων |
campaigns:write | Δημιουργία προγραμμάτων, αλλαγή προγραμμάτων που δεν έχουν εκδώσει ακόμη κωδικούς, διαγραφή τους, έκδοση κωδικού |
settings:write | Χρειάζεται επιπλέον για αλλαγή ενός ζωντανού προγράμματος - ενός που έχει εκδώσει πραγματικούς κωδικούς |
users:read | Λίστα εκδοθέντων κωδικών (οι κωδικοί ανήκουν σε άτομα) |
Το αντικείμενο προγράμματος
{
"id": "6c0f3c1e-8a52-4a8e-9a39-2a1d7f0b9a11",
"name": "Welcome 10%",
"slug": "welcome10",
"description": "10% off the first order",
"integrationId": "0b8d6f2a-5f43-4e0a-b9a3-7a8b2d1c4e55",
"platform": "woocommerce",
"storeName": "My Store",
"source": "personal",
"status": "active",
"rules": {
"discountType": "percent",
"amount": 10,
"currency": null,
"minimumSubtotal": 50,
"minimumQuantity": null,
"scope": { "kind": "all" },
"excludeSaleItems": false,
"usageLimit": 1,
"oncePerCustomer": true,
"combinable": false,
"expiry": { "mode": "relative", "amount": 14, "unit": "days", "endOfDay": true }
},
"rulesVersion": 1,
"codeFormat": { "length": 10, "charset": "unambiguous", "prefix": "WELCOME-", "suffix": "", "separatorEvery": null },
"fallback": { "policy": "skip", "sharedCode": null },
"reuseOpenCode": true,
"lockToPerson": false,
"live": true,
"sampleCode": "WELCOME-PREVIEW",
"storeError": null,
"stats": { "issued": 1240, "redeemed": 311, "revenue": 18420.5, "currency": "EUR" },
"createdAt": "2026-10-04T08:00:00.000Z",
"updatedAt": "2026-10-04T08:00:00.000Z"
}
| Πεδίο | Τιμές |
|---|---|
integrationId | Ένα συνδεδεμένο κατάστημα, ή null: το Joryio δημιουργεί και παρακολουθεί τους κωδικούς χωρίς κατάστημα |
status | draft, active, paused, archived - μόνο το active εκδίδει κωδικούς |
rules.discountType | percent, fixed_cart, fixed_product (όχι στο PrestaShop: 400), free_shipping |
rules.scope | { "kind": "all" }, ή products (WooCommerce, Shopify, PrestaShop) / categories (WooCommerce, Magento, PrestaShop) / collections (Shopify) με ids - τα ids του ίδιου του καταστήματος· το products στο Magento απαντά 400 |
rules.minimumQuantity | Μόνο Shopify |
rules.excludeSaleItems | Μόνο WooCommerce |
rules.usageLimit | Χρήσεις ανά κωδικό, προεπιλογή 1· null = απεριόριστες |
rules.expiry | { "mode": "none" }, { "mode": "fixed", "date": "2026-12-31T23:59:59Z" }, ή { "mode": "relative", "amount": 14, "unit": "days" | "hours", "endOfDay": true } |
codeFormat.charset | unambiguous (γράμματα και ψηφία χωρίς όμοιους χαρακτήρες, προεπιλογή), letters, digits· length 6-20 |
fallback.policy | skip (προεπιλογή), shared_code (χρειάζεται sharedCode), send_without |
lockToPerson | WooCommerce, Magento και PrestaShop (ο λογαριασμός πελάτη του ατόμου) |
live | true μόλις το πρόγραμμα εκδώσει πραγματικό (όχι δοκιμαστικό) κωδικό |
rulesVersion | Αυξάνεται όταν αλλάζουν οι κανόνες ενός ζωντανού προγράμματος· οι κωδικοί που έχουν ήδη εκδοθεί κρατούν τους κανόνες με τους οποίους δημιουργήθηκαν |
Προγράμματα
Λίστα προγραμμάτων
GET /coupons/programs?status=active&includeArchived=false
Επιστρέφει πίνακα αντικειμένων προγράμματος. Τα αρχειοθετημένα προγράμματα παραλείπονται, εκτός αν includeArchived=true.
Δημιουργία προγράμματος
POST /coupons/programs
Το σώμα είναι το αντικείμενο προγράμματος χωρίς τα πεδία μόνο ανάγνωσης (id, platform, storeName, rulesVersion, stock, live, sampleCode, storeError, stats, ημερομηνίες). Το slug είναι [a-z0-9_], μοναδικό ανά χώρο εργασίας. Το status μπορεί να είναι draft (προεπιλογή) ή active.
{
"name": "Welcome 10%",
"slug": "welcome10",
"integrationId": "0b8d6f2a-5f43-4e0a-b9a3-7a8b2d1c4e55",
"rules": { "discountType": "percent", "amount": 10, "scope": { "kind": "all" }, "usageLimit": 1, "oncePerCustomer": true, "combinable": false, "expiry": { "mode": "relative", "amount": 14, "unit": "days" } },
"codeFormat": { "length": 10, "charset": "unambiguous", "prefix": "WELCOME-" },
"fallback": { "policy": "skip" },
"reuseOpenCode": true,
"lockToPerson": false
}
Ανάγνωση προγράμματος
GET /coupons/programs/{id}
Ενημέρωση προγράμματος
PATCH /coupons/programs/{id}
Οποιοδήποτε πεδίο του σώματος δημιουργίας, ή status (draft, active, paused, archived). Η αλλαγή ζωντανού προγράμματος χρειάζεται settings:write εκτός από campaigns:write.
Διαγραφή προγράμματος
DELETE /coupons/programs/{id}
204 για πρόγραμμα που δεν εξέδωσε ποτέ πραγματικό κωδικό. Ένα ζωντανό πρόγραμμα απαντά 409 - αρχειοθετήστε το αντί γι' αυτό (PATCH με "status": "archived").
Αναφορά προγράμματος
GET /coupons/programs/{id}/report
{
"programId": "6c0f3c1e-8a52-4a8e-9a39-2a1d7f0b9a11",
"totals": { "issued": 1240, "redeemed": 311, "redemptionRate": 0.2508, "revenue": 18420.5, "discount": 1842.05, "currency": "EUR", "expired": 402, "failed": 3, "redeemedBySomeoneElse": 12 },
"bySource": [
{ "kind": "journey", "id": "a1b2c3d4-0000-4000-8000-000000000001", "name": "Welcome journey", "issued": 980, "redeemed": 270, "revenue": 15900 }
],
"daily": [{ "date": "2026-10-04", "issued": 52, "redeemed": 14 }]
}
Τα έσοδα και η έκπτωση είναι και τα δύο στο νόμισμα αναφορών του χώρου εργασίας (currency): μια παραγγελία σε άλλο νόμισμα μετατρέπεται με τη δική της ισοτιμία, την ίδια με την οποία μετατράπηκαν τα έσοδά της. Οι δοκιμαστικοί κωδικοί δεν μετρούν.
Έκδοση κωδικού
POST /coupons/programs/{id}/issue
Δίνει έναν κωδικό από ενεργό πρόγραμμα σε μία επαφή - για συνεργάτες που δείχνουν τον κωδικό στο δικό τους κανάλι. Προσδιορίστε την επαφή με ένα από:
| Πεδίο | Περιγραφή |
|---|---|
contactId | Το εσωτερικό id επαφής του Joryio |
externalId | Το δικό σας id χρήστη |
email | Το email της επαφής |
issueKey | Προαιρετικό κλειδί idempotency: το ίδιο issueKey επιστρέφει πάντα τον ίδιο κωδικό |
{ "externalId": "customer-123", "issueKey": "order-confirmation-9876" }
Απόκριση:
{
"issued": true,
"reused": false,
"applyUrl": "https://shop.example.com/?jry_coupon=WELCOME-7KQ4M2XH9P",
"issue": {
"id": "1f6a...", "programId": "6c0f...", "programSlug": "welcome10", "programName": "Welcome 10%",
"contactId": "66a1f2c3d4e5f6a7b8c9d0e1", "code": "WELCOME-7KQ4M2XH9P", "status": "issued", "isTest": false,
"sourceKind": "api", "campaignId": null, "canvasId": null, "nodeId": null, "channel": null,
"issuedAt": "2026-10-04T09:00:00.000Z", "expiresAt": "2026-10-18T23:59:59.000Z",
"redeemedAt": null, "redeemedOrderId": null, "redeemedRevenue": null, "failureReason": null
}
}
Με ενεργό το reuseOpenCode του προγράμματος, μια επαφή που έχει ακόμη ανοιχτό κωδικό από το πρόγραμμα παίρνει αυτόν τον κωδικό ("reused": true). Όταν δεν μπορεί να εκδοθεί κωδικός η απάντηση είναι { "issued": false, "reason": "..." } - για παράδειγμα program_paused, store_error, store_permission_missing (το κατάστημα Shopify δεν έχει εγκρίνει ακόμη το write_discounts), store_reconnect_required (το WooCommerce προστέθηκε στον ιστότοπο WordPress μετά τη σύνδεσή του - αποσυνδέστε και συνδέστε ξανά το πρόσθετο Joryio).
Εκδοθέντες κωδικοί
GET /coupons/issues?contactId=66a1f2c3d4e5f6a7b8c9d0e1&programId=&status=&limit=50&offset=0
Επιστρέφει { "items": [issue, ...], "total": 3 }, από τον νεότερο. Το status είναι pending, issued, failed, redeemed, expired ή revoked. limit έως 200.
Συνδεδεμένα καταστήματα
GET /coupons/stores
[
{
"integrationId": "0b8d6f2a-5f43-4e0a-b9a3-7a8b2d1c4e55",
"platform": "shopify",
"storeName": "My Shop",
"storeUrl": "https://my-shop.myshopify.com",
"status": "connected",
"capabilities": { "lockToPerson": false, "perCodeExpiry": false, "percentCap": false, "scopes": ["all", "products", "collections"] },
"missingPermission": "write_discounts"
}
]
Το missingPermission δηλώνει τι πρέπει να εγκρίνει ο έμπορος πριν δημιουργηθούν κωδικοί (Shopify: ανοίξτε Integrations → Shopify → Approve new permissions).
Πηγές κωδικών
Το πεδίο source ενός προγράμματος λέει από πού προέρχονται οι κωδικοί του. Ορίζεται κατά τη δημιουργία (προεπιλογή personal) και δεν αλλάζει αφού το πρόγραμμα αποκτήσει κωδικούς. Δείτε Πηγές κωδικών.
source | Κωδικοί | sourceConfig |
|---|---|---|
personal | Ένας κωδικός ανά άτομο, που δημιουργείται όταν τον χρειάζεται ένα μήνυμα | {} |
bank | Δημιουργούνται στο κατάστημα εκ των προτέρων και μοιράζονται ένας ανά άτομο. Χρειάζεται integrationId. | { "bankTargetSize": 5000 } - πόσοι αχρησιμοποίητοι κωδικοί μένουν έτοιμοι (0 = μόνο κατ' απαίτηση και πριν από καμπάνιες) |
uploaded | Τους ανεβάζετε εσείς (Ανέβασμα κωδικών) και μοιράζονται ένας ανά άτομο· δεν δημιουργούνται ποτέ σε κατάστημα. integrationId προαιρετικό· lockToPerson δεν επιτρέπεται. | {} |
shared | Ένας κωδικός για όλους, καταγεγραμμένος ανά έκδοση | { "sharedCode": "SUMMER10", "createInStore": true } - το createInStore χρειάζεται integrationId· το false απλώς καταχωρίζει κωδικό που υπάρχει ήδη |
Τα προγράμματα έχουν επίσης:
| Πεδίο | Τιμές |
|---|---|
lowStock | { "threshold": 500, "percent": null } - για bank και uploaded: ειδοποίηση όταν απομένουν λιγότεροι από threshold αχρησιμοποίητοι κωδικοί, ή λιγότερο από percent (1-99) % όλων των κωδικών που φορτώθηκαν. Το null απενεργοποιεί έναν κανόνα. |
stock | Μόνο για ανάγνωση. { "available": 1830, "total": 5000, "level": "ok" } για bank και uploaded (level: ok, low, empty)· null για τις άλλες πηγές. |
Σε πρόγραμμα uploaded, και σε shared με createInStore: false, τα rules περιγράφουν μόνο την αξία που δείχνει το {{ coupons.<slug>.value }} - το κατάστημα δεν τα βλέπει ποτέ.
{
"name": "Partner coffee voucher",
"slug": "coffee",
"source": "uploaded",
"integrationId": null,
"lowStock": { "threshold": 200 },
"rules": { "discountType": "fixed_cart", "amount": 3, "currency": "EUR", "scope": { "kind": "all" }, "usageLimit": 1, "oncePerCustomer": true, "combinable": false, "expiry": { "mode": "none" } },
"fallback": { "policy": "send_without" }
}
Απόθεμα
GET /coupons/programs/{id}/stock
{
"programId": "6c0f3c1e-8a52-4a8e-9a39-2a1d7f0b9a11",
"source": "bank",
"tracked": true,
"available": 1830,
"total": 5000,
"used": 3170,
"level": "ok",
"lowStock": { "threshold": 500, "percent": null },
"bank": { "targetSize": 5000, "filling": false, "lastRunAt": "2026-10-04T09:15:00.000Z", "lastAdded": 250, "lastError": null }
}
Το tracked είναι false (και οι μετρήσεις 0) για προγράμματα personal και shared. Το bank υπάρχει μόνο στις τράπεζες κωδικών· το filling είναι true όσο εκτελείται συμπλήρωση.
Ανέβασμα κωδικών
POST /coupons/programs/{id}/codes
POST /coupons/programs/{id}/codes?dryRun=true
Προσθέτει κωδικούς σε πρόγραμμα uploaded. Στείλτε είτε αρχείο CSV ως multipart/form-data (πεδίο file) είτε JSON { "text": "...", "fileName": "optional.csv" } με τους κωδικούς επικολλημένους. Κάθε ανέβασμα προστίθεται· οι προηγούμενοι κωδικοί μένουν. Το dryRun=true ελέγχει και επιστρέφει την ίδια αναφορά χωρίς να αποθηκεύσει τίποτα - η προεπισκόπηση.
{ "text": "code,expires_at,value\nCOFFEE-001,2026-12-31,Free coffee\nCOFFEE-002,,Free coffee" }
| Στήλη | Υποχρεωτική | Μορφή |
|---|---|---|
code | Ναι | 3-64 χαρακτήρες: γράμματα, ψηφία και - _ . # / +· συγκρίνονται χωρίς διάκριση πεζών-κεφαλαίων |
expires_at | Όχι | YYYY-MM-DD (το τέλος εκείνης της ημέρας, UTC) ή ημερομηνία-ώρα ISO· πρέπει να είναι στο μέλλον |
value | Όχι | Έως 100 χαρακτήρες· εμφανίζεται ως {{ coupons.<slug>.value }} για αυτόν τον κωδικό |
Η γραμμή επικεφαλίδας είναι προαιρετική (χωρίς αυτήν οι στήλες διαβάζονται με αυτή τη σειρά)· τα διαχωριστικά κόμμα, ερωτηματικό και tab αναγνωρίζονται από την πρώτη γραμμή. Όρια: 100.000 γραμμές και 10 MB ανά ανέβασμα, 2.000.000 κωδικοί ανά πρόγραμμα.
Απάντηση (CouponUploadReport):
{
"uploadId": "9d2e4b10-1c3f-4b7a-8a55-0e6f2c9d1a77",
"dryRun": false,
"totalRows": 3,
"accepted": 2,
"rejected": 1,
"duplicates": 1,
"truncated": false,
"maxRows": 100000,
"hasHeader": true,
"preview": [{ "line": 2, "code": "COFFEE-001", "expiresAt": "2026-12-31T23:59:59.000Z", "value": "Free coffee" }],
"rejectedRows": [{ "line": 4, "code": "COFFEE-001", "reason": "duplicate_in_file", "message": "The same code appears earlier in this file." }]
}
Το uploadId είναι null σε δοκιμαστική εκτέλεση (dry run). Το preview περιέχει τις πρώτες 10 αποδεκτές γραμμές και το rejectedRows τις πρώτες 500 που απορρίφθηκαν. Το truncated είναι true όταν το αρχείο είχε περισσότερες γραμμές από maxRows (οι υπόλοιπες δεν διαβάστηκαν).
reason | Σημασία |
|---|---|
missing_code | Η γραμμή δεν έχει κωδικό |
invalid_code | Δεν είναι 3-64 γράμματα, ψηφία και - _ . # / + |
invalid_expiry | Η λήξη δεν είναι ημερομηνία |
expired | Η λήξη έχει περάσει |
value_too_long | Η αξία ξεπερνά τους 100 χαρακτήρες |
duplicate_in_file | Ο ίδιος κωδικός εμφανίζεται νωρίτερα στο αρχείο |
already_in_program | Το πρόγραμμα έχει ήδη τον κωδικό |
already_exists | Άλλο πρόγραμμα του χώρου εργασίας έχει τον κωδικό |
over_limit | Το πρόγραμμα είναι γεμάτο |
Ένα πρόγραμμα με άλλη πηγή απαντά 400.
Προηγούμενα ανεβάσματα
GET /coupons/programs/{id}/uploads
Τα τελευταία 100 ανεβάσματα, από το νεότερο: { "id", "kind", "fileName", "totalRows", "accepted", "rejected", "duplicates", "rejectedRows", "createdBy", "createdAt" }.
Δημιουργία κωδικών τράπεζας
POST /coupons/programs/{id}/bank/generate
{ "count": 5000 }
Δημιουργεί count (1-100.000) νέους κωδικούς στο κατάστημα για πρόγραμμα bank. Η εργασία τρέχει στο παρασκήνιο: η απάντηση είναι αμέσως 202 Accepted με { "started": true, "requested": 5000 }· παρακολουθήστε τη με το Απόθεμα (bank.filling, bank.lastAdded, bank.lastError). Ένα δεύτερο αίτημα όσο εκτελείται συμπλήρωση απαντά 400. Το Shopify προσθέτει κωδικούς στην έκπτωση του προγράμματος, το WooCommerce δημιουργεί ένα κουπόνι ανά κωδικό το Magento τους παράγει κάτω από τον κανόνα τιμής καλαθιού του προγράμματος με τη μορφή κωδικού του και το PrestaShop δημιουργεί έναν κανόνα καλαθιού ανά κωδικό.
Πριν σταλεί μια καμπάνια, κάθε τράπεζα που χρησιμοποιεί το περιεχόμενό της συμπληρώνεται αυτόματα ώστε να καλύπτει το κοινό. Το Launch Review μπλοκάρει καμπάνια της οποίας το κοινό είναι μεγαλύτερο από τους κωδικούς μιας τράπεζας ή λίστας (coupon_stock_short) και προειδοποιεί όταν η αποστολή αφήνει λιγότερους κωδικούς από την ειδοποίηση χαμηλού αποθέματος (coupon_stock_low).
Σφάλματα
| Κατάσταση | Πότε |
|---|---|
400 | Επικύρωση - για παράδειγμα lockToPerson σε πρόγραμμα Shopify (το Shopify ορίζει ποιος χρησιμοποιεί μια έκπτωση ανά έκπτωση, όχι ανά κωδικό), slug που υπάρχει ήδη ή δεν είναι [a-z0-9_], shared_code χωρίς sharedCode, ημερομηνία λήξης στο παρελθόν |
403 | Λείπει δικαίωμα - μαζί με το settings:write στην αλλαγή ζωντανού προγράμματος |
404 | Το πρόγραμμα δεν βρίσκεται σε αυτόν τον χώρο εργασίας |
409 | Διαγραφή ζωντανού προγράμματος |