{"openapi":"3.1.0","info":{"title":"Ishtaqna API","version":"1","description":"Everything the Ishtaqna dashboard does, from code. Send `Authorization: Bearer <API key>`. Errors are `{ error: { code, message } }`, and codes never change meaning. The same actions are MCP tools at /mcp; docs at /docs."},"servers":[{"url":"https://ishtaqna.com"}],"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","validation_failed","conflict","revision_conflict","rate_limited","subscription_required","plan_limit_emails","plan_limit_contacts","plan_limit_brands","credit_insufficient","account_blocked","sender_not_allowed","send_check_failed","no_recipients","channel_not_connected","template_not_approved","quiet_hours","sending_disabled","unavailable","internal_error"]},"message":{"type":"string"}}}}}}},"paths":{"/api/v1/organization":{"get":{"operationId":"get_organization","summary":"Get the organization","description":"Gets the organization the key or session belongs to: its name, country, time zone, plan and the plan's limits.","tags":["Organization"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"timezone":{"type":"string"},"locale":{"type":"string","enum":["ar","en"]},"status":{"type":"string","enum":["active","blocked","deleting"]},"plan":{"type":"string"},"limits":{"type":"object","properties":{"contacts":{"type":"number"},"emailsPerMonth":{"type":"number"},"emailsPerDay":{"description":"A daily ceiling on top of the monthly one (the free plan's 250); null for none.","type":["number","null"]},"whatsappRecipientsPerMonth":{"type":"number"},"brands":{"type":"number"},"seats":{"type":"number"}},"required":["contacts","emailsPerMonth","emailsPerDay","whatsappRecipientsPerMonth","brands","seats"],"additionalProperties":false},"usage":{"type":"object","properties":{"period":{"type":"string"},"emails":{"type":"number"}},"required":["period","emails"],"additionalProperties":false,"description":"This calendar month's usage, counted against the plan."},"createdAt":{"type":"string"}},"required":["id","name","country","timezone","locale","status","plan","limits","usage","createdAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"patch":{"operationId":"update_organization","summary":"Update the organization","description":"Changes the organization's name, time zone or language. Send only the fields to change; the others stay as they are.","tags":["Organization"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"country":{"type":"string"},"timezone":{"type":"string"},"locale":{"type":"string","enum":["ar","en"]},"status":{"type":"string","enum":["active","blocked","deleting"]},"plan":{"type":"string"},"limits":{"type":"object","properties":{"contacts":{"type":"number"},"emailsPerMonth":{"type":"number"},"emailsPerDay":{"description":"A daily ceiling on top of the monthly one (the free plan's 250); null for none.","type":["number","null"]},"whatsappRecipientsPerMonth":{"type":"number"},"brands":{"type":"number"},"seats":{"type":"number"}},"required":["contacts","emailsPerMonth","emailsPerDay","whatsappRecipientsPerMonth","brands","seats"],"additionalProperties":false},"usage":{"type":"object","properties":{"period":{"type":"string"},"emails":{"type":"number"}},"required":["period","emails"],"additionalProperties":false,"description":"This calendar month's usage, counted against the plan."},"createdAt":{"type":"string"}},"required":["id","name","country","timezone","locale","status","plan","limits","usage","createdAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"The business name, as customers know it.","type":"string","minLength":1,"maxLength":120},"timezone":{"description":"IANA time zone used for schedules and quiet hours, e.g. Asia/Riyadh.","type":"string"},"locale":{"description":"Language of the dashboard and system emails.","type":"string","enum":["ar","en"]}},"required":[]}}}}},"delete":{"operationId":"delete_organization","summary":"Delete the account","description":"Deletes the organization and everything in it: contacts, campaigns, brands, automations, store connections, keys and members. The account locks at once and all sending stops; the data is erased for good 30 days later. Opt-out records are kept as one-way hashes so unsubscribed people are never contacted again. Send the organization's exact name and acknowledged: true (the owner read /legal/delete-account) to confirm. It can't be undone.","tags":["Organization"],"parameters":[{"name":"confirm","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The organization's exact name, as a confirmation."}},{"name":"acknowledged","in":"query","required":true,"schema":{"type":"boolean","description":"true: the owner has read /legal/delete-account and understands the deletion is permanent."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","const":true},"erasedAfter":{"type":"string","description":"When the data is erased for good (ISO 8601)."}},"required":["deleted","erasedAfter"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"owner","hints":{"destructive":true,"idempotent":false}}}},"/api/v1/organization/sending-health":{"get":{"operationId":"get_sending_health","summary":"Get sending health","description":"Shows how healthy this organization's email sending is: bounce and complaint rates over 30 days against the pause and block levels, the sending tier, each brand's Gmail warm-up allowance, and how many contacts are dormant or suppressed.","tags":["Organization"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","blocked","deleting"]},"timezone":{"type":"string","description":"The organization's IANA time zone, for showing times."},"blockedReason":{"description":"high_bounces or high_complaints when sending was blocked automatically.","type":["string","null"]},"tier":{"type":"string","enum":["probation","main"],"description":"New organizations send from the probation domain for 30 days or 5,000 clean emails."},"level":{"type":"string","enum":["good","watch","blocked"],"description":"watch: rates are above half the pause level."},"last30Days":{"type":"object","properties":{"sent":{"type":"number"},"hardBounces":{"type":"number"},"complaints":{"type":"number"},"bounceRate":{"type":"number","description":"Percent of sent."},"complaintRate":{"type":"number","description":"Percent of sent."}},"required":["sent","hardBounces","complaints","bounceRate","complaintRate"],"additionalProperties":false},"thresholds":{"type":"object","properties":{"pauseBounceRate":{"type":"number"},"pauseComplaintRate":{"type":"number"},"blockBounceRate":{"type":"number"},"blockComplaintRate":{"type":"number"}},"required":["pauseBounceRate","pauseComplaintRate","blockBounceRate","blockComplaintRate"],"additionalProperties":false},"brands":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nameAr":{"type":"string"},"sender":{"type":"string"},"gmailSentToday":{"type":"number"},"gmailCapToday":{"description":"Gmail recipients allowed today while the brand warms up; null means no limit.","type":["number","null"]},"gmailPausedUntil":{"description":"Set when Gmail asked us to slow down.","type":["string","null"]}},"required":["id","nameAr","sender","gmailSentToday","gmailCapToday","gmailPausedUntil"],"additionalProperties":false}},"dormant":{"type":"number","description":"Contacts who stopped reading and no longer get email (they don't count toward the plan)."},"suppressed":{"type":"number","description":"Addresses that bounced, complained or unsubscribed: never emailed again."}},"required":["status","timezone","blockedReason","tier","level","last30Days","thresholds","brands","dormant","suppressed"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/organization/stats":{"get":{"operationId":"get_overview_stats","summary":"Get the overview numbers","description":"The organization's numbers for the last 7 or 30 days next to the period before: messages sent, opened, clicked and unsubscribed (campaigns and automations, tests excluded), how many contacts it has and gained with a daily series, the latest sent campaigns with their open rates, the same numbers day by day, and the 12 latest events (opens, clicks, unsubscribes, paid orders, signups and imports) for an activity feed.","tags":["Organization"],"parameters":[{"name":"days","in":"query","required":false,"schema":{"default":30,"description":"7 or 30 (default).","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"days":{"type":"number"},"current":{"type":"object","properties":{"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"},"openRate":{"type":"number","description":"Percent of sent."},"clickRate":{"type":"number"},"unsubscribeRate":{"type":"number"}},"required":["sent","opened","clicked","unsubscribed","openRate","clickRate","unsubscribeRate"],"additionalProperties":false},"previous":{"type":"object","properties":{"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"},"openRate":{"type":"number","description":"Percent of sent."},"clickRate":{"type":"number"},"unsubscribeRate":{"type":"number"}},"required":["sent","opened","clicked","unsubscribed","openRate","clickRate","unsubscribeRate"],"additionalProperties":false},"contacts":{"type":"object","properties":{"total":{"type":"number"},"added":{"type":"number","description":"Added in the period."},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"total":{"type":"number"}},"required":["date","total"],"additionalProperties":false},"description":"Contacts at the end of each day of the period."}},"required":["total","added","series"],"additionalProperties":false},"recentCampaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sentAt":{"type":["string","null"]},"sent":{"type":"number"},"openRate":{"type":"number"}},"required":["id","name","sentAt","sent","openRate"],"additionalProperties":false}},"daily":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"sent":{"type":"number"},"opened":{"type":"number"},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["date","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"description":"Each day of the period, oldest first, counted by the day the message was sent."},"activity":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["open","click","unsubscribe","order","signup","import"]},"at":{"type":"string"},"contactId":{"type":["string","null"]},"contactName":{"description":"Their name, or their email or phone when there is no name.","type":["string","null"]},"channel":{"description":"email or whatsapp, for opens, clicks and unsubscribes.","type":["string","null"]},"campaignId":{"type":["string","null"]},"campaignName":{"description":"The campaign or automation behind the event; for orders, the one credited.","type":["string","null"]},"amount":{"description":"Order total, for paid orders.","type":["number","null"]},"currency":{"type":["string","null"]},"source":{"description":"Where a signup came from (page, api, dashboard, website…).","type":["string","null"]},"added":{"description":"Contacts added, for a finished import.","type":["number","null"]},"fileName":{"description":"The imported file, for imports.","type":["string","null"]}},"required":["type","at","contactId","contactName","channel","campaignId","campaignName","amount","currency","source","added","fileName"],"additionalProperties":false},"description":"The 12 latest events, newest first: opens, clicks and unsubscribes on campaigns and automations, paid store orders, contacts added one at a time, and finished imports."}},"required":["days","current","previous","contacts","recentCampaigns","daily","activity"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/brands":{"get":{"operationId":"list_brands","summary":"List brands","description":"Lists the organization's brands (its shops, clinics or stores), oldest first, with their sending addresses.","tags":["Brands"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"brands":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAr":{"type":"string"},"nameEn":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"postalAddress":{"type":["string","null"]},"replyToEmail":{"type":["string","null"]},"replyToWhatsapp":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"sharedSender":{"type":"string","description":"The ready-to-use sending address for brands without their own domain. New organizations send from the probation domain until they prove clean."},"page":{"type":"object","properties":{"enabled":{"default":true,"description":"false hides the page (it answers 404).","type":"boolean"},"headline":{"default":"","description":"The big line under the logo; the brand's Arabic name when empty.","type":"string","maxLength":80},"description":{"default":"","description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"default":"teal","description":"Button and logo color: teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"customColor":{"default":"","description":"The brand's own color, e.g. #0F766E. Overrides accent when set; button text turns white or black to stay readable."},"theme":{"default":"light","description":"light: white; soft: tinted with the brand color; dark: near black.","type":"string","enum":["light","soft","dark"]},"background":{"default":"dots","description":"Behind the top of the page: plain, dots, grid, glow (a soft breathing light) or aurora (two slowly drifting lights).","type":"string","enum":["plain","dots","grid","glow","aurora"]},"collect":{"default":"both","description":"What the form asks for: email, phone (WhatsApp) or both.","type":"string","enum":["email","phone","both"]},"askName":{"default":true,"description":"Ask for a first name, used in {{first_name}}.","type":"boolean"},"buttonText":{"default":"","description":"The subscribe button; «اشترك» when empty.","type":"string","maxLength":30},"thanksText":{"default":"","description":"Shown after subscribing; a sensible Arabic default when empty.","type":"string","maxLength":200},"showCount":{"default":false,"description":"Show how many subscribers joined (only from 50).","type":"boolean"},"links":{"default":{"whatsapp":"","instagram":"","x":"","tiktok":"","snapchat":"","facebook":"","telegram":"","youtube":"","threads":"","website":""},"description":"Links shown under the form; empty ones are hidden.","type":"object","properties":{"whatsapp":{"default":"","description":"A WhatsApp number in international format, e.g. +966500000000.","type":"string","maxLength":20},"instagram":{"default":"","description":"Instagram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"x":{"default":"","description":"X (Twitter): a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"tiktok":{"default":"","description":"TikTok: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"snapchat":{"default":"","description":"Snapchat: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"facebook":{"default":"","description":"Facebook: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"telegram":{"default":"","description":"Telegram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"youtube":{"default":"","description":"YouTube: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"threads":{"default":"","description":"Threads: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"website":{"default":"","description":"The brand's website.","type":"string","maxLength":300}},"required":["whatsapp","instagram","x","tiktok","snapchat","facebook","telegram","youtube","threads","website"],"additionalProperties":false}},"required":["enabled","headline","description","accent","customColor","theme","background","collect","askName","buttonText","thanksText","showCount","links"],"additionalProperties":false,"description":"The brand's public signup page settings."},"design":{"type":"object","properties":{"background":{"default":"#FFFFFF","description":"The email's background, e.g. #FFFFFF."},"text":{"default":"#171717","description":"Headings and text, e.g. #171717."},"accent":{"default":"#0F766E","description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable."},"corners":{"default":"medium","type":"string","enum":["none","small","medium","large","full"],"description":"Button and image corners: none, small, medium, large or full (round buttons)."},"align":{"default":"right","type":"string","enum":["right","center"],"description":"right: aligned to the start, like a letter. center: centered, like an announcement."},"header":{"default":"logo","type":"string","enum":["logo","name","none"],"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing."}},"required":["background","text","accent","corners","align","header"],"additionalProperties":false,"description":"How the brand's emails look: colors, corners, alignment and header."},"pageUrl":{"type":"string","description":"Where the page lives: https://<slug>.ishtaqna.com."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","nameAr","nameEn","logoUrl","postalAddress","replyToEmail","replyToWhatsapp","websiteUrl","sharedSender","page","design","pageUrl","createdAt","updatedAt"],"additionalProperties":false}}},"required":["brands"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_brand","summary":"Create a brand","description":"Adds a brand (a shop, clinic or store) to the organization. It can send at once from its shared address hello@<slug>.<shared domain>.","tags":["Brands"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAr":{"type":"string"},"nameEn":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"postalAddress":{"type":["string","null"]},"replyToEmail":{"type":["string","null"]},"replyToWhatsapp":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"sharedSender":{"type":"string","description":"The ready-to-use sending address for brands without their own domain. New organizations send from the probation domain until they prove clean."},"page":{"type":"object","properties":{"enabled":{"default":true,"description":"false hides the page (it answers 404).","type":"boolean"},"headline":{"default":"","description":"The big line under the logo; the brand's Arabic name when empty.","type":"string","maxLength":80},"description":{"default":"","description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"default":"teal","description":"Button and logo color: teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"customColor":{"default":"","description":"The brand's own color, e.g. #0F766E. Overrides accent when set; button text turns white or black to stay readable."},"theme":{"default":"light","description":"light: white; soft: tinted with the brand color; dark: near black.","type":"string","enum":["light","soft","dark"]},"background":{"default":"dots","description":"Behind the top of the page: plain, dots, grid, glow (a soft breathing light) or aurora (two slowly drifting lights).","type":"string","enum":["plain","dots","grid","glow","aurora"]},"collect":{"default":"both","description":"What the form asks for: email, phone (WhatsApp) or both.","type":"string","enum":["email","phone","both"]},"askName":{"default":true,"description":"Ask for a first name, used in {{first_name}}.","type":"boolean"},"buttonText":{"default":"","description":"The subscribe button; «اشترك» when empty.","type":"string","maxLength":30},"thanksText":{"default":"","description":"Shown after subscribing; a sensible Arabic default when empty.","type":"string","maxLength":200},"showCount":{"default":false,"description":"Show how many subscribers joined (only from 50).","type":"boolean"},"links":{"default":{"whatsapp":"","instagram":"","x":"","tiktok":"","snapchat":"","facebook":"","telegram":"","youtube":"","threads":"","website":""},"description":"Links shown under the form; empty ones are hidden.","type":"object","properties":{"whatsapp":{"default":"","description":"A WhatsApp number in international format, e.g. +966500000000.","type":"string","maxLength":20},"instagram":{"default":"","description":"Instagram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"x":{"default":"","description":"X (Twitter): a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"tiktok":{"default":"","description":"TikTok: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"snapchat":{"default":"","description":"Snapchat: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"facebook":{"default":"","description":"Facebook: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"telegram":{"default":"","description":"Telegram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"youtube":{"default":"","description":"YouTube: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"threads":{"default":"","description":"Threads: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"website":{"default":"","description":"The brand's website.","type":"string","maxLength":300}},"required":["whatsapp","instagram","x","tiktok","snapchat","facebook","telegram","youtube","threads","website"],"additionalProperties":false}},"required":["enabled","headline","description","accent","customColor","theme","background","collect","askName","buttonText","thanksText","showCount","links"],"additionalProperties":false,"description":"The brand's public signup page settings."},"design":{"type":"object","properties":{"background":{"default":"#FFFFFF","description":"The email's background, e.g. #FFFFFF."},"text":{"default":"#171717","description":"Headings and text, e.g. #171717."},"accent":{"default":"#0F766E","description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable."},"corners":{"default":"medium","type":"string","enum":["none","small","medium","large","full"],"description":"Button and image corners: none, small, medium, large or full (round buttons)."},"align":{"default":"right","type":"string","enum":["right","center"],"description":"right: aligned to the start, like a letter. center: centered, like an announcement."},"header":{"default":"logo","type":"string","enum":["logo","name","none"],"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing."}},"required":["background","text","accent","corners","align","header"],"additionalProperties":false,"description":"How the brand's emails look: colors, corners, alignment and header."},"pageUrl":{"type":"string","description":"Where the page lives: https://<slug>.ishtaqna.com."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","nameAr","nameEn","logoUrl","postalAddress","replyToEmail","replyToWhatsapp","websiteUrl","sharedSender","page","design","pageUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"nameAr":{"type":"string","minLength":1,"maxLength":80,"description":"The brand name in Arabic, as customers see it in messages."},"nameEn":{"description":"The brand name in English, if it has one.","type":"string","minLength":1,"maxLength":80},"postalAddress":{"description":"Business address printed in email footers. Emails can't be sent without one.","type":"string","maxLength":300},"replyToEmail":{"description":"Where email replies go, e.g. the owner's Gmail.","type":"string","format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"replyToWhatsapp":{"description":"WhatsApp number for the reply button in emails, in international format.","type":"string","pattern":"^\\+[1-9][0-9]{7,14}$"},"websiteUrl":{"description":"The brand's website or Instagram page.","type":"string","format":"uri"},"logoUrl":{"description":"Square logo, https link.","type":"string","format":"starts_with","pattern":"^https:\\/\\/.*"},"slug":{"description":"Lowercase letters, digits and dashes, 3 to 40 characters. Default: made from nameEn, or random.","type":"string"}},"required":["nameAr"]}}}}}},"/api/v1/brands/{id}":{"get":{"operationId":"get_brand","summary":"Get a brand","description":"Gets one brand of the organization by its ID, with its names, reply-to details and sending address.","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAr":{"type":"string"},"nameEn":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"postalAddress":{"type":["string","null"]},"replyToEmail":{"type":["string","null"]},"replyToWhatsapp":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"sharedSender":{"type":"string","description":"The ready-to-use sending address for brands without their own domain. New organizations send from the probation domain until they prove clean."},"page":{"type":"object","properties":{"enabled":{"default":true,"description":"false hides the page (it answers 404).","type":"boolean"},"headline":{"default":"","description":"The big line under the logo; the brand's Arabic name when empty.","type":"string","maxLength":80},"description":{"default":"","description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"default":"teal","description":"Button and logo color: teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"customColor":{"default":"","description":"The brand's own color, e.g. #0F766E. Overrides accent when set; button text turns white or black to stay readable."},"theme":{"default":"light","description":"light: white; soft: tinted with the brand color; dark: near black.","type":"string","enum":["light","soft","dark"]},"background":{"default":"dots","description":"Behind the top of the page: plain, dots, grid, glow (a soft breathing light) or aurora (two slowly drifting lights).","type":"string","enum":["plain","dots","grid","glow","aurora"]},"collect":{"default":"both","description":"What the form asks for: email, phone (WhatsApp) or both.","type":"string","enum":["email","phone","both"]},"askName":{"default":true,"description":"Ask for a first name, used in {{first_name}}.","type":"boolean"},"buttonText":{"default":"","description":"The subscribe button; «اشترك» when empty.","type":"string","maxLength":30},"thanksText":{"default":"","description":"Shown after subscribing; a sensible Arabic default when empty.","type":"string","maxLength":200},"showCount":{"default":false,"description":"Show how many subscribers joined (only from 50).","type":"boolean"},"links":{"default":{"whatsapp":"","instagram":"","x":"","tiktok":"","snapchat":"","facebook":"","telegram":"","youtube":"","threads":"","website":""},"description":"Links shown under the form; empty ones are hidden.","type":"object","properties":{"whatsapp":{"default":"","description":"A WhatsApp number in international format, e.g. +966500000000.","type":"string","maxLength":20},"instagram":{"default":"","description":"Instagram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"x":{"default":"","description":"X (Twitter): a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"tiktok":{"default":"","description":"TikTok: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"snapchat":{"default":"","description":"Snapchat: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"facebook":{"default":"","description":"Facebook: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"telegram":{"default":"","description":"Telegram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"youtube":{"default":"","description":"YouTube: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"threads":{"default":"","description":"Threads: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"website":{"default":"","description":"The brand's website.","type":"string","maxLength":300}},"required":["whatsapp","instagram","x","tiktok","snapchat","facebook","telegram","youtube","threads","website"],"additionalProperties":false}},"required":["enabled","headline","description","accent","customColor","theme","background","collect","askName","buttonText","thanksText","showCount","links"],"additionalProperties":false,"description":"The brand's public signup page settings."},"design":{"type":"object","properties":{"background":{"default":"#FFFFFF","description":"The email's background, e.g. #FFFFFF."},"text":{"default":"#171717","description":"Headings and text, e.g. #171717."},"accent":{"default":"#0F766E","description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable."},"corners":{"default":"medium","type":"string","enum":["none","small","medium","large","full"],"description":"Button and image corners: none, small, medium, large or full (round buttons)."},"align":{"default":"right","type":"string","enum":["right","center"],"description":"right: aligned to the start, like a letter. center: centered, like an announcement."},"header":{"default":"logo","type":"string","enum":["logo","name","none"],"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing."}},"required":["background","text","accent","corners","align","header"],"additionalProperties":false,"description":"How the brand's emails look: colors, corners, alignment and header."},"pageUrl":{"type":"string","description":"Where the page lives: https://<slug>.ishtaqna.com."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","nameAr","nameEn","logoUrl","postalAddress","replyToEmail","replyToWhatsapp","websiteUrl","sharedSender","page","design","pageUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"patch":{"operationId":"update_brand","summary":"Update a brand","description":"Changes a brand's names, address, reply-to details, website or logo. Send only the fields to change.","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAr":{"type":"string"},"nameEn":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"postalAddress":{"type":["string","null"]},"replyToEmail":{"type":["string","null"]},"replyToWhatsapp":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"sharedSender":{"type":"string","description":"The ready-to-use sending address for brands without their own domain. New organizations send from the probation domain until they prove clean."},"page":{"type":"object","properties":{"enabled":{"default":true,"description":"false hides the page (it answers 404).","type":"boolean"},"headline":{"default":"","description":"The big line under the logo; the brand's Arabic name when empty.","type":"string","maxLength":80},"description":{"default":"","description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"default":"teal","description":"Button and logo color: teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"customColor":{"default":"","description":"The brand's own color, e.g. #0F766E. Overrides accent when set; button text turns white or black to stay readable."},"theme":{"default":"light","description":"light: white; soft: tinted with the brand color; dark: near black.","type":"string","enum":["light","soft","dark"]},"background":{"default":"dots","description":"Behind the top of the page: plain, dots, grid, glow (a soft breathing light) or aurora (two slowly drifting lights).","type":"string","enum":["plain","dots","grid","glow","aurora"]},"collect":{"default":"both","description":"What the form asks for: email, phone (WhatsApp) or both.","type":"string","enum":["email","phone","both"]},"askName":{"default":true,"description":"Ask for a first name, used in {{first_name}}.","type":"boolean"},"buttonText":{"default":"","description":"The subscribe button; «اشترك» when empty.","type":"string","maxLength":30},"thanksText":{"default":"","description":"Shown after subscribing; a sensible Arabic default when empty.","type":"string","maxLength":200},"showCount":{"default":false,"description":"Show how many subscribers joined (only from 50).","type":"boolean"},"links":{"default":{"whatsapp":"","instagram":"","x":"","tiktok":"","snapchat":"","facebook":"","telegram":"","youtube":"","threads":"","website":""},"description":"Links shown under the form; empty ones are hidden.","type":"object","properties":{"whatsapp":{"default":"","description":"A WhatsApp number in international format, e.g. +966500000000.","type":"string","maxLength":20},"instagram":{"default":"","description":"Instagram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"x":{"default":"","description":"X (Twitter): a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"tiktok":{"default":"","description":"TikTok: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"snapchat":{"default":"","description":"Snapchat: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"facebook":{"default":"","description":"Facebook: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"telegram":{"default":"","description":"Telegram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"youtube":{"default":"","description":"YouTube: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"threads":{"default":"","description":"Threads: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"website":{"default":"","description":"The brand's website.","type":"string","maxLength":300}},"required":["whatsapp","instagram","x","tiktok","snapchat","facebook","telegram","youtube","threads","website"],"additionalProperties":false}},"required":["enabled","headline","description","accent","customColor","theme","background","collect","askName","buttonText","thanksText","showCount","links"],"additionalProperties":false,"description":"The brand's public signup page settings."},"design":{"type":"object","properties":{"background":{"default":"#FFFFFF","description":"The email's background, e.g. #FFFFFF."},"text":{"default":"#171717","description":"Headings and text, e.g. #171717."},"accent":{"default":"#0F766E","description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable."},"corners":{"default":"medium","type":"string","enum":["none","small","medium","large","full"],"description":"Button and image corners: none, small, medium, large or full (round buttons)."},"align":{"default":"right","type":"string","enum":["right","center"],"description":"right: aligned to the start, like a letter. center: centered, like an announcement."},"header":{"default":"logo","type":"string","enum":["logo","name","none"],"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing."}},"required":["background","text","accent","corners","align","header"],"additionalProperties":false,"description":"How the brand's emails look: colors, corners, alignment and header."},"pageUrl":{"type":"string","description":"Where the page lives: https://<slug>.ishtaqna.com."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","nameAr","nameEn","logoUrl","postalAddress","replyToEmail","replyToWhatsapp","websiteUrl","sharedSender","page","design","pageUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"nameAr":{"description":"The brand name in Arabic, as customers see it in messages.","type":"string","minLength":1,"maxLength":80},"nameEn":{"description":"The brand name in English, if it has one.","type":"string","minLength":1,"maxLength":80},"postalAddress":{"description":"Business address printed in email footers. Emails can't be sent without one.","type":"string","maxLength":300},"replyToEmail":{"description":"Where email replies go, e.g. the owner's Gmail.","type":"string","format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"},"replyToWhatsapp":{"description":"WhatsApp number for the reply button in emails, in international format.","type":"string","pattern":"^\\+[1-9][0-9]{7,14}$"},"websiteUrl":{"description":"The brand's website or Instagram page.","type":"string","format":"uri"},"logoUrl":{"description":"Square logo, https link; null removes it.","anyOf":[{"description":"Square logo, https link.","type":"string","format":"starts_with","pattern":"^https:\\/\\/.*"},{"type":"null"}]}},"required":[]}}}}},"delete":{"operationId":"delete_brand","summary":"Delete a brand","description":"Deletes a brand. Its campaigns stop and its shared sending address stops working. It can't be undone. The last brand can't be deleted.","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["id","deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"owner","hints":{"destructive":true,"idempotent":true}}}},"/api/v1/brands/slugs/{slug}":{"get":{"operationId":"check_brand_slug","summary":"Check a brand slug","description":"Says whether a slug is free to use. The slug becomes the brand's subdomain on the shared sending domain.","tags":["Brands"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","description":"The slug to check, e.g. alsanabel."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"available":{"type":"boolean"},"reason":{"type":"string","enum":["ok","invalid","taken"]}},"required":["slug","available","reason"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/brands/{id}/page":{"patch":{"operationId":"update_brand_page","summary":"Customize a brand's page","description":"Changes the brand's public signup page at <slug>.ishtaqna.com: whether it's on, its headline and description, its color (a preset or the brand's own), theme and background, what it asks for (email, phone or both, and a first name), the button and thank-you text, the subscriber count, and links (WhatsApp, Instagram, X, TikTok, Snapchat, Facebook, Telegram, YouTube, Threads, a website). Send only what changes.","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAr":{"type":"string"},"nameEn":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"postalAddress":{"type":["string","null"]},"replyToEmail":{"type":["string","null"]},"replyToWhatsapp":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"sharedSender":{"type":"string","description":"The ready-to-use sending address for brands without their own domain. New organizations send from the probation domain until they prove clean."},"page":{"type":"object","properties":{"enabled":{"default":true,"description":"false hides the page (it answers 404).","type":"boolean"},"headline":{"default":"","description":"The big line under the logo; the brand's Arabic name when empty.","type":"string","maxLength":80},"description":{"default":"","description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"default":"teal","description":"Button and logo color: teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"customColor":{"default":"","description":"The brand's own color, e.g. #0F766E. Overrides accent when set; button text turns white or black to stay readable."},"theme":{"default":"light","description":"light: white; soft: tinted with the brand color; dark: near black.","type":"string","enum":["light","soft","dark"]},"background":{"default":"dots","description":"Behind the top of the page: plain, dots, grid, glow (a soft breathing light) or aurora (two slowly drifting lights).","type":"string","enum":["plain","dots","grid","glow","aurora"]},"collect":{"default":"both","description":"What the form asks for: email, phone (WhatsApp) or both.","type":"string","enum":["email","phone","both"]},"askName":{"default":true,"description":"Ask for a first name, used in {{first_name}}.","type":"boolean"},"buttonText":{"default":"","description":"The subscribe button; «اشترك» when empty.","type":"string","maxLength":30},"thanksText":{"default":"","description":"Shown after subscribing; a sensible Arabic default when empty.","type":"string","maxLength":200},"showCount":{"default":false,"description":"Show how many subscribers joined (only from 50).","type":"boolean"},"links":{"default":{"whatsapp":"","instagram":"","x":"","tiktok":"","snapchat":"","facebook":"","telegram":"","youtube":"","threads":"","website":""},"description":"Links shown under the form; empty ones are hidden.","type":"object","properties":{"whatsapp":{"default":"","description":"A WhatsApp number in international format, e.g. +966500000000.","type":"string","maxLength":20},"instagram":{"default":"","description":"Instagram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"x":{"default":"","description":"X (Twitter): a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"tiktok":{"default":"","description":"TikTok: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"snapchat":{"default":"","description":"Snapchat: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"facebook":{"default":"","description":"Facebook: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"telegram":{"default":"","description":"Telegram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"youtube":{"default":"","description":"YouTube: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"threads":{"default":"","description":"Threads: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"website":{"default":"","description":"The brand's website.","type":"string","maxLength":300}},"required":["whatsapp","instagram","x","tiktok","snapchat","facebook","telegram","youtube","threads","website"],"additionalProperties":false}},"required":["enabled","headline","description","accent","customColor","theme","background","collect","askName","buttonText","thanksText","showCount","links"],"additionalProperties":false,"description":"The brand's public signup page settings."},"design":{"type":"object","properties":{"background":{"default":"#FFFFFF","description":"The email's background, e.g. #FFFFFF."},"text":{"default":"#171717","description":"Headings and text, e.g. #171717."},"accent":{"default":"#0F766E","description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable."},"corners":{"default":"medium","type":"string","enum":["none","small","medium","large","full"],"description":"Button and image corners: none, small, medium, large or full (round buttons)."},"align":{"default":"right","type":"string","enum":["right","center"],"description":"right: aligned to the start, like a letter. center: centered, like an announcement."},"header":{"default":"logo","type":"string","enum":["logo","name","none"],"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing."}},"required":["background","text","accent","corners","align","header"],"additionalProperties":false,"description":"How the brand's emails look: colors, corners, alignment and header."},"pageUrl":{"type":"string","description":"Where the page lives: https://<slug>.ishtaqna.com."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","nameAr","nameEn","logoUrl","postalAddress","replyToEmail","replyToWhatsapp","websiteUrl","sharedSender","page","design","pageUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"description":"false hides the page.","type":"boolean"},"headline":{"description":"The big line; the brand name when empty.","type":"string","maxLength":80},"description":{"description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"description":"teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"collect":{"description":"email, phone or both.","type":"string","enum":["email","phone","both"]},"askName":{"description":"Ask for a first name.","type":"boolean"},"buttonText":{"description":"The subscribe button text.","type":"string","maxLength":30},"thanksText":{"description":"Shown after subscribing.","type":"string","maxLength":200},"showCount":{"description":"Show the number of subscribers (from 50).","type":"boolean"},"customColor":{"description":"The brand's own color, e.g. #0F766E; empty goes back to accent.","type":"string","maxLength":7},"theme":{"description":"light, soft (tinted) or dark.","type":"string","enum":["light","soft","dark"]},"background":{"description":"plain, dots, grid, glow or aurora.","type":"string","enum":["plain","dots","grid","glow","aurora"]},"links":{"description":"Links under the form; send only the ones that change.","type":"object","properties":{"whatsapp":{"description":"+966500000000","type":"string","maxLength":20},"instagram":{"description":"Handle or https:// link.","type":"string","maxLength":200},"x":{"description":"Handle or https:// link.","type":"string","maxLength":200},"tiktok":{"description":"Handle or https:// link.","type":"string","maxLength":200},"snapchat":{"description":"Handle or https:// link.","type":"string","maxLength":200},"facebook":{"description":"Handle or https:// link.","type":"string","maxLength":200},"telegram":{"description":"Handle or https:// link.","type":"string","maxLength":200},"youtube":{"description":"Handle or https:// link.","type":"string","maxLength":200},"threads":{"description":"Handle or https:// link.","type":"string","maxLength":200},"website":{"description":"https:// link.","type":"string","maxLength":300}}}},"required":[]}}}}}},"/api/v1/brands/{id}/design":{"patch":{"operationId":"update_brand_design","summary":"Design a brand's emails","description":"Changes how the brand's emails look: background, text and button colors, button and image corners, alignment (right or center) and what sits at the top (logo, name or nothing). Every email the brand sends uses it. Send only what changes.","tags":["Brands"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"nameAr":{"type":"string"},"nameEn":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"postalAddress":{"type":["string","null"]},"replyToEmail":{"type":["string","null"]},"replyToWhatsapp":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"sharedSender":{"type":"string","description":"The ready-to-use sending address for brands without their own domain. New organizations send from the probation domain until they prove clean."},"page":{"type":"object","properties":{"enabled":{"default":true,"description":"false hides the page (it answers 404).","type":"boolean"},"headline":{"default":"","description":"The big line under the logo; the brand's Arabic name when empty.","type":"string","maxLength":80},"description":{"default":"","description":"One or two sentences: what subscribers get.","type":"string","maxLength":300},"accent":{"default":"teal","description":"Button and logo color: teal, emerald, sky, indigo, plum, rose, amber or ink.","type":"string","enum":["teal","emerald","sky","indigo","plum","rose","amber","ink"]},"customColor":{"default":"","description":"The brand's own color, e.g. #0F766E. Overrides accent when set; button text turns white or black to stay readable."},"theme":{"default":"light","description":"light: white; soft: tinted with the brand color; dark: near black.","type":"string","enum":["light","soft","dark"]},"background":{"default":"dots","description":"Behind the top of the page: plain, dots, grid, glow (a soft breathing light) or aurora (two slowly drifting lights).","type":"string","enum":["plain","dots","grid","glow","aurora"]},"collect":{"default":"both","description":"What the form asks for: email, phone (WhatsApp) or both.","type":"string","enum":["email","phone","both"]},"askName":{"default":true,"description":"Ask for a first name, used in {{first_name}}.","type":"boolean"},"buttonText":{"default":"","description":"The subscribe button; «اشترك» when empty.","type":"string","maxLength":30},"thanksText":{"default":"","description":"Shown after subscribing; a sensible Arabic default when empty.","type":"string","maxLength":200},"showCount":{"default":false,"description":"Show how many subscribers joined (only from 50).","type":"boolean"},"links":{"default":{"whatsapp":"","instagram":"","x":"","tiktok":"","snapchat":"","facebook":"","telegram":"","youtube":"","threads":"","website":""},"description":"Links shown under the form; empty ones are hidden.","type":"object","properties":{"whatsapp":{"default":"","description":"A WhatsApp number in international format, e.g. +966500000000.","type":"string","maxLength":20},"instagram":{"default":"","description":"Instagram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"x":{"default":"","description":"X (Twitter): a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"tiktok":{"default":"","description":"TikTok: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"snapchat":{"default":"","description":"Snapchat: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"facebook":{"default":"","description":"Facebook: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"telegram":{"default":"","description":"Telegram: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"youtube":{"default":"","description":"YouTube: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"threads":{"default":"","description":"Threads: a handle (with or without @) or a full https:// link.","type":"string","maxLength":200},"website":{"default":"","description":"The brand's website.","type":"string","maxLength":300}},"required":["whatsapp","instagram","x","tiktok","snapchat","facebook","telegram","youtube","threads","website"],"additionalProperties":false}},"required":["enabled","headline","description","accent","customColor","theme","background","collect","askName","buttonText","thanksText","showCount","links"],"additionalProperties":false,"description":"The brand's public signup page settings."},"design":{"type":"object","properties":{"background":{"default":"#FFFFFF","description":"The email's background, e.g. #FFFFFF."},"text":{"default":"#171717","description":"Headings and text, e.g. #171717."},"accent":{"default":"#0F766E","description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable."},"corners":{"default":"medium","type":"string","enum":["none","small","medium","large","full"],"description":"Button and image corners: none, small, medium, large or full (round buttons)."},"align":{"default":"right","type":"string","enum":["right","center"],"description":"right: aligned to the start, like a letter. center: centered, like an announcement."},"header":{"default":"logo","type":"string","enum":["logo","name","none"],"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing."}},"required":["background","text","accent","corners","align","header"],"additionalProperties":false,"description":"How the brand's emails look: colors, corners, alignment and header."},"pageUrl":{"type":"string","description":"Where the page lives: https://<slug>.ishtaqna.com."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","slug","nameAr","nameEn","logoUrl","postalAddress","replyToEmail","replyToWhatsapp","websiteUrl","sharedSender","page","design","pageUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"background":{"description":"The email's background, e.g. #FFFFFF.","type":"string","pattern":"^#[0-9a-f]{6}$"},"text":{"description":"Headings and text, e.g. #171717.","type":"string","pattern":"^#[0-9a-f]{6}$"},"accent":{"description":"Buttons and links, e.g. #0F766E. Button text turns white or black to stay readable.","type":"string","pattern":"^#[0-9a-f]{6}$"},"corners":{"description":"Button and image corners: none, small, medium, large or full (round buttons).","type":"string","enum":["none","small","medium","large","full"]},"align":{"description":"right: aligned to the start, like a letter. center: centered, like an announcement.","type":"string","enum":["right","center"]},"header":{"description":"What sits at the top: the logo (the name when there's no logo), the name, or nothing.","type":"string","enum":["logo","name","none"]}},"required":[]}}}}}},"/api/v1/contacts":{"get":{"operationId":"list_contacts","summary":"List contacts","description":"Lists the organization's contacts, newest first, 50 a page, with their tags and the status of each channel. Pass nextCursor back as cursor for the next page.","tags":["Contacts"],"parameters":[{"name":"search","in":"query","required":false,"schema":{"description":"Part of an email, phone number or name.","type":"string","maxLength":100}},{"name":"tag","in":"query","required":false,"schema":{"description":"Only contacts with this tag.","type":"string","maxLength":40}},{"name":"city","in":"query","required":false,"schema":{"description":"Only contacts in this city.","type":"string","maxLength":80}},{"name":"channel","in":"query","required":false,"schema":{"description":"Only contacts subscribed (active) on this channel.","type":"string","enum":["email","whatsapp"]}},{"name":"segment","in":"query","required":false,"schema":{"description":"Only contacts a saved segment picks.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"description":"Contacts per page, 50 by default, 100 at most.","type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"description":"nextCursor from the previous page.","type":"string","maxLength":200}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number"]}},"source":{"type":"string"},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","sms"]},"status":{"type":"string","enum":["active","pending","unsubscribed","bounced","complained","dormant","invalid"]},"consentBasis":{"type":["string","null"]},"consentAt":{"type":["string","null"]},"optedOutAt":{"type":["string","null"]}},"required":["channel","status","consentBasis","consentAt","optedOutAt"],"additionalProperties":false}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","email","phone","firstName","lastName","city","country","tags","fields","source","channels","createdAt","updatedAt"],"additionalProperties":false}},"total":{"type":"number"},"nextCursor":{"type":["string","null"]}},"required":["contacts","total","nextCursor"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"add_contact","summary":"Add a contact","description":"Adds one customer, or updates them if the email or phone is already a contact. Consent is recorded per channel; an unknown basis keeps the channel pending, so no marketing goes out until they agree. Works with signups-only keys.","tags":["Contacts"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number"]}},"source":{"type":"string"},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","sms"]},"status":{"type":"string","enum":["active","pending","unsubscribed","bounced","complained","dormant","invalid"]},"consentBasis":{"type":["string","null"]},"consentAt":{"type":["string","null"]},"optedOutAt":{"type":["string","null"]}},"required":["channel","status","consentBasis","consentAt","optedOutAt"],"additionalProperties":false}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","email","phone","firstName","lastName","city","country","tags","fields","source","channels","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"signups","role":"editor","hints":{"openWorld":false}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"description":"Email address. Typos like gmial.com are fixed; role and throwaway inboxes are refused.","type":"string","maxLength":254},"phone":{"description":"Phone number in any common format; stored in international format.","type":"string","maxLength":40},"firstName":{"description":"First name, used to greet them.","type":"string","maxLength":80},"lastName":{"description":"Last or family name.","type":"string","maxLength":80},"city":{"description":"City.","type":"string","maxLength":80},"tags":{"description":"Tags, as a list or comma-separated text.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"fields":{"description":"Values for the org's custom fields, by key.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"source":{"description":"Where they came from, e.g. website, qr, store. Default: api or dashboard.","type":"string","minLength":1,"maxLength":40},"consent":{"description":"How each channel's consent was given: signup_form, qr, checkout, in_store, whatsapp_optin or unknown (the default).","type":"object","properties":{"email":{"type":"string","enum":["signup_form","qr","checkout","in_store","whatsapp_optin","unknown"]},"whatsapp":{"type":"string","enum":["signup_form","qr","checkout","in_store","whatsapp_optin","unknown"]}}}},"required":[]}}}}}},"/api/v1/contacts/{id}":{"get":{"operationId":"get_contact","summary":"Get a contact","description":"Gets one contact by its ID, with its details, tags, custom field values and the consent record and status of each channel.","tags":["Contacts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number"]}},"source":{"type":"string"},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","sms"]},"status":{"type":"string","enum":["active","pending","unsubscribed","bounced","complained","dormant","invalid"]},"consentBasis":{"type":["string","null"]},"consentAt":{"type":["string","null"]},"optedOutAt":{"type":["string","null"]}},"required":["channel","status","consentBasis","consentAt","optedOutAt"],"additionalProperties":false}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","email","phone","firstName","lastName","city","country","tags","fields","source","channels","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"patch":{"operationId":"update_contact","summary":"Update a contact","description":"Changes a contact's names, city, tags or custom field values. Send only what changes: tags replace the contact's tags, fields only change the keys given.","tags":["Contacts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number"]}},"source":{"type":"string"},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","sms"]},"status":{"type":"string","enum":["active","pending","unsubscribed","bounced","complained","dormant","invalid"]},"consentBasis":{"type":["string","null"]},"consentAt":{"type":["string","null"]},"optedOutAt":{"type":["string","null"]}},"required":["channel","status","consentBasis","consentAt","optedOutAt"],"additionalProperties":false}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","email","phone","firstName","lastName","city","country","tags","fields","source","channels","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"description":"First name; null removes it.","anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"lastName":{"description":"Last name; null removes it.","anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"city":{"description":"City; null removes it.","anyOf":[{"type":"string","maxLength":80},{"type":"null"}]},"tags":{"description":"The contact's tags, replacing the current ones.","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"fields":{"description":"Custom field values by key; null removes one.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","null"]}}},"required":[]}}}}}},"/api/v1/contacts/{id}/channels/{channel}":{"patch":{"operationId":"update_contact_channel","summary":"Change a contact's channel status","description":"Unsubscribes a contact from a channel, or makes it active again. Making it active needs consent: true, your word that the person asked for it; bounced and complained channels never become active.","tags":["Contacts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}},{"name":"channel","in":"path","required":true,"schema":{"type":"string","enum":["email","whatsapp"],"description":"email or whatsapp."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","number"]}},"source":{"type":"string"},"channels":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","sms"]},"status":{"type":"string","enum":["active","pending","unsubscribed","bounced","complained","dormant","invalid"]},"consentBasis":{"type":["string","null"]},"consentAt":{"type":["string","null"]},"optedOutAt":{"type":["string","null"]}},"required":["channel","status","consentBasis","consentAt","optedOutAt"],"additionalProperties":false}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","email","phone","firstName","lastName","city","country","tags","fields","source","channels","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","unsubscribed"],"description":"active or unsubscribed."},"consent":{"description":"Required (true) to make a channel active: the person asked for it.","type":"boolean"}},"required":["status"]}}}}}},"/api/v1/contacts/tag":{"post":{"operationId":"tag_contacts","summary":"Tag contacts","description":"Adds tags to contacts, keeping the tags they already have. Segments can then pick them by tag.","tags":["Contacts"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"number"}},"required":["updated"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"minItems":1,"maxItems":1000,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"description":"Contact IDs, 1,000 at most."},"tags":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"description":"Tags to add, 10 at most."}},"required":["ids","tags"]}}}}}},"/api/v1/contacts/untag":{"post":{"operationId":"untag_contacts","summary":"Untag contacts","description":"Removes tags from contacts; their other tags stay as they are.","tags":["Contacts"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"number"}},"required":["updated"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"minItems":1,"maxItems":1000,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"description":"Contact IDs, 1,000 at most."},"tags":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"description":"Tags to remove, 10 at most."}},"required":["ids","tags"]}}}}}},"/api/v1/contacts/delete":{"post":{"operationId":"delete_contacts","summary":"Delete contacts","description":"Deletes contacts with their details and history. It can't be undone. Opted-out, bounced and complained addresses stay blocked, so they are never messaged again even if imported later.","tags":["Contacts"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"number"}},"required":["deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"minItems":1,"maxItems":1000,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"description":"Contact IDs, 1,000 at most."}},"required":["ids"]}}}}}},"/api/v1/contacts/tags":{"get":{"operationId":"list_contact_tags","summary":"List tags","description":"Lists the tags the organization's contacts have, most used first, with how many contacts have each (200 at most).","tags":["Contacts"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string"},"contacts":{"type":"number"}},"required":["tag","contacts"],"additionalProperties":false}}},"required":["tags"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/contacts/fields":{"get":{"operationId":"list_contact_fields","summary":"List custom fields","description":"Lists the organization's custom contact fields, like last visit or birthday, with their key and type.","tags":["Contacts"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","number","date"]},"createdAt":{"type":"string"}},"required":["key","label","type","createdAt"],"additionalProperties":false}}},"required":["fields"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_contact_field","summary":"Create a custom field","description":"Adds a custom field contacts can hold, like last_visit or birthday, 20 at most. Dates are stored as YYYY-MM-DD.","tags":["Contacts"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"type":{"type":"string","enum":["text","number","date"]},"createdAt":{"type":"string"}},"required":["key","label","type","createdAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$","description":"The field's key, e.g. last_visit."},"label":{"type":"string","minLength":1,"maxLength":40,"description":"The field's name as owners see it, e.g. آخر زيارة."},"type":{"type":"string","enum":["text","number","date"],"description":"text, number or date."}},"required":["key","label","type"]}}}}}},"/api/v1/contacts/fields/{key}":{"delete":{"operationId":"delete_contact_field","summary":"Delete a custom field","description":"Deletes a custom field definition. It can't be undone, though contacts keep their values hidden until a field with the same key is added again.","tags":["Contacts"],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$","description":"The field's key."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["key","deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"idempotent":true}}}},"/api/v1/contacts/import":{"post":{"operationId":"import_contacts","summary":"Import contacts","description":"Imports up to 1,000 rows per call. Phones are fixed to international format, email typos are corrected, and invalid, role, throwaway, duplicate and previously opted-out addresses are left out and counted. Send the next chunk with the importId of the first; 250,000 rows per import at most.","tags":["Imports"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"fileName":{"type":["string","null"]},"status":{"type":"string","enum":["processing","done","failed"]},"consent":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"totalRows":{"type":["number","null"]},"processed":{"type":"number"},"added":{"type":"number"},"updated":{"type":"number"},"leftOut":{"type":"number"},"corrected":{"type":"number"},"reasons":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}},"createdAt":{"type":"string"},"finishedAt":{"type":["string","null"]}},"required":["id","fileName","status","consent","totalRows","processed","added","updated","leftOut","corrected","reasons","createdAt","finishedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"minItems":1,"maxItems":1000,"type":"array","items":{"type":"object","properties":{"email":{"type":"string","maxLength":320},"phone":{"type":"string","maxLength":60},"fullName":{"type":"string","maxLength":200},"firstName":{"type":"string","maxLength":120},"lastName":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":120},"country":{"type":"string","maxLength":60},"tags":{"anyOf":[{"type":"string","maxLength":500},{"maxItems":50,"type":"array","items":{"type":"string","maxLength":60}}]},"fields":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string","maxLength":500}}}},"description":"The rows, 1,000 at most, with columns already mapped to fields."},"consent":{"type":"object","properties":{"email":{"type":"string","enum":["signup_form","qr","checkout","in_store","whatsapp_optin","unknown"]},"whatsapp":{"type":"string","enum":["signup_form","qr","checkout","in_store","whatsapp_optin","unknown"]}},"required":["email","whatsapp"],"description":"How these people agreed to hear from you, per channel. unknown keeps them pending until they agree."},"attest":{"type":"boolean","description":"Must be true unless both channels are unknown: these people agreed to receive your messages; the list wasn't bought or scraped."},"importId":{"description":"The importId the first chunk answered with, to add rows to the same import.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"fileName":{"description":"The uploaded file's name, shown in the import history.","type":"string","maxLength":200},"total":{"description":"With the first chunk: rows in the whole file, so the import turns done once all arrive.","type":"integer","minimum":1,"maximum":250000},"firstRowNumber":{"description":"Row number of rows[0] in the file, for the left-out report. Default: continues from the import's count.","type":"integer","minimum":1,"maximum":9007199254740991}},"required":["rows","consent","attest"]}}}}}},"/api/v1/contacts/imports/{id}":{"get":{"operationId":"get_import","summary":"Get an import","description":"An import's status and counts: rows processed, contacts added and updated, rows left out by reason, and typos corrected.","tags":["Imports"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"fileName":{"type":["string","null"]},"status":{"type":"string","enum":["processing","done","failed"]},"consent":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"totalRows":{"type":["number","null"]},"processed":{"type":"number"},"added":{"type":"number"},"updated":{"type":"number"},"leftOut":{"type":"number"},"corrected":{"type":"number"},"reasons":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}},"createdAt":{"type":"string"},"finishedAt":{"type":["string","null"]}},"required":["id","fileName","status","consent","totalRows","processed","added","updated","leftOut","corrected","reasons","createdAt","finishedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/contacts/imports":{"get":{"operationId":"list_imports","summary":"List imports","description":"The organization's latest imports, newest first, with their status and counts.","tags":["Imports"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":10,"description":"How many, 10 by default, 50 at most.","type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"imports":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"fileName":{"type":["string","null"]},"status":{"type":"string","enum":["processing","done","failed"]},"consent":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"totalRows":{"type":["number","null"]},"processed":{"type":"number"},"added":{"type":"number"},"updated":{"type":"number"},"leftOut":{"type":"number"},"corrected":{"type":"number"},"reasons":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"number"}},"createdAt":{"type":"string"},"finishedAt":{"type":["string","null"]}},"required":["id","fileName","status","consent","totalRows","processed","added","updated","leftOut","corrected","reasons","createdAt","finishedAt"],"additionalProperties":false}}},"required":["imports"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/contacts/imports/{id}/left-out":{"get":{"operationId":"list_left_out","summary":"List left-out rows","description":"The rows an import left out, with the reason and what the row had, in file order, 100 a page. Kept for 7 days after the import.","tags":["Imports"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}},{"name":"after","in":"query","required":false,"schema":{"description":"Return rows after this cursor (nextCursor of the previous page).","type":"integer","minimum":0,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"schema":{"default":100,"description":"Rows per page, 100 by default, 500 at most.","type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"rowNumber":{"type":"number"},"reason":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"name":{"type":["string","null"]}},"required":["rowNumber","reason","email","phone","name"],"additionalProperties":false}},"nextCursor":{"type":["number","null"]}},"required":["rows","nextCursor"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/segments/count":{"post":{"operationId":"count_segment","summary":"Count a segment","description":"Counts the contacts some conditions would pick, without saving anything. Try conditions here before create_segment.","tags":["Segments"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"number"},"summary":{"type":"array","items":{"type":"string"}}},"required":["contacts","summary"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"match":{"default":"all","description":"all: contacts meeting every condition. any: at least one.","type":"string","enum":["all","any"]},"conditions":{"minItems":1,"maxItems":10,"type":"array","items":{"anyOf":[{"type":"object","properties":{"field":{"type":"string","const":"tag"},"op":{"type":"string","enum":["has","has_not"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"city"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","minLength":1,"maxLength":80}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"country"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","pattern":"^[A-Z]{2}$"}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"source"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"added"},"op":{"type":"string","enum":["within_days","before_days"]},"value":{"type":"integer","minimum":1,"maximum":3650}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"channel"},"op":{"type":"string","enum":["active","not_active"]},"value":{"type":"string","enum":["email","whatsapp"]}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"orders"},"op":{"type":"string","enum":["bought_within_days","not_bought_within_days","count_at_least","spent_at_least"]},"value":{"type":"number","minimum":0,"maximum":10000000}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","pattern":"^field\\.[a-z][a-z0-9_]{0,39}$"},"op":{"type":"string","enum":["is","contains","is_set","not_set","before","since","at_least","less_than"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"type":"number"}]}},"required":["field","op"]}]},"description":"Up to 10 conditions. tag has/has_not; city/country/source is/is_not; added within_days/before_days (number); channel active/not_active (email|whatsapp); orders bought_within_days/not_bought_within_days (bought before, but not in the last N days)/count_at_least/spent_at_least (store currency), from a connected store; field.<key> is/contains/is_set/not_set/before/since (YYYY-MM-DD)/at_least/less_than."}},"required":["conditions"]}}}}}},"/api/v1/segments":{"get":{"operationId":"list_segments","summary":"List segments","description":"Lists the organization's saved segments, oldest first, with their conditions in plain Arabic and how many contacts each picks now.","tags":["Segments"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"segments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"match":{"type":"string","enum":["all","any"]},"conditions":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"summary":{"type":"array","items":{"type":"string"},"description":"Each condition in plain Arabic."},"contacts":{"type":"number","description":"How many contacts it picks now."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","match","conditions","summary","contacts","createdAt","updatedAt"],"additionalProperties":false}}},"required":["segments"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_segment","summary":"Create a segment","description":"Saves conditions that pick some contacts, like VIPs in Riyadh or customers not seen in 90 days. Contacts join and leave it as they meet the conditions.","tags":["Segments"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"match":{"type":"string","enum":["all","any"]},"conditions":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"summary":{"type":"array","items":{"type":"string"},"description":"Each condition in plain Arabic."},"contacts":{"type":"number","description":"How many contacts it picks now."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","match","conditions","summary","contacts","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60,"description":"The segment's name, e.g. عملاء الرياض المميزون."},"match":{"default":"all","description":"all: contacts meeting every condition. any: at least one.","type":"string","enum":["all","any"]},"conditions":{"minItems":1,"maxItems":10,"type":"array","items":{"anyOf":[{"type":"object","properties":{"field":{"type":"string","const":"tag"},"op":{"type":"string","enum":["has","has_not"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"city"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","minLength":1,"maxLength":80}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"country"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","pattern":"^[A-Z]{2}$"}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"source"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"added"},"op":{"type":"string","enum":["within_days","before_days"]},"value":{"type":"integer","minimum":1,"maximum":3650}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"channel"},"op":{"type":"string","enum":["active","not_active"]},"value":{"type":"string","enum":["email","whatsapp"]}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"orders"},"op":{"type":"string","enum":["bought_within_days","not_bought_within_days","count_at_least","spent_at_least"]},"value":{"type":"number","minimum":0,"maximum":10000000}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","pattern":"^field\\.[a-z][a-z0-9_]{0,39}$"},"op":{"type":"string","enum":["is","contains","is_set","not_set","before","since","at_least","less_than"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"type":"number"}]}},"required":["field","op"]}]},"description":"Up to 10 conditions. tag has/has_not; city/country/source is/is_not; added within_days/before_days (number); channel active/not_active (email|whatsapp); orders bought_within_days/not_bought_within_days (bought before, but not in the last N days)/count_at_least/spent_at_least (store currency), from a connected store; field.<key> is/contains/is_set/not_set/before/since (YYYY-MM-DD)/at_least/less_than."}},"required":["name","conditions"]}}}}}},"/api/v1/segments/{id}":{"get":{"operationId":"get_segment","summary":"Get a segment","description":"Gets one saved segment with its conditions and how many contacts it picks now.","tags":["Segments"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"match":{"type":"string","enum":["all","any"]},"conditions":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"summary":{"type":"array","items":{"type":"string"},"description":"Each condition in plain Arabic."},"contacts":{"type":"number","description":"How many contacts it picks now."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","match","conditions","summary","contacts","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"patch":{"operationId":"update_segment","summary":"Update a segment","description":"Renames a segment or replaces its conditions. Send only what changes.","tags":["Segments"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"match":{"type":"string","enum":["all","any"]},"conditions":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"summary":{"type":"array","items":{"type":"string"},"description":"Each condition in plain Arabic."},"contacts":{"type":"number","description":"How many contacts it picks now."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","match","conditions","summary","contacts","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"The segment's name.","type":"string","minLength":1,"maxLength":60},"match":{"description":"all or any.","type":"string","enum":["all","any"]},"conditions":{"description":"New conditions, replacing the old ones (same rules as create_segment).","minItems":1,"maxItems":10,"type":"array","items":{"anyOf":[{"type":"object","properties":{"field":{"type":"string","const":"tag"},"op":{"type":"string","enum":["has","has_not"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"city"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","minLength":1,"maxLength":80}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"country"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","pattern":"^[A-Z]{2}$"}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"source"},"op":{"type":"string","enum":["is","is_not"]},"value":{"type":"string","minLength":1,"maxLength":40}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"added"},"op":{"type":"string","enum":["within_days","before_days"]},"value":{"type":"integer","minimum":1,"maximum":3650}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"channel"},"op":{"type":"string","enum":["active","not_active"]},"value":{"type":"string","enum":["email","whatsapp"]}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","const":"orders"},"op":{"type":"string","enum":["bought_within_days","not_bought_within_days","count_at_least","spent_at_least"]},"value":{"type":"number","minimum":0,"maximum":10000000}},"required":["field","op","value"]},{"type":"object","properties":{"field":{"type":"string","pattern":"^field\\.[a-z][a-z0-9_]{0,39}$"},"op":{"type":"string","enum":["is","contains","is_set","not_set","before","since","at_least","less_than"]},"value":{"anyOf":[{"type":"string","maxLength":200},{"type":"number"}]}},"required":["field","op"]}]}}},"required":[]}}}}},"delete":{"operationId":"delete_segment","summary":"Delete a segment","description":"Deletes a saved segment. Its contacts stay as they are. It can't be undone.","tags":["Segments"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["id","deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"destructive":true,"idempotent":true}}}},"/api/v1/campaigns/templates":{"get":{"operationId":"list_campaign_templates","summary":"List campaign templates","description":"Lists the ready-made Arabic campaigns (win-back, new product, offer, Ramadan, Eid, welcome, birthday, review request, blank) a new campaign or automation can start from.","tags":["Campaigns"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"subject":{"type":"string"}},"required":["key","name","description","subject"],"additionalProperties":false}}},"required":["templates"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/campaigns/occasions":{"get":{"operationId":"list_occasions","summary":"List upcoming occasions","description":"Lists the occasions in the next days that shops in the organization's country build campaigns around (Ramadan, the two Eids, national days, White Friday, salary day), with the days left, the template to start from and a tip in Arabic. remind is true when it's time to prepare. Hijri dates follow the Umm al-Qura calendar and can move a day.","tags":["Campaigns"],"parameters":[{"name":"days","in":"query","required":false,"schema":{"default":60,"description":"How far ahead to look, 60 days by default.","type":"integer","minimum":1,"maximum":120}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"today":{"type":"string","description":"Today in the organization's time zone, YYYY-MM-DD."},"occasions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"id":{"type":"string"},"nameAr":{"type":"string"},"date":{"type":"string"},"daysLeft":{"type":"number"},"template":{"type":"string","description":"A key for create_campaign's template."},"remind":{"type":"boolean"},"approximate":{"type":"boolean","description":"A Hijri date: the actual day depends on the moon sighting."},"tipAr":{"type":"string"}},"required":["key","id","nameAr","date","daysLeft","template","remind","approximate","tipAr"],"additionalProperties":false}}},"required":["today","occasions"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/campaigns":{"get":{"operationId":"list_campaigns","summary":"List campaigns","description":"Lists the organization's campaigns, newest first, with status and headline numbers (recipients, sent, opened, clicked).","tags":["Campaigns"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"default":50,"description":"How many, 50 by default.","type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"campaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"sent":{"type":"number"},"opened":{"type":"number"},"clicked":{"type":"number"}},"required":["id","name","kind","template","brandId","subject","previewText","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt","sent","opened","clicked"],"additionalProperties":false}}},"required":["campaigns"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_campaign","summary":"Create a campaign","description":"Creates a draft, from a template or blank. Nothing is sent. kind permission_request makes the one-time email that asks pending contacts for consent.","tags":["Campaigns"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"Internal name. Default: the template's name.","type":"string","minLength":1,"maxLength":120},"template":{"description":"A template key from list_campaign_templates. Default: blank.","type":"string"},"kind":{"default":"campaign","description":"campaign, or permission_request for pending contacts.","type":"string","enum":["campaign","permission_request"]},"brandId":{"description":"The sending brand. Default: the organization's first brand.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"channel":{"description":"email (default) or whatsapp.","type":"string","enum":["email","whatsapp"]},"waTemplateId":{"description":"whatsapp: an approved template (list_whatsapp_templates).","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":[]}}}}}},"/api/v1/campaigns/{id}":{"get":{"operationId":"get_campaign","summary":"Get a campaign","description":"Gets a campaign with its content, who it would go to right now, its sender address and anything that blocks sending it.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"audience":{"type":"number","description":"Contacts it would go to right now."},"sender":{"type":"string","description":"The From address."},"problems":{"type":"array","items":{"type":"string"},"description":"What blocks sending, in Arabic. Empty means ready."},"provider":{"description":"outbox (development), ses, or null when sending is off.","type":["string","null"]},"review":{"type":"object","properties":{"status":{"type":"string","enum":["none","pending","passed","held","approved","rejected"]},"reasons":{"type":"array","items":{"type":"string"},"description":"Why the content is held for review, in Arabic."},"tips":{"type":"array","items":{"type":"string"},"description":"Advice for better inbox placement, in Arabic."}},"required":["status","reasons","tips"],"additionalProperties":false,"description":"The content review that runs before every send."},"steps":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"step":{"type":"number"},"size":{"type":"number"},"releaseAt":{"type":"string"}},"required":["step","size","releaseAt"],"additionalProperties":false}},{"type":"null"}],"description":"First-send steps for contacts never emailed before; null when the campaign went out in one step."},"canResume":{"type":"boolean","description":"Whether resume_campaign is allowed now. Pauses that protect sending reputation need our team."},"timezone":{"type":"string","description":"The organization's IANA time zone, for showing times."},"whatsapp":{"anyOf":[{"type":"object","properties":{"templateName":{"type":["string","null"]},"templateStatus":{"type":["string","null"]},"preview":{"description":"The template as a sample customer reads it.","type":["string","null"]},"buttonText":{"type":["string","null"]},"recipients":{"type":"number","description":"Contacts it would go to on WhatsApp."},"emailFallback":{"type":"number","description":"Contacts without WhatsApp who would get the email instead."},"estimate":{"type":"object","properties":{"usd":{"type":"number","description":"Estimated total Meta charges, paid by the owner to Meta (no markup)."},"byCountry":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"recipients":{"type":"number"},"ratePerMessage":{"type":"number"}},"required":["country","recipients","ratePerMessage"],"additionalProperties":false}},"unknown":{"type":"number","description":"Recipients in countries without a known rate."},"ratesAsOf":{"type":"string"}},"required":["usd","byCountry","unknown","ratesAsOf"],"additionalProperties":false,"description":"From Meta's published rate card."}},"required":["templateName","templateStatus","preview","buttonText","recipients","emailFallback","estimate"],"additionalProperties":false},{"type":"null"}],"description":"WhatsApp campaigns only."}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt","audience","sender","problems","provider","review","steps","canResume","timezone","whatsapp"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"patch":{"operationId":"update_campaign","summary":"Update a draft campaign","description":"Changes a draft's name, subject, preview text, blocks, segment or brand. Send only what changes. With revision, the change is refused if someone else saved in between.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"Internal name.","type":"string","minLength":1,"maxLength":120},"subject":{"description":"Subject line. Merge tags like {{first_name|عميلنا العزيز}} work.","type":"string","maxLength":200},"previewText":{"description":"Text inbox apps show after the subject.","type":"string","maxLength":300},"content":{"description":"The blocks: heading (level 1-3), text (**bold** and line breaks), list (bullet or number items), quote, button (solid or outline), image (full, wide or half width), divider. Most take align: right, center or left; without it the brand's email design decides.","type":"object","properties":{"blocks":{"maxItems":40,"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"heading"},"text":{"type":"string","maxLength":200},"level":{"anyOf":[{"type":"number","const":1},{"type":"number","const":2},{"type":"number","const":3}]},"align":{"type":"string","enum":["right","center","left"]}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","const":"text"},"text":{"type":"string","maxLength":5000},"align":{"type":"string","enum":["right","center","left"]}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","const":"list"},"style":{"type":"string","enum":["bullet","number"]},"items":{"minItems":1,"maxItems":30,"type":"array","items":{"type":"string","maxLength":500}},"align":{"type":"string","enum":["right","center","left"]}},"required":["type","style","items"]},{"type":"object","properties":{"type":{"type":"string","const":"quote"},"text":{"type":"string","maxLength":1000},"align":{"type":"string","enum":["right","center","left"]}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","const":"button"},"text":{"type":"string","maxLength":60},"url":{"type":"string","maxLength":2000},"style":{"type":"string","enum":["solid","outline"]},"align":{"type":"string","enum":["right","center","left"]}},"required":["type","text","url"]},{"type":"object","properties":{"type":{"type":"string","const":"image"},"url":{"type":"string","maxLength":2000},"alt":{"default":"","type":"string","maxLength":200},"href":{"type":"string","maxLength":2000},"width":{"type":"string","enum":["full","wide","half"]},"align":{"type":"string","enum":["right","center","left"]}},"required":["type","url"]},{"type":"object","properties":{"type":{"type":"string","const":"divider"}},"required":["type"]}]}}},"required":["blocks"]},"segmentId":{"description":"A segment to send to, or null for every subscribed contact.","anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"brandId":{"description":"The sending brand.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"waTemplateId":{"description":"whatsapp: the approved template to send.","anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"fallbackEmail":{"description":"whatsapp: also email contacts who have no WhatsApp subscription (uses the subject and blocks).","type":"boolean"},"revision":{"description":"The revision you started from (get_campaign); refused with revision_conflict if it changed.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":[]}}}}},"delete":{"operationId":"delete_campaign","summary":"Delete a draft campaign","description":"Deletes a draft. It can't be undone. Campaigns that were sent can't be deleted, so their reports stay.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean","const":true}},"required":["id","deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"destructive":true,"idempotent":true}}}},"/api/v1/campaigns/{id}/duplicate":{"post":{"operationId":"duplicate_campaign","summary":"Duplicate a campaign","description":"Copies a campaign's subject, preview text, blocks, segment and brand into a new draft.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/campaigns/{id}/preview":{"get":{"operationId":"preview_campaign","summary":"Preview a campaign","description":"Renders a campaign as one contact would get it (or a sample reader), with merge tags filled in. Nothing is sent and links aren't tracked.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}},{"name":"contactId","in":"query","required":false,"schema":{"description":"A contact to preview as. Default: a sample reader.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"subject":{"type":"string"},"html":{"type":"string"},"text":{"type":"string"},"from":{"type":"string"}},"required":["subject","html","text","from"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/campaigns/{id}/test":{"post":{"operationId":"send_test_email","summary":"Send a test email","description":"Sends the campaign as saved, subject prefixed with [تجربة], to one address: yours by default. It counts toward the plan's emails. It can't be undone.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string"},"messageId":{"type":"number"}},"required":["to","messageId"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"destructive":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"description":"The address to send the test to. Default: the signed-in user's email (required for API keys).","type":"string","format":"email","pattern":"^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":[]}}}}}},"/api/v1/campaigns/{id}/send":{"post":{"operationId":"send_campaign","summary":"Send a campaign now","description":"Sends a draft now to every contact subscribed by email (or its segment's), one email each. It can't be undone: emails can't be recalled. Sending a campaign that is already sending or sent answers conflict, so retrying never sends twice. The content is reviewed first (a hold pauses it with pause_reason content_review). Contacts never emailed before go out in steps (2%, then 5%, then the rest, 30 minutes apart) while bounces and complaints stay low. Contacts who ignored 6 campaigns over 180 days get a 'still want our emails?' message instead.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"recipients":{"type":"number"},"steps":{"type":"array","items":{"type":"number"},"description":"Recipients per first-send step, the first step first. One number means one step."},"lastChance":{"type":"number","description":"Inactive contacts who get the 'still want our emails?' message instead."},"madeDormant":{"type":"number","description":"Contacts who never answered that message and stop getting email."}},"required":["id","status","recipients","steps","lastChance","madeDormant"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/campaigns/{id}/schedule":{"post":{"operationId":"schedule_campaign","summary":"Schedule a campaign","description":"Schedules a draft to send by itself at a time, between 5 minutes and 60 days from now, after the same checks as send_campaign. At that time it is sent exactly as send_campaign would, with the scheduler's permissions checked again. Once it goes out it can't be undone; until then unschedule_campaign cancels it. Give at with a time zone, or use get_best_send_time for when this organization's customers open most.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$","description":"When to send, ISO 8601 with an offset, e.g. 2026-11-12T20:00:00+03:00."}},"required":["at"]}}}}}},"/api/v1/campaigns/{id}/unschedule":{"post":{"operationId":"unschedule_campaign","summary":"Unschedule a campaign","description":"Cancels a scheduled send: the campaign goes back to being a draft you can edit, send or schedule again.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/campaigns/best-time":{"get":{"operationId":"get_best_send_time","summary":"Get the best time to send","description":"When this organization's customers open most, from people's opens and WhatsApp reads in the last 90 days, by weekday and hour in the organization's time zone. best is null until there are 30 opens to go on.","tags":["Campaigns"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"timezone":{"type":"string"},"opens":{"type":"number","description":"Opens the answer is based on."},"best":{"anyOf":[{"type":"object","properties":{"weekday":{"type":"number","description":"0 Sunday … 6 Saturday."},"weekdayAr":{"type":"string"},"hour":{"type":"number"}},"required":["weekday","weekdayAr","hour"],"additionalProperties":false},{"type":"null"}]},"heatmap":{"type":"array","items":{"type":"array","items":{"type":"number"}},"description":"7 rows (Sunday first) of 24 hourly counts."}},"required":["timezone","opens","best","heatmap"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/campaigns/{id}/pause":{"post":{"operationId":"pause_campaign","summary":"Pause a campaign","description":"Stops a campaign that is sending. Emails already sent stay sent; the rest wait for resume_campaign.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/campaigns/{id}/resume":{"post":{"operationId":"resume_campaign","summary":"Resume a paused campaign","description":"Sends the rest of a paused campaign. It can't be undone: emails can't be recalled once they go out. Pauses for content review or high bounce/complaint rates can't be resumed this way; they answer conflict.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/campaigns/{id}/cancel":{"post":{"operationId":"cancel_campaign","summary":"Cancel the rest of a campaign","description":"Stops a sending or paused campaign for good: emails not sent yet are dropped. It can't be undone; emails already sent stay sent.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["campaign","permission_request","automation"],"description":"automation: the message of an automation (see list_automations)."},"template":{"type":["string","null"]},"brandId":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"content":{"type":"object","properties":{"blocks":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"required":["blocks"],"additionalProperties":false},"segmentId":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"],"description":"email, or whatsapp (an approved template)."},"waTemplateId":{"description":"whatsapp: the approved template it sends.","type":["string","null"]},"fallbackEmail":{"type":"boolean","description":"whatsapp: email the content to contacts who have no WhatsApp subscription."},"status":{"type":"string","enum":["draft","scheduled","sending","paused","sent","canceled"],"description":"scheduled: it goes out by itself at scheduledAt."},"pauseReason":{"type":["string","null"]},"scheduledAt":{"description":"When a scheduled campaign goes out.","type":["string","null"]},"scheduleError":{"description":"Why a scheduled send didn't go out, in Arabic; it's a draft again.","type":["string","null"]},"revision":{"type":"number"},"recipients":{"type":"number"},"startedAt":{"type":["string","null"]},"finishedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","kind","template","brandId","subject","previewText","content","segmentId","channel","waTemplateId","fallbackEmail","status","pauseReason","scheduledAt","scheduleError","revision","recipients","startedAt","finishedAt","createdAt","updatedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/campaigns/{id}/tips":{"get":{"operationId":"get_campaign_tips","summary":"Get deliverability tips for a campaign","description":"Checks a campaign's content before sending: what would hold it for review (phishing-like requests, prohibited offers, risky links) and tips that help it reach the inbox, in Arabic. Nothing is sent.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"flags":{"type":"array","items":{"type":"string"},"description":"Problems that would hold the campaign for review, in Arabic."},"tips":{"type":"array","items":{"type":"string"},"description":"Advice for better inbox placement, in Arabic. Never blocks sending."}},"required":["flags","tips"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/campaigns/{id}/checklist":{"get":{"operationId":"get_campaign_checklist","summary":"Check a campaign before sending","description":"The review before sending a draft, as a checklist: what blocks sending (fail), what is worth fixing (warn: the preview text, no test sent since the last change, content our team would review, inbox tips) and what already passes (subject length, unsubscribe link, size, postal address, sender). Each item says where to fix it. Nothing is sent.","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ready":{"type":"boolean","description":"No failing item: the draft can be sent or scheduled."},"audience":{"type":"number","description":"Who it would reach now."},"sizeKb":{"description":"The email's size in KB, out of 100.","type":["number","null"]},"items":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"status":{"type":"string","enum":["fail","warn","pass"],"description":"fail blocks sending; warn is worth fixing; pass is already fine."},"text":{"type":"string","description":"What it checks, in Arabic."},"detail":{"description":"One line of explanation or advice, in Arabic.","type":["string","null"]},"fix":{"anyOf":[{"type":"string","enum":["write","audience","brand","whatsapp","test","plan"]},{"type":"null"}],"description":"Where to fix it: the content, the audience, the brand settings, WhatsApp, a test send, or the plan."}},"required":["key","status","text","detail","fix"],"additionalProperties":false},"description":"Failing items first, then warnings, then what passes."}},"required":["ready","audience","sizeKb","items"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/campaigns/{id}/report":{"get":{"operationId":"get_campaign_report","summary":"Get a campaign's report","description":"Results of a campaign: recipients, sent, delivered, waiting (later steps or tomorrow's Gmail allowance), failed, skipped, opens (people only; Apple Mail Privacy Protection and scanners counted apart), clicks, bounces, complaints, unsubscribes, consent confirmations, rates, clicks per link, and, with a connected store, the paid orders it brought (bought within 7 days of clicking, or 3 days of opening).","tags":["Campaigns"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"recipients":{"type":"number"},"sent":{"type":"number"},"delivered":{"type":"number","description":"Confirmed by the receiving server (only when the provider reports deliveries)."},"queued":{"type":"number"},"held":{"type":"number","description":"Waiting for a later first-send step or tomorrow's Gmail allowance."},"nextAt":{"description":"When the next held messages are due, if any.","type":["string","null"]},"failed":{"type":"number"},"skipped":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded)."},"machineOpened":{"type":"number","description":"Opens by Apple Mail Privacy Protection or security scanners only."},"clicked":{"type":"number"},"bounced":{"type":"number","description":"Hard bounces: the address doesn't exist. Never emailed again."},"complained":{"type":"number","description":"Marked as spam by the recipient."},"unsubscribed":{"type":"number"},"confirmed":{"type":"number"},"lastChance":{"type":"number","description":"Got the 'still want our emails?' message instead of the campaign."},"read":{"type":"number","description":"WhatsApp messages read (blue ticks)."},"replied":{"type":"number","description":"WhatsApp messages that got a reply."},"whatsappSent":{"type":"number","description":"Sent on WhatsApp (the rest went by email)."},"estimatedCostUsd":{"type":"number","description":"Estimated Meta charges for the WhatsApp messages sent, paid by the owner to Meta."},"openRate":{"type":"number","description":"Human opens ÷ sent; still an estimate (some inboxes load images automatically)."},"clickRate":{"type":"number","description":"Clicks ÷ sent."},"bounceRate":{"type":"number","description":"Hard bounces ÷ sent. Campaigns pause above 2.5%."},"complaintRate":{"type":"number","description":"Complaints ÷ sent. Campaigns pause above 0.08%."},"links":{"type":"array","items":{"type":"object","properties":{"index":{"type":"number"},"url":{"type":"string"},"clicks":{"type":"number"},"people":{"type":"number"}},"required":["index","url","clicks","people"],"additionalProperties":false}},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number","description":"Paid orders' total, in the store's currency."},"currency":{"type":"string"},"fromClicks":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"}},"required":["orders","total"],"additionalProperties":false,"description":"Bought within 7 days of clicking a link in this campaign."},"fromOpens":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"}},"required":["orders","total"],"additionalProperties":false,"description":"Bought within 3 days of opening or reading it, without clicking."}},"required":["orders","total","currency","fromClicks","fromOpens"],"additionalProperties":false},{"type":"null"}],"description":"Orders this campaign brought; null when no store is connected."}},"required":["status","recipients","sent","delivered","queued","held","nextAt","failed","skipped","opened","machineOpened","clicked","bounced","complained","unsubscribed","confirmed","lastChance","read","replied","whatsappSent","estimatedCostUsd","openRate","clickRate","bounceRate","complaintRate","links","revenue"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/automations":{"get":{"operationId":"list_automations","summary":"List automations","description":"Lists the four automations an organization can run (welcome, birthday, win_back, post_purchase), which exist, their state, what they sent, opened, clicked and the revenue they brought, and what stops a draft from starting.","tags":["Automations"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"automations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"state":{"type":"string","enum":["draft","running","paused","in_review","held","stopped"],"description":"running; in_review: the message is being reviewed; held: our team is reviewing it; stopped: paused by the sending health checks (see pauseReason)."},"pauseReason":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"]},"campaignId":{"type":"string","description":"Its message: edit it with update_campaign while the automation is a draft or paused."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"startedAt":{"type":["string","null"]},"lastRunAt":{"type":["string","null"]},"stats":{"type":"object","properties":{"entered":{"type":"number","description":"People who entered it (once per occurrence)."},"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["entered","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["orders","total","currency"],"additionalProperties":false},{"type":"null"}],"description":"Paid orders it brought (7 days after a click, 3 after an open); null without a store."},"problems":{"type":"array","items":{"type":"string"},"description":"What stops it from starting, in Arabic. Empty when it can start."}},"required":["id","type","name","status","state","pauseReason","channel","campaignId","settings","startedAt","lastRunAt","stats","revenue","problems"],"additionalProperties":false}},"types":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"nameAr":{"type":"string"},"descriptionAr":{"type":"string"},"needsStore":{"type":"boolean"},"created":{"type":"boolean"}},"required":["type","nameAr","descriptionAr","needsStore","created"],"additionalProperties":false}}},"required":["automations","types"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_automation","summary":"Create an automation","description":"Creates one of the four automations as a draft, with a ready Arabic message from its template; nothing is sent until start_automation. channel whatsapp needs an approved WhatsApp template (waTemplateId); fallbackEmail also emails those without WhatsApp. Edit the message with update_campaign on its campaignId.","tags":["Automations"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"state":{"type":"string","enum":["draft","running","paused","in_review","held","stopped"],"description":"running; in_review: the message is being reviewed; held: our team is reviewing it; stopped: paused by the sending health checks (see pauseReason)."},"pauseReason":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"]},"campaignId":{"type":"string","description":"Its message: edit it with update_campaign while the automation is a draft or paused."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"startedAt":{"type":["string","null"]},"lastRunAt":{"type":["string","null"]},"stats":{"type":"object","properties":{"entered":{"type":"number","description":"People who entered it (once per occurrence)."},"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["entered","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["orders","total","currency"],"additionalProperties":false},{"type":"null"}],"description":"Paid orders it brought (7 days after a click, 3 after an open); null without a store."},"problems":{"type":"array","items":{"type":"string"},"description":"What stops it from starting, in Arabic. Empty when it can start."}},"required":["id","type","name","status","state","pauseReason","channel","campaignId","settings","startedAt","lastRunAt","stats","revenue","problems"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"channel":{"default":"email","description":"email (default) or whatsapp.","type":"string","enum":["email","whatsapp"]},"waTemplateId":{"description":"For channel whatsapp: an approved WhatsApp template.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"fallbackEmail":{"description":"For channel whatsapp: email contacts who aren't on WhatsApp.","type":"boolean"},"brandId":{"description":"The brand it sends as; the first brand by default.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"settings":{"description":"Per type: welcome {delayMinutes}; birthday {field}; win_back {days, basis orders|field, field}; post_purchase {days}; any {segmentId}.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["type"]}}}}}},"/api/v1/automations/{id}":{"get":{"operationId":"get_automation","summary":"Get an automation","description":"Gets one automation with its numbers, what stops it from starting, and the latest 20 people who entered it with what happened to their message.","tags":["Automations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"state":{"type":"string","enum":["draft","running","paused","in_review","held","stopped"],"description":"running; in_review: the message is being reviewed; held: our team is reviewing it; stopped: paused by the sending health checks (see pauseReason)."},"pauseReason":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"]},"campaignId":{"type":"string","description":"Its message: edit it with update_campaign while the automation is a draft or paused."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"startedAt":{"type":["string","null"]},"lastRunAt":{"type":["string","null"]},"stats":{"type":"object","properties":{"entered":{"type":"number","description":"People who entered it (once per occurrence)."},"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["entered","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["orders","total","currency"],"additionalProperties":false},{"type":"null"}],"description":"Paid orders it brought (7 days after a click, 3 after an open); null without a store."},"problems":{"type":"array","items":{"type":"string"},"description":"What stops it from starting, in Arabic. Empty when it can start."},"recent":{"type":"array","items":{"type":"object","properties":{"contactId":{"type":"string"},"name":{"type":"string"},"occurrence":{"type":"string"},"at":{"type":"string"},"messageStatus":{"type":["string","null"]}},"required":["contactId","name","occurrence","at","messageStatus"],"additionalProperties":false}}},"required":["id","type","name","status","state","pauseReason","channel","campaignId","settings","startedAt","lastRunAt","stats","revenue","problems","recent"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"patch":{"operationId":"update_automation","summary":"Change an automation's settings","description":"Changes when an automation sends (its settings) or its name. Send only what changes; settings are merged with the current ones. Its message is edited with update_campaign while it's a draft or paused.","tags":["Automations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"state":{"type":"string","enum":["draft","running","paused","in_review","held","stopped"],"description":"running; in_review: the message is being reviewed; held: our team is reviewing it; stopped: paused by the sending health checks (see pauseReason)."},"pauseReason":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"]},"campaignId":{"type":"string","description":"Its message: edit it with update_campaign while the automation is a draft or paused."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"startedAt":{"type":["string","null"]},"lastRunAt":{"type":["string","null"]},"stats":{"type":"object","properties":{"entered":{"type":"number","description":"People who entered it (once per occurrence)."},"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["entered","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["orders","total","currency"],"additionalProperties":false},{"type":"null"}],"description":"Paid orders it brought (7 days after a click, 3 after an open); null without a store."},"problems":{"type":"array","items":{"type":"string"},"description":"What stops it from starting, in Arabic. Empty when it can start."}},"required":["id","type","name","status","state","pauseReason","channel","campaignId","settings","startedAt","lastRunAt","stats","revenue","problems"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"A name for the dashboard.","type":"string","minLength":1,"maxLength":120},"settings":{"description":"The settings to change, e.g. { days: 90 } for win_back.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":[]}}}}},"delete":{"operationId":"delete_automation","summary":"Delete an automation","description":"Deletes an automation that never sent anything, with its message. It can't be undone. One that sent stays, so its report and revenue stay: pause it instead.","tags":["Automations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"idempotent":true}}}},"/api/v1/automations/{id}/start":{"post":{"operationId":"start_automation","summary":"Start an automation","description":"Turns an automation on: its message is reviewed, then everyone who qualifies from now on gets it automatically, once per occurrence. Messages it sends can't be undone. People are only counted from the moment it starts (a welcome greets new contacts, not old ones); birthday, win_back and post_purchase send between 10:00 and 20:00 in the organization's time zone, and nobody gets more than one marketing message in 20 hours.","tags":["Automations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"state":{"type":"string","enum":["draft","running","paused","in_review","held","stopped"],"description":"running; in_review: the message is being reviewed; held: our team is reviewing it; stopped: paused by the sending health checks (see pauseReason)."},"pauseReason":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"]},"campaignId":{"type":"string","description":"Its message: edit it with update_campaign while the automation is a draft or paused."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"startedAt":{"type":["string","null"]},"lastRunAt":{"type":["string","null"]},"stats":{"type":"object","properties":{"entered":{"type":"number","description":"People who entered it (once per occurrence)."},"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["entered","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["orders","total","currency"],"additionalProperties":false},{"type":"null"}],"description":"Paid orders it brought (7 days after a click, 3 after an open); null without a store."},"problems":{"type":"array","items":{"type":"string"},"description":"What stops it from starting, in Arabic. Empty when it can start."}},"required":["id","type","name","status","state","pauseReason","channel","campaignId","settings","startedAt","lastRunAt","stats","revenue","problems"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/automations/{id}/pause":{"post":{"operationId":"pause_automation","summary":"Pause an automation","description":"Turns an automation off: nobody new enters it, and its messages not sent yet are dropped (they are time-bound, like a welcome or a birthday). While paused, its message can be edited; start_automation turns it back on.","tags":["Automations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["welcome","birthday","win_back","post_purchase"],"description":"welcome, birthday, win_back or post_purchase."},"name":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused"]},"state":{"type":"string","enum":["draft","running","paused","in_review","held","stopped"],"description":"running; in_review: the message is being reviewed; held: our team is reviewing it; stopped: paused by the sending health checks (see pauseReason)."},"pauseReason":{"type":["string","null"]},"channel":{"type":"string","enum":["email","whatsapp"]},"campaignId":{"type":"string","description":"Its message: edit it with update_campaign while the automation is a draft or paused."},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"startedAt":{"type":["string","null"]},"lastRunAt":{"type":["string","null"]},"stats":{"type":"object","properties":{"entered":{"type":"number","description":"People who entered it (once per occurrence)."},"sent":{"type":"number"},"opened":{"type":"number","description":"People who opened (machine opens excluded) or read on WhatsApp."},"clicked":{"type":"number"},"unsubscribed":{"type":"number"}},"required":["entered","sent","opened","clicked","unsubscribed"],"additionalProperties":false},"revenue":{"anyOf":[{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"}},"required":["orders","total","currency"],"additionalProperties":false},{"type":"null"}],"description":"Paid orders it brought (7 days after a click, 3 after an open); null without a store."},"problems":{"type":"array","items":{"type":"string"},"description":"What stops it from starting, in Arabic. Empty when it can start."}},"required":["id","type","name","status","state","pauseReason","channel","campaignId","settings","startedAt","lastRunAt","stats","revenue","problems"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/whatsapp":{"get":{"operationId":"get_whatsapp","summary":"Get the WhatsApp connection","description":"Shows the connected WhatsApp number (quality rating, Meta's daily messaging limit), which way of connecting is available here, and the quiet hours for marketing messages.","tags":["WhatsApp"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"anyOf":[{"type":"string","enum":["outbox","meta"]},{"type":"null"}],"description":"outbox: local test numbers. meta: Embedded Signup. null: WhatsApp isn't configured here."},"account":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string","enum":["meta","outbox"],"description":"meta: the Cloud API. outbox: a local test number (development)."},"displayPhone":{"type":"string"},"verifiedName":{"type":["string","null"]},"status":{"type":"string","enum":["connected","restricted","disconnected"]},"qualityRating":{"type":"string","enum":["GREEN","YELLOW","RED","UNKNOWN"],"description":"Meta's quality rating. RED pauses WhatsApp campaigns."},"messagingLimit":{"type":"string","description":"Meta's tier, e.g. TIER_250: unique recipients per moving 24 hours."},"dailyLimit":{"description":"The tier as a number; null means unlimited.","type":["number","null"]},"coexistence":{"type":"boolean","description":"The number is also used in the WhatsApp Business app."},"connectedAt":{"type":"string"},"syncedAt":{"type":["string","null"]}},"required":["id","provider","displayPhone","verifiedName","status","qualityRating","messagingLimit","dailyLimit","coexistence","connectedAt","syncedAt"],"additionalProperties":false},{"type":"null"}]},"embeddedSignup":{"anyOf":[{"type":"object","properties":{"appId":{"type":"string"},"configId":{"type":"string"},"graphVersion":{"type":"string"}},"required":["appId","configId","graphVersion"],"additionalProperties":false},{"type":"null"}],"description":"Public ids for Meta's Embedded Signup button."},"quietHours":{"type":"object","properties":{"start":{"type":"integer","minimum":0,"maximum":23,"description":"Hour (0–23, recipient's local time) when marketing stops."},"end":{"type":"integer","minimum":0,"maximum":23,"description":"Hour when marketing may start again."}},"required":["start","end"],"additionalProperties":false},"timezone":{"type":"string","description":"The organization's IANA time zone, for showing times."}},"required":["mode","account","embeddedSignup","quietHours","timezone"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/whatsapp/connect":{"post":{"operationId":"connect_whatsapp","summary":"Connect a WhatsApp number","description":"Connects the business's own WhatsApp number. In production use method embedded_signup with the code, WABA id and phone number id from Meta's Embedded Signup, or manual with an existing token. Locally, method test connects a simulated number.","tags":["WhatsApp"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string","enum":["meta","outbox"],"description":"meta: the Cloud API. outbox: a local test number (development)."},"displayPhone":{"type":"string"},"verifiedName":{"type":["string","null"]},"status":{"type":"string","enum":["connected","restricted","disconnected"]},"qualityRating":{"type":"string","enum":["GREEN","YELLOW","RED","UNKNOWN"],"description":"Meta's quality rating. RED pauses WhatsApp campaigns."},"messagingLimit":{"type":"string","description":"Meta's tier, e.g. TIER_250: unique recipients per moving 24 hours."},"dailyLimit":{"description":"The tier as a number; null means unlimited.","type":["number","null"]},"coexistence":{"type":"boolean","description":"The number is also used in the WhatsApp Business app."},"connectedAt":{"type":"string"},"syncedAt":{"type":["string","null"]}},"required":["id","provider","displayPhone","verifiedName","status","qualityRating","messagingLimit","dailyLimit","coexistence","connectedAt","syncedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"owner","hints":{"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"type":"string","enum":["test","embedded_signup","manual"],"description":"How to connect."},"phone":{"description":"test only: the number to simulate, in international format.","type":"string","pattern":"^\\+[1-9][0-9]{7,14}$"},"code":{"description":"embedded_signup: the code from FB.login (valid for 30 seconds).","type":"string","maxLength":2000},"wabaId":{"description":"The WhatsApp Business Account id.","type":"string","pattern":"^\\d{5,30}$"},"phoneNumberId":{"description":"The phone number id.","type":"string","pattern":"^\\d{5,30}$"},"accessToken":{"description":"manual: a business or system-user token with WhatsApp permissions. Stored encrypted.","type":"string","minLength":20,"maxLength":1000},"coexistence":{"description":"The number stays on the WhatsApp Business app too (skips registration).","type":"boolean"}},"required":["method"]}}}}}},"/api/v1/whatsapp/disconnect":{"post":{"operationId":"disconnect_whatsapp","summary":"Disconnect WhatsApp","description":"Disconnects the WhatsApp number from Ishtaqna and forgets its token; WhatsApp campaigns that are sending pause. It can't be undone: connecting again means submitting the templates again.","tags":["WhatsApp"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"disconnected":{"type":"boolean"}},"required":["disconnected"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"owner","hints":{"destructive":true,"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/whatsapp/sync":{"post":{"operationId":"sync_whatsapp","summary":"Refresh the WhatsApp number from Meta","description":"Reads the number's current quality rating and messaging limit, and each template's review status, from Meta. Webhooks do this automatically; this is for checking now.","tags":["WhatsApp"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string","enum":["meta","outbox"],"description":"meta: the Cloud API. outbox: a local test number (development)."},"displayPhone":{"type":"string"},"verifiedName":{"type":["string","null"]},"status":{"type":"string","enum":["connected","restricted","disconnected"]},"qualityRating":{"type":"string","enum":["GREEN","YELLOW","RED","UNKNOWN"],"description":"Meta's quality rating. RED pauses WhatsApp campaigns."},"messagingLimit":{"type":"string","description":"Meta's tier, e.g. TIER_250: unique recipients per moving 24 hours."},"dailyLimit":{"description":"The tier as a number; null means unlimited.","type":["number","null"]},"coexistence":{"type":"boolean","description":"The number is also used in the WhatsApp Business app."},"connectedAt":{"type":"string"},"syncedAt":{"type":["string","null"]}},"required":["id","provider","displayPhone","verifiedName","status","qualityRating","messagingLimit","dailyLimit","coexistence","connectedAt","syncedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/whatsapp/settings":{"patch":{"operationId":"update_whatsapp_settings","summary":"Set WhatsApp quiet hours","description":"Sets the hours, in each recipient's local time, when marketing messages wait instead of going out. Default 22:00 to 09:00. Equal hours turn quiet hours off.","tags":["WhatsApp"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"quietHours":{"type":"object","properties":{"start":{"type":"integer","minimum":0,"maximum":23,"description":"Hour (0–23, recipient's local time) when marketing stops."},"end":{"type":"integer","minimum":0,"maximum":23,"description":"Hour when marketing may start again."}},"required":["start","end"],"additionalProperties":false}},"required":["quietHours"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"quietHours":{"type":"object","properties":{"start":{"type":"integer","minimum":0,"maximum":23,"description":"Hour (0–23, recipient's local time) when marketing stops."},"end":{"type":"integer","minimum":0,"maximum":23,"description":"Hour when marketing may start again."}},"required":["start","end"],"description":"When marketing waits."}},"required":["quietHours"]}}}}}},"/api/v1/whatsapp/library":{"get":{"operationId":"list_whatsapp_library","summary":"List ready WhatsApp templates","description":"Lists Ishtaqna's ready Arabic WhatsApp templates (win-back, new product, offer, Ramadan, Eid, welcome, birthday, review request) that can be submitted to Meta with create_whatsapp_template.","tags":["WhatsApp"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"body":{"type":"string"},"buttonText":{"type":["string","null"]}},"required":["key","name","description","body","buttonText"],"additionalProperties":false}}},"required":["templates"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/whatsapp/templates":{"get":{"operationId":"list_whatsapp_templates","summary":"List WhatsApp templates","description":"Lists the templates submitted for the connected number, with their review status at Meta and a preview as a sample customer reads them.","tags":["WhatsApp"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","description":"The template's name at Meta."},"language":{"type":"string"},"category":{"type":"string","enum":["MARKETING","UTILITY"]},"status":{"type":"string","enum":["pending","approved","rejected","paused","disabled"],"description":"Only approved templates can be sent."},"libraryKey":{"type":["string","null"]},"body":{"type":"string","description":"The text as written, with merge tags."},"preview":{"type":"string","description":"The text as a sample customer reads it."},"footerText":{"type":["string","null"]},"buttonText":{"type":["string","null"]},"buttonUrl":{"description":"Where the button goes; clicks are tracked through our link.","type":["string","null"]},"optOutText":{"description":"The quick-reply opt-out button, if any.","type":["string","null"]},"rejectedReason":{"type":["string","null"]},"createdAt":{"type":"string"}},"required":["id","name","language","category","status","libraryKey","body","preview","footerText","buttonText","buttonUrl","optOutText","rejectedReason","createdAt"],"additionalProperties":false}}},"required":["templates"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_whatsapp_template","summary":"Submit a WhatsApp template","description":"Checks a template against Meta's format rules and our content rules, then submits it to Meta for review. Write with merge tags ({{first_name|عميلنا العزيز}}, {{city}}, {{brand_name}}) or start from a library key. Marketing templates get an opt-out button. Approval arrives by webhook, usually within minutes.","tags":["WhatsApp"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","description":"The template's name at Meta."},"language":{"type":"string"},"category":{"type":"string","enum":["MARKETING","UTILITY"]},"status":{"type":"string","enum":["pending","approved","rejected","paused","disabled"],"description":"Only approved templates can be sent."},"libraryKey":{"type":["string","null"]},"body":{"type":"string","description":"The text as written, with merge tags."},"preview":{"type":"string","description":"The text as a sample customer reads it."},"footerText":{"type":["string","null"]},"buttonText":{"type":["string","null"]},"buttonUrl":{"description":"Where the button goes; clicks are tracked through our link.","type":["string","null"]},"optOutText":{"description":"The quick-reply opt-out button, if any.","type":["string","null"]},"rejectedReason":{"type":["string","null"]},"createdAt":{"type":"string"}},"required":["id","name","language","category","status","libraryKey","body","preview","footerText","buttonText","buttonUrl","optOutText","rejectedReason","createdAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"libraryKey":{"description":"Start from a ready template (list_whatsapp_library).","type":"string","maxLength":40},"brandId":{"description":"The brand whose name is written into the template. Default: the first brand.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"category":{"description":"MARKETING (default) for offers and news; UTILITY only for transactional updates.","type":"string","enum":["MARKETING","UTILITY"]},"body":{"description":"The message text, up to 1024 characters after merge tags. Default: the library text.","type":"string","maxLength":1500},"footerText":{"description":"Small grey line under the message, up to 60 characters.","anyOf":[{"type":"string","maxLength":60},{"type":"null"}]},"buttonText":{"description":"Label of the link button, up to 25 characters.","anyOf":[{"type":"string","maxLength":25},{"type":"null"}]},"buttonUrl":{"description":"Where the button goes (https). Clicks are tracked.","anyOf":[{"type":"string","maxLength":2000,"format":"uri"},{"type":"null"}]},"optOut":{"description":"Add the «إيقاف العروض» opt-out button (default true for marketing).","type":"boolean"}},"required":[]}}}}}},"/api/v1/whatsapp/templates/{id}":{"delete":{"operationId":"delete_whatsapp_template","summary":"Delete a WhatsApp template","description":"Deletes a template here and at Meta. It can't be undone; campaigns that use it can no longer send.","tags":["WhatsApp"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"destructive":true,"idempotent":true,"openWorld":true}}}},"/api/v1/whatsapp/replies":{"get":{"operationId":"list_whatsapp_replies","summary":"List WhatsApp replies","description":"Lists the latest messages customers sent to the connected number, newest first, marking the ones that were opt-outs. Answer them from the WhatsApp app or WhatsApp Manager.","tags":["WhatsApp"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"description":"How many (default 50).","type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"fromPhone":{"type":"string"},"contactId":{"type":["string","null"]},"contactName":{"type":["string","null"]},"body":{"type":["string","null"]},"type":{"type":"string"},"optOut":{"type":"boolean"},"receivedAt":{"type":"string"}},"required":["id","fromPhone","contactId","contactName","body","type","optOut","receivedAt"],"additionalProperties":false}}},"required":["replies"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/stores":{"get":{"operationId":"get_stores","summary":"Get connected stores","description":"Shows the online stores connected to the organization (Salla, Zid), how many customers and orders came from each, when they last synced, which platforms can be connected here, and the revenue campaigns brought in the last 30 days.","tags":["Stores"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"stores":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["salla","zid","test"],"description":"test: a simulated store for development."},"name":{"type":"string"},"domain":{"type":["string","null"]},"currency":{"type":"string"},"status":{"type":"string","enum":["connected","error","disconnected"],"description":"error: the platform refused our token; connect again."},"error":{"type":["string","null"]},"consent":{"type":"object","properties":{"email":{"type":"string"},"whatsapp":{"type":"string"}},"required":["email","whatsapp"],"additionalProperties":false},"customersSynced":{"type":"number"},"ordersSynced":{"type":"number"},"syncedAt":{"type":["string","null"]},"connectedAt":{"type":"string"}},"required":["id","platform","name","domain","currency","status","error","consent","customersSynced","ordersSynced","syncedAt","connectedAt"],"additionalProperties":false}},"available":{"type":"object","properties":{"salla":{"type":"boolean"},"zid":{"type":"boolean"},"test":{"type":"boolean"}},"required":["salla","zid","test"],"additionalProperties":false,"description":"Platforms whose app credentials are set here; test is development only."},"revenue":{"anyOf":[{"type":"object","properties":{"currency":{"type":"string"},"days":{"type":"number"},"storeOrders":{"type":"number","description":"Every paid order in the period."},"storeTotal":{"type":"number"},"attributed":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"},"fromClicks":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"}},"required":["orders","total"],"additionalProperties":false},"fromOpens":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"}},"required":["orders","total"],"additionalProperties":false}},"required":["orders","total","currency","fromClicks","fromOpens"],"additionalProperties":false,"description":"What campaigns brought (7 days after a click, 3 after an open)."},"byCampaign":{"type":"array","items":{"type":"object","properties":{"campaignId":{"type":"string"},"name":{"type":"string"},"orders":{"type":"number"},"total":{"type":"number"}},"required":["campaignId","name","orders","total"],"additionalProperties":false}},"headline":{"type":"string","description":"The attributed total, formatted in Arabic, e.g. 1,250 ر.س."}},"required":["currency","days","storeOrders","storeTotal","attributed","byCampaign","headline"],"additionalProperties":false},{"type":"null"}],"description":"Null until a store is connected."}},"required":["stores","available","revenue"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/stores/connect":{"post":{"operationId":"connect_store","summary":"Connect a store","description":"Connects a Salla or Zid store: answers authorizeUrl, where the owner installs or approves Ishtaqna for their store; afterwards the store shows on /app/stores to link (claim_store), and its customers and orders are imported. Locally, platform test connects a simulated store at once. Customers are imported with the consent basis you choose per channel; unknown keeps them pending until they agree.","tags":["Stores"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"store":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["salla","zid","test"],"description":"test: a simulated store for development."},"name":{"type":"string"},"domain":{"type":["string","null"]},"currency":{"type":"string"},"status":{"type":"string","enum":["connected","error","disconnected"],"description":"error: the platform refused our token; connect again."},"error":{"type":["string","null"]},"consent":{"type":"object","properties":{"email":{"type":"string"},"whatsapp":{"type":"string"}},"required":["email","whatsapp"],"additionalProperties":false},"customersSynced":{"type":"number"},"ordersSynced":{"type":"number"},"syncedAt":{"type":["string","null"]},"connectedAt":{"type":"string"}},"required":["id","platform","name","domain","currency","status","error","consent","customersSynced","ordersSynced","syncedAt","connectedAt"],"additionalProperties":false},{"type":"null"}],"description":"The connected store (test), or null until the owner approves."},"authorizeUrl":{"description":"Open this to approve Ishtaqna in Salla or Zid.","type":["string","null"]}},"required":["store","authorizeUrl"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"platform":{"type":"string","enum":["salla","zid","test"],"description":"salla, zid, or test (development only)."},"consent":{"type":"object","properties":{"email":{"type":"string","enum":["checkout","signup_form","in_store","unknown"],"description":"checkout: customers agreed to offers when buying; unknown: ask them first (they stay pending)."},"whatsapp":{"type":"string","enum":["checkout","signup_form","in_store","unknown"],"description":"Same choices, for WhatsApp."}},"required":["email","whatsapp"],"description":"Why this store's customers may get marketing, per channel. unknown keeps them pending until they agree."},"attest":{"description":"Required (true) when a consent basis isn't unknown: these customers agreed to receive offers.","type":"boolean"},"brandId":{"description":"The brand this store belongs to; the first brand by default.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["platform","consent"]}}}}}},"/api/v1/stores/claim":{"post":{"operationId":"claim_store","summary":"Link a store installed from its app store","description":"Links a store that installed or approved Ishtaqna to this organization, then imports its customers and orders. The dashboard offers the installId to the signed-in owner whose email matches the store account's, or who just came back from approving; it works once, for 7 days.","tags":["Stores"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["salla","zid","test"],"description":"test: a simulated store for development."},"name":{"type":"string"},"domain":{"type":["string","null"]},"currency":{"type":"string"},"status":{"type":"string","enum":["connected","error","disconnected"],"description":"error: the platform refused our token; connect again."},"error":{"type":["string","null"]},"consent":{"type":"object","properties":{"email":{"type":"string"},"whatsapp":{"type":"string"}},"required":["email","whatsapp"],"additionalProperties":false},"customersSynced":{"type":"number"},"ordersSynced":{"type":"number"},"syncedAt":{"type":["string","null"]},"connectedAt":{"type":"string"}},"required":["id","platform","name","domain","currency","status","error","consent","customersSynced","ordersSynced","syncedAt","connectedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"installId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"From the link opened after installing Ishtaqna in the store."},"consent":{"type":"object","properties":{"email":{"type":"string","enum":["checkout","signup_form","in_store","unknown"],"description":"checkout: customers agreed to offers when buying; unknown: ask them first (they stay pending)."},"whatsapp":{"type":"string","enum":["checkout","signup_form","in_store","unknown"],"description":"Same choices, for WhatsApp."}},"required":["email","whatsapp"],"description":"Why this store's customers may get marketing, per channel. unknown keeps them pending until they agree."},"attest":{"description":"Required (true) when a consent basis isn't unknown.","type":"boolean"}},"required":["installId","consent"]}}}}}},"/api/v1/stores/{id}/sync":{"post":{"operationId":"sync_store","summary":"Sync a store now","description":"Reads the store's orders since the last sync now (and every customer, the first time). Webhooks bring new orders and customers automatically; this catches anything missed.","tags":["Stores"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","const":"started"}},"required":["status"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"editor","hints":{"idempotent":true,"openWorld":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/stores/{id}/disconnect":{"post":{"operationId":"disconnect_store","summary":"Disconnect a store","description":"Disconnects a store and forgets its tokens: new orders stop arriving. Contacts and past orders stay, so reports keep their revenue. Connecting again means approving Ishtaqna in the store again.","tags":["Stores"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["salla","zid","test"],"description":"test: a simulated store for development."},"name":{"type":"string"},"domain":{"type":["string","null"]},"currency":{"type":"string"},"status":{"type":"string","enum":["connected","error","disconnected"],"description":"error: the platform refused our token; connect again."},"error":{"type":["string","null"]},"consent":{"type":"object","properties":{"email":{"type":"string"},"whatsapp":{"type":"string"}},"required":["email","whatsapp"],"additionalProperties":false},"customersSynced":{"type":"number"},"ordersSynced":{"type":"number"},"syncedAt":{"type":["string","null"]},"connectedAt":{"type":"string"}},"required":["id","platform","name","domain","currency","status","error","consent","customersSynced","ordersSynced","syncedAt","connectedAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"idempotent":true}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{},"required":[]}}}}}},"/api/v1/stores/orders":{"get":{"operationId":"list_store_orders","summary":"List store orders","description":"Lists the orders from connected stores, newest first, 50 a page, with the customer and the campaign credited for each. Filter by campaignId to see what one campaign brought. Pass nextCursor back as cursor for the next page.","tags":["Stores"],"parameters":[{"name":"campaignId","in":"query","required":false,"schema":{"description":"Only orders credited to this campaign.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"name":"limit","in":"query","required":false,"schema":{"default":50,"description":"How many, 50 by default.","type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","required":false,"schema":{"description":"nextCursor from the previous page.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"reference":{"description":"The order number the shop shows.","type":["string","null"]},"total":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string","enum":["pending","paid","cancelled","refunded"],"description":"Only paid orders count as revenue."},"placedAt":{"type":"string"},"contact":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"campaign":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}],"description":"The campaign credited, if any."},"via":{"anyOf":[{"type":"string","enum":["click","open"]},{"type":"null"}],"description":"click: bought within 7 days of clicking; open: within 3 days of opening."}},"required":["id","reference","total","currency","status","placedAt","contact","campaign","via"],"additionalProperties":false}},"nextCursor":{"type":["number","null"]}},"required":["orders","nextCursor"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/stores/revenue":{"get":{"operationId":"get_revenue","summary":"Get revenue from campaigns","description":"For the last N days: the connected store's paid orders, and the part campaigns brought (bought within 7 days of clicking, or 3 days of opening or reading), with the top campaigns. Null until a store is connected.","tags":["Stores"],"parameters":[{"name":"days","in":"query","required":false,"schema":{"default":30,"description":"The period, 30 days by default.","type":"integer","minimum":1,"maximum":365}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"revenue":{"anyOf":[{"type":"object","properties":{"currency":{"type":"string"},"days":{"type":"number"},"storeOrders":{"type":"number","description":"Every paid order in the period."},"storeTotal":{"type":"number"},"attributed":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"},"currency":{"type":"string"},"fromClicks":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"}},"required":["orders","total"],"additionalProperties":false},"fromOpens":{"type":"object","properties":{"orders":{"type":"number"},"total":{"type":"number"}},"required":["orders","total"],"additionalProperties":false}},"required":["orders","total","currency","fromClicks","fromOpens"],"additionalProperties":false,"description":"What campaigns brought (7 days after a click, 3 after an open)."},"byCampaign":{"type":"array","items":{"type":"object","properties":{"campaignId":{"type":"string"},"name":{"type":"string"},"orders":{"type":"number"},"total":{"type":"number"}},"required":["campaignId","name","orders","total"],"additionalProperties":false}},"headline":{"type":"string","description":"The attributed total, formatted in Arabic, e.g. 1,250 ر.س."}},"required":["currency","days","storeOrders","storeTotal","attributed","byCampaign","headline"],"additionalProperties":false},{"type":"null"}]}},"required":["revenue"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"viewer","hints":{"readOnly":true,"idempotent":true}}}},"/api/v1/api-keys":{"get":{"operationId":"list_api_keys","summary":"List API keys","description":"Lists the organization's API keys, revoked ones included, newest first. The keys themselves are never shown again.","tags":["API keys"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"apiKeys":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"level":{"type":"string","enum":["full","signups","read"]},"prefix":{"type":"string","description":"The key's first characters, to recognize it."},"lastUsedAt":{"type":["string","null"]},"revokedAt":{"type":["string","null"]},"createdAt":{"type":"string"}},"required":["id","name","level","prefix","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false}}},"required":["apiKeys"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"readOnly":true,"idempotent":true}}},"post":{"operationId":"create_api_key","summary":"Create an API key","description":"Creates an API key and returns it once; only its hash is stored. full can do everything, read can only read, and signups can only add contacts.","tags":["API keys"],"parameters":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"level":{"type":"string","enum":["full","signups","read"]},"prefix":{"type":"string","description":"The key's first characters, to recognize it."},"lastUsedAt":{"type":["string","null"]},"revokedAt":{"type":["string","null"]},"createdAt":{"type":"string"},"key":{"type":"string","description":"The secret key. Shown only in this answer."}},"required":["id","name","level","prefix","lastUsedAt","revokedAt","createdAt","key"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60,"description":"What the key is for, e.g. Website signups."},"level":{"type":"string","enum":["full","signups","read"],"description":"full, read or signups."}},"required":["name","level"]}}}}}},"/api/v1/api-keys/{id}":{"delete":{"operationId":"revoke_api_key","summary":"Revoke an API key","description":"Revokes an API key for good: requests with it answer unauthorized from now on. It can't be undone.","tags":["API keys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The resource's ID."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"level":{"type":"string","enum":["full","signups","read"]},"prefix":{"type":"string","description":"The key's first characters, to recognize it."},"lastUsedAt":{"type":["string","null"]},"revokedAt":{"type":["string","null"]},"createdAt":{"type":"string"}},"required":["id","name","level","prefix","lastUsedAt","revokedAt","createdAt"],"additionalProperties":false}}}},"default":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"x-ishtaqna":{"level":"full","role":"admin","hints":{"destructive":true,"idempotent":true}}}}}}