Guides
Integration Flows
Setup, purchase, POS and discount flows end-to-end.
Store integrations — recommended flow
1. Prerequisites
- Obtain base URL, API key, and required scopes from Sendy.
- Confirm the key is linked to your store (otherwise expect 400 from the service layer).
- Store the key as a secret (env / vault), not in client-side code.
- Cache or call
GET /api/v1/address-reference/provincesandGET /api/v1/address-reference/provinces/{code}/areasas needed (no API key) so you can send validaddressProvinceCode/addressAreaIdon order create — seeapi-design.json→addressReference.
2. Orders
- Create:
POST /orders(orPOST /orders/bulkfor batches). SetfulfillmentTypeto match how you fulfill (from_tovswarehouse). SendaddressProvinceCodeandaddressAreaIdfromGET /api/v1/address-reference/provincesandGET /api/v1/address-reference/provinces/{code}/areas. SendcustomerPhoneas a valid Iraq mobile (seeIraqPhoneValidationin code). Persist returnedidandpublicIdin your system. - Track:
GET /orders/{orderId}for status, payment snapshot,fulfillmentType, andaddressProvinceCode/addressAreaId. - Adjust delivery details:
PUT /orders/{orderId}if the free-text address or map pin needs to change. The request body is still validated like create (including province, area, and phone), but the server only updatescustomerAddress,deliveryLat, anddeliveryLng. - Cancel:
POST /orders/{orderId}/cancelwith optional reason.
3. Catalog and inventory
- Products:
POST /catalog/productsto upsert by SKU;GET /catalog/productsto reconcile. - Stock:
PUT /catalog/inventory/{inventoryItemId}withquantityOnHand;GET /catalog/inventoryfor full list (includeswarehouseIdwhen relevant).
4. Returns
- After delivery,
POST /orders/{orderId}/return-requestwith optional reason. - Poll
GET /orders/{orderId}/return-requestsorGET /return-requests/{returnRequestId}for status (pending,approved,rejected,completed).
5. Errors and retries
- 400 — validation, bad filter, or business rule; inspect
errorsandmessage; fix payload before retrying. - 403 — missing scope; fix key configuration.
- 404 — wrong id or resource not visible to this store.
- 409 — conflict (e.g. duplicate pending return).
- 5xx — transient; retry with backoff and idempotency awareness on creates (Sendy does not document a separate idempotency key header; treat
externalRefas your own deduplication key on the client side if needed).
For exact JSON properties, always refer to api-design.json → dtos.
6. Storefront (social-link order intake)
This flow is for stores that want a shareable public URL to paste in their Instagram bio or WhatsApp — customers visit the link, browse products, and place orders without any app login.
-
Add prices and images to catalog products (optional but recommended):
PUT /catalog/products/{productId}via the integration API, or store JWTPUT /api/v1/store/products/{id}.- Products without a
priceare still accepted at checkout (line total = 0).
-
Customize storefront settings (store JWT,
store.storefront.manage):PUT /api/v1/store/storefrontwithdescription,coverImageUrl,niche.- Apply a niche template if desired:
GET /api/v1/store/storefront/templates→POST /api/v1/store/storefront/templates/{id}/apply.
-
Publish the storefront:
POST /api/v1/store/storefront/publish.- Returns
{ slug, is_published: true }and thepublicUrl. - Fails with 400 if the store has no slug (contact support to assign one; demo stores have slugs seeded automatically).
-
Share the public URL:
- Format:
{baseUrl}/api/v1/public/storefronts/{slug}(e.g.…/flora-baghdad). - Paste in Instagram bio, WhatsApp link, or any social post.
- Format:
-
Customer flow (no auth):
GET /api/v1/public/storefronts/{slug}— browse store info + active priced products.POST /api/v1/public/storefronts/{slug}/orders— place an order by SKU + quantity.- Resulting order has
source = "Storefront"; it appears in the store's normal order list.
-
Unpublish when needed:
DELETE /api/v1/store/storefront/publish.
7. Webhook flow (recommended)
- Register endpoint:
POST /webhookswith your HTTPS URL. - Persist returned subscription id and keep the webhook secret secure.
- On each delivery, verify
X-Sendy-Signatureagainst the exact raw body (HMAC SHA-256). - De-duplicate by
X-Sendy-Event-Id(and/orevent_id) and process asynchronously. - Return
2xxonly after persistence/queueing; non-2xx triggers retries with backoff. - Rotate secret using
POST /webhooks/{subscriptionId}/rotate-secretduring routine key rotation.
8. Store Setup Flow
Use this flow when onboarding a new store before it starts operating.
- Initialize settings (required first):
POST /api/v1/store/settingswithcurrencyCode,timezone,industry,countryCode,language.- Returns 409 if settings already exist.
- Configure storefront (optional):
PUT /api/v1/store/storefrontwith extended fields:description,coverImageUrl,bannerImageUrl,contactEmail, social links, SEO fields, FAQs, policies,customDomain.- Apply a niche template:
POST /api/v1/store/storefront/templates/{id}/apply.
- Add package sizes (optional, for shipping):
POST /api/v1/store/package-sizes— mark one asisDefault: true.
- Configure cashier (optional, for POS):
PUT /api/v1/store/cashier/settingswithrequirePin,openingCashDefault,receiptFooterNote.
- Add product categories (optional):
POST /api/v1/store/categories— supports parent/child hierarchy viaparentCategoryId.
- Publish storefront (when ready):
POST /api/v1/store/storefront/publish.
9. Purchase Flow
Use this flow to track procurement from suppliers.
- Add supplier (optional):
POST /api/v1/store/supplierswithfullName, contact details.
- Create Purchase Order (starts as
Draft):POST /api/v1/store/purchase-orderswithsupplierId,orderDate,items[](min 1 item required).- Server computes
subTotalandtotalAmount.
- Advance status as PO progresses:
PUT /api/v1/store/purchase-orders/{id}withstatus: "Sent"/"PartiallyReceived"/"Received"/"Cancelled".
- Attach supporting documents (max 3):
POST /api/v1/store/purchase-orders/{id}/attachmentswithfileName,fileUrl,fileSize.
- Log the expense after payment:
POST /api/v1/store/expenseswithname,amount,expenseType,category,expenseDate.
10. POS / Cashier Flow
Use this flow for point-of-sale sessions.
- Pin frequently sold products (setup step):
POST /api/v1/store/cashier/pinnedwithstoreProductId,sortOrder. Max 30 items.- Reorder with
PUT /api/v1/store/cashier/pinned/reorder.
- Open a session at start of shift:
POST /api/v1/store/cashier/sessions/openwithopeningCashamount.- Returns 409 if a session is already open.
- Sell (during session):
- Create orders via the normal
POST /api/v1/store/ordersflow.
- Create orders via the normal
- Close session at end of shift:
POST /api/v1/store/cashier/sessions/{sessionId}/closewithclosingCash, optionalnotes.
- Review history:
GET /api/v1/store/cashier/sessionsfor all past sessions.
11. Discount Flow
Discount Codes
- Create a code:
POST /api/v1/store/discounts/codeswithcode(auto-uppercased),discountType,discountValue, optionalminOrderValue,maxUses,startsAt,expiresAt.
- Validate at checkout:
GET /api/v1/store/discounts/codes/validate?code=SAVE20&orderValue=50000- Returns
{ isValid, discountType, discountValue }or{ isValid: false, errorMessage }.
- Apply the discount server-side when creating the order (pass the validated code; service deducts from order total).
Discount Rules
- Create a rule for automatic discounts (no code required):
POST /api/v1/store/discounts/ruleswithname,discountType,discountValue, optionalcategoryId(per-category rule),channels.- Rules with
isActive: trueare applied automatically during order processing.
Shipping Rules
- Create a rule:
POST /api/v1/store/shipping/ruleswithname,ruleType(FlatRate,FreeShipping,WeightBased,OrderValueBased),cost, optionalminOrderValue/maxOrderValue.- Rules with
isActive: trueare evaluated during checkout to determine shipping cost.
12. Social Messaging Agent Setup
Use this flow to connect WhatsApp or Instagram and enable the AI-powered CRM inbox.
A — Connect a channel
-
Connect the account (
store.social_channels.manage):POST /api/v1/store/social/channels- Required:
channelType(WhatsApporInstagram),externalAccountId,displayName,accessToken,aiProviderCode,aiModelCode. - Optional:
appSecret(strongly recommended for webhook HMAC verification),systemPromptOverride,isEnabled,isAgentEnabled. - Server encrypts
accessTokenandappSecret; returnswebhookVerifyToken— copy it before leaving this screen.
-
Register the webhook with Meta (one-time, in Meta Developer Console):
- Callback URL:
https://<your-host>/api/v1/webhooks/social/whatsapp(or/instagram) - Verify Token: the
webhookVerifyTokenfrom the connect response - Subscribe to:
messages,message_deliveries,message_reads - Meta calls
GET /api/v1/webhooks/social/whatsapp?hub.mode=subscribe&hub.verify_token=...&hub.challenge=...; Sendy responds with the challenge to confirm.
- Callback URL:
-
Rotate the verify token if compromised:
POST /api/v1/store/social/channels/{channelId}/rotate-token— generates a newWebhookVerifyToken; update the Meta webhook registration with the new value.
B — Manage AI agent
-
Toggle the AI agent on/off per channel:
POST /api/v1/store/social/channels/{channelId}/toggle-agent{ "enabled": true/false }- When disabled, inbound messages are still received and stored but no
AiMessageJobis created — staff must reply manually.
-
AI dispatch (automatic, background):
- A Hangfire job (
social.ai.dispatch) runs every minute. - It picks pending
AiMessageJobrecords, calls the configured AI provider (OpenAI or Anthropic) with the conversation history + store context as system prompt, sends the reply via the Meta API, and records token usage. - Failed jobs retry with exponential backoff;
Deadstatus is set afterMaxAttempts.
- A Hangfire job (
C — Staff CRM inbox
-
View conversations (
store.conversations.view):GET /api/v1/store/social/conversations?status=Open&page=1- Returns paginated list of conversations. Filter by
channelIdorstatus(Open,Pending,Resolved).
-
Read full conversation (
store.conversations.view):GET /api/v1/store/social/conversations/{conversationId}- Returns conversation metadata plus the full message history (inbound + outbound, AI-generated or manual).
-
Send a message manually (
store.conversations.manage):POST /api/v1/store/social/conversations/{conversationId}/messages{ "text": "..." }- Calls Meta API in real time; persists
SocialMessagerecord on success.
-
Resolve / reopen (
store.conversations.manage):POST /{conversationId}/resolve— sets status toResolved.POST /{conversationId}/reopen— sets status back toOpen.
D — Token usage and billing
- Token consumption is accumulated per subscription period in
StoreAiTokenUsage. GET /api/v1/store/subscription/usagereturnsaiInputTokensUsed,aiOutputTokensUsedalongside the plan's included quota.- Overage beyond
IncludedInputTokensPerPeriod/IncludedOutputTokensPerPeriodis tracked asOverageInputTokens/OverageOutputTokensand billed atOverageInputTokenPriceIqd/OverageOutputTokenPriceIqdper 1,000 tokens. - Social Messaging is available on all subscription plans (
AllowsSocialMessaging = true); token quota and overage pricing are configured per plan.
Source: DOCS/03-integrations/specs/store/flow.md