{"openapi":"3.0.0","paths":{"/api/v1/messages":{"post":{"description":"Unified send endpoint for all channels. Supports inline content or a templateId with variables. Pass an Idempotency-Key header to make retries safe.","operationId":"PublicMessagesController_send_api/v1","parameters":[{"name":"Idempotency-Key","in":"header","description":"Unique key (max 255 chars). Duplicate requests within 24h replay the original response.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageDto"}}}},"responses":{"201":{"description":""}},"security":[{"api-key":[]}],"summary":"Send a transactional message (email, SMS, or WhatsApp)","tags":["Messages"]},"get":{"operationId":"PublicMessagesController_list_api/v1","parameters":[{"name":"channel","required":false,"in":"query","schema":{"type":"string","enum":["email","sms","whatsapp"]}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["queued","sending","sent","delivered","opened","clicked","bounced","failed"]}},{"name":"createdAfter","required":false,"in":"query","description":"ISO 8601 — only messages created at/after","schema":{"type":"string"}},{"name":"createdBefore","required":false,"in":"query","description":"ISO 8601 — only messages created at/before","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"Opaque cursor from the previous page (pagination.cursor)","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"List messages (filter by channel, status, date; cursor pagination)","tags":["Messages"]}},"/api/v1/messages/{id}":{"get":{"operationId":"PublicMessagesController_getOne_api/v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Get the delivery status of a message","tags":["Messages"]}},"/api/v1/contacts":{"post":{"operationId":"PublicContactsController_create_api/v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicCreateContactDto"}}}},"responses":{"201":{"description":""}},"security":[{"api-key":[]}],"summary":"Create a contact","tags":["Contacts"]},"get":{"operationId":"PublicContactsController_list_api/v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","description":"Search by email, name","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["ACTIVE","UNSUBSCRIBED","BOUNCED","COMPLAINED","QUARANTINED"]}},{"name":"tags","required":false,"in":"query","description":"Filter by tags (OR)","schema":{"type":"array","items":{"type":"string"}}},{"name":"source","required":false,"in":"query","description":"Filter by source","schema":{"type":"string"}},{"name":"createdAfter","required":false,"in":"query","description":"Created after date","schema":{"type":"string"}},{"name":"createdBefore","required":false,"in":"query","description":"Created before date","schema":{"type":"string"}},{"name":"minEngagementScore","required":false,"in":"query","description":"Minimum engagement score","schema":{"type":"number"}},{"name":"sortBy","required":false,"in":"query","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","status","engagementScore","lastEngagedAt","source"]}},{"name":"sortOrder","required":false,"in":"query","schema":{"default":"desc","type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"List contacts (search, filter, page pagination)","tags":["Contacts"]}},"/api/v1/contacts/bulk":{"post":{"operationId":"PublicContactsController_bulk_api/v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkContactsDto"}}}},"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Create up to 1000 contacts, with a per-row result report","tags":["Contacts"]}},"/api/v1/contacts/{id}":{"get":{"operationId":"PublicContactsController_get_api/v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Get a contact","tags":["Contacts"]},"patch":{"operationId":"PublicContactsController_update_api/v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicUpdateContactDto"}}}},"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Update a contact","tags":["Contacts"]},"delete":{"operationId":"PublicContactsController_remove_api/v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"api-key":[]}],"summary":"Delete a contact","tags":["Contacts"]}},"/api/v1/templates":{"post":{"operationId":"PublicTemplatesController_create_api/v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateDto"}}}},"responses":{"201":{"description":""}},"security":[{"api-key":[]}],"summary":"Create a template (email or SMS)","tags":["Templates"]},"get":{"operationId":"PublicTemplatesController_list_api/v1","parameters":[{"name":"channel","required":false,"in":"query","schema":{"enum":["email","sms","whatsapp"],"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"List templates across all channels","tags":["Templates"]}},"/api/v1/templates/{id}":{"get":{"operationId":"PublicTemplatesController_get_api/v1","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Get a template by id (searches all channels)","tags":["Templates"]}},"/api/v1/analytics/messages":{"get":{"operationId":"PublicAnalyticsController_messages_api/v1","parameters":[{"name":"startDate","required":false,"in":"query","description":"ISO 8601 (default: start of current month)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"ISO 8601 (default: now)","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Message delivery statistics by channel over a date range","tags":["Analytics"]}}},"info":{"title":"QuickGrow AI Public API","description":"REST API for third-party applications: transactional messages (email/SMS/WhatsApp), contacts, templates, analytics, and webhooks. Authenticate with an API key from Settings → Developer API, sent as `X-API-Key: mk_...`. All routes are versioned under `/api/v1`.","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"api-key":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Tenant API key (mk_...)"}},"schemas":{"AttachmentDto":{"type":"object","properties":{"filename":{"type":"string","description":"File name shown to the recipient","example":"invoice.pdf"},"content":{"type":"string","description":"File content, base64-encoded"},"contentType":{"type":"string","description":"MIME type, e.g. application/pdf"},"cid":{"type":"string","description":"Content-ID, for referencing the file inline from the HTML body"}},"required":["filename","content"]},"SendMessageDto":{"type":"object","properties":{"channel":{"type":"string","enum":["email","sms","whatsapp"],"example":"email"},"to":{"type":"string","description":"Recipient address: an email address for channel \"email\", an E.164 phone number for \"sms\"/\"whatsapp\"","example":"customer@example.com"},"subject":{"type":"string","description":"Email subject line (email only)"},"html":{"type":"string","description":"HTML body (email only)"},"text":{"type":"string","description":"Plain-text body (sms/whatsapp body, or email text fallback)"},"from":{"type":"string","description":"Sender email address (email only)"},"fromName":{"type":"string","description":"Sender display name (email only), e.g. the school or brand the message is from. The address itself still has to be a domain this tenant has verified.","example":"Shaheed Suhrawardy Model High School"},"replyTo":{"type":"string","description":"Reply-to email address (email only)"},"templateId":{"type":"string","description":"Template id to render instead of inline content (must match the channel)"},"variables":{"type":"object","description":"Values for {{variable}} placeholders when using templateId","example":{"customerName":"Alex","orderId":"INV-123"}},"tags":{"description":"Tags for filtering and analytics","type":"array","items":{"type":"string"}},"metadata":{"type":"object","description":"Integrator's own reference data, echoed back on status reads and webhooks","example":{"externalRef":"INV-123"}},"attachments":{"description":"Files to attach (email only). Base64-encoded, at most 10 files and 7 MB decoded in total.","type":"array","items":{"$ref":"#/components/schemas/AttachmentDto"}}},"required":["channel","to"]},"PublicCreateContactDto":{"type":"object","properties":{"email":{"type":"string","example":"contact@example.com"},"phone":{"type":"string","example":"+8801712345678"},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"tags":{"example":["newsletter","promotion"],"type":"array","items":{"type":"string"}},"source":{"type":"string","example":"website_signup"},"customFields":{"type":"object","example":{"brand":"Acme Inc","position":"Manager"}}}},"BulkContactsDto":{"type":"object","properties":{"contacts":{"description":"Up to 1000 contacts per request","type":"array","items":{"$ref":"#/components/schemas/PublicCreateContactDto"}}},"required":["contacts"]},"PublicUpdateContactDto":{"type":"object","properties":{"phone":{"type":"string","example":"+8801712345678"},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"Doe"},"tags":{"example":["newsletter","promotion"],"type":"array","items":{"type":"string"}},"customFields":{"type":"object","example":{"brand":"Acme Inc","position":"Manager"}}}},"CreateTemplateDto":{"type":"object","properties":{"locale":{"type":"string","example":"bn","description":"BCP-47 language tag"},"channel":{"type":"string","enum":["email","sms"],"description":"Template channel. WhatsApp templates require Meta approval and are managed in the portal."},"name":{"type":"string","example":"Order Confirmation","maxLength":100},"description":{"type":"string","maxLength":500},"subject":{"type":"string","description":"Subject line — required when channel is \"email\"","example":"Your order {{orderId}} is confirmed","maxLength":255},"htmlContent":{"type":"string","description":"HTML body (email only). Use {{variable}} placeholders."},"textContent":{"type":"string","description":"Plain-text body. Required for \"sms\"; for \"email\" it is the text fallback (required when htmlContent is omitted).","example":"Hi {{firstName}}, your order {{orderId}} is confirmed."},"variables":{"description":"Variable names used in the content, without braces","example":["firstName","orderId"],"type":"array","items":{"type":"string"}}},"required":["channel","name"]}}}}