דלג לתוכן הראשי

Coupons API

תוכנית קופונים היא המתכון שממנו הודעה מנפיקה קודים אישיים ({{ coupons.<slug>.code }}). Joryio יוצרת כל קוד בחנות WooCommerce,‏ Shopify,‏ Magento או PrestaShop המחוברת (או מייצרת ועוקבת אחריו לבד כשלתוכנית אין חנות) ומזהה את ההזמנה שהשתמשה בו. ההתנהגות של התוכניות מתוארת בקודי קופון.

כל נקודות הקצה בעמוד הזה יחסיות לכתובת הבסיס: 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 מייצרת ועוקבת אחרי הקודים בלי חנות
statusdraft, active, paused, archived - רק active מנפיקה קודים
rules.discountTypepercent, fixed_cart, fixed_product (לא ב-PrestaShop: 400), free_shipping
rules.scope{ "kind": "all" }, או products (WooCommerce, Shopify, PrestaShop) / categories (WooCommerce, Magento, PrestaShop) / collections (Shopify) עם ids - המזהים של החנות עצמה; products ב-Magento מחזיר 400
rules.minimumQuantityShopify בלבד
rules.excludeSaleItemsWooCommerce בלבד
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.charsetunambiguous (אותיות וספרות ללא תווים דומים, ברירת מחדל), letters, digits; length 6-20
fallback.policyskip (ברירת מחדל), shared_code (דורש sharedCode), send_without
lockToPersonWooCommerce,‏ Magento ו-PrestaShop (חשבון הלקוח של האדם)
livetrue מרגע שהתוכנית הנפיקה קוד אמיתי (לא קוד בדיקה)
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מזהה איש הקשר הפנימי של Joryio
externalIdמזהה המשתמש שלכם
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 }} לקוד הזה

שורת הכותרת אופציונלית (בלעדיה העמודות נקראות בסדר הזה); מפרידי פסיק, נקודה-פסיק וטאב מזוהים מהשורה הראשונה. מגבלות: 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מחיקת תוכנית חיה