{"openapi":"3.0.0","info":{"title":"JetEmail API","version":"1.0.0","description":"API documentation for JetEmail's transactional email service."},"externalDocs":{"description":"Download OpenAPI Specification","url":"/openapi.json"},"components":{"securitySchemes":{"apiKeyAuth":{"type":"http","scheme":"bearer","description":"API key for account management endpoints. Use your api_ prefixed token."},"transactionalKeyAuth":{"type":"http","scheme":"bearer","description":"Transactional key for sending emails. Use your transactional_ prefixed token."}},"schemas":{"MarketingTemplate":{"type":"object","properties":{"id":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Welcome email"},"subject":{"type":"string","description":"Subject line. Merge tokens are rendered per recipient here just as they are in the body.","example":"Welcome to JetEmail, {{firstName | there}} 👋"},"preview_text":{"type":"string"},"from_name":{"type":"string","description":"Default sender name"},"from_email":{"type":"string","description":"Default from address — must be on a verified sending domain"},"reply_to":{"type":"string","description":"Default reply-to"},"editor_type":{"type":"string","enum":["builder","html"],"example":"builder"},"theme_id":{"type":"string","nullable":true},"blocks":{"type":"string","description":"JSON array of builder blocks (builder templates render from these)"},"styles":{"type":"string","description":"JSON EmailStyles (global background/font/colors/button defaults)"},"html":{"type":"string","description":"Rendered email HTML, merge tokens intact"},"text":{"type":"string","description":"Plaintext fallback"},"created_at":{"type":"integer","description":"Unix seconds"},"updated_at":{"type":"integer","description":"Unix seconds"}}},"MarketingTemplateInput":{"type":"object","properties":{"name":{"type":"string"},"subject":{"type":"string"},"previewText":{"type":"string"},"fromName":{"type":"string"},"fromEmail":{"type":"string","description":"Must be on a verified sending domain"},"replyTo":{"type":"string"},"editorType":{"type":"string","enum":["builder","html"]},"themeId":{"type":"string","nullable":true},"blocks":{"type":"array","items":{"type":"object"},"description":"Builder block tree"},"styles":{"type":"object","description":"EmailStyles"},"html":{"type":"string"},"text":{"type":"string"}}},"MarketingField":{"type":"object","description":"A custom merge/personalization field usable as {{key}} and supplied per-recipient at send time.","properties":{"id":{"type":"string"},"key":{"type":"string","example":"companyName"},"label":{"type":"string","example":"Company name"}}},"MarketingTheme":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"Brand theme"},"styles":{"type":"string","description":"JSON EmailStyles"}}},"MarketingAudience":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"Newsletter subscribers"},"description":{"type":"string"},"contact_count":{"type":"integer","example":128}}},"MarketingContact":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","example":"jane@example.com"},"first_name":{"type":"string"},"last_name":{"type":"string"},"attributes":{"type":"string","description":"JSON object of custom merge fields"},"status":{"type":"string","enum":["subscribed","unsubscribed","bounced","complained"],"example":"subscribed"},"created_at":{"type":"integer"}}},"MarketingWorkflow":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"Welcome series"},"status":{"type":"string","enum":["draft","active","paused","archived"],"example":"active"},"version":{"type":"integer","example":1},"trigger":{"type":"string","description":"JSON: { type, config } — e.g. { \"type\":\"event\", \"config\":{ \"name\":\"signup\" } }"},"graph":{"type":"string","description":"JSON: { entry, nodes } — ordered email/timer nodes"},"reentry":{"type":"string","enum":["once","after_complete","always"],"example":"once"},"created_at":{"type":"integer"},"updated_at":{"type":"integer"}}},"MarketingBroadcast":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"template_id":{"type":"string","nullable":true},"audience_id":{"type":"string","nullable":true},"from_name":{"type":"string"},"from_email":{"type":"string"},"subject":{"type":"string"},"status":{"type":"string","enum":["draft","scheduled","sending","sent","failed","paused"],"example":"sending"},"scheduled_at":{"type":"integer","nullable":true},"sent_at":{"type":"integer","nullable":true},"recipient_count":{"type":"integer"},"sent_count":{"type":"integer"},"created_at":{"type":"integer"},"updated_at":{"type":"integer"}}},"MarketingAsset":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string","description":"Public image URL","example":"https://jetemailassets.com/abc/2026/07/xyz.png"},"content_type":{"type":"string","example":"image/png"},"size":{"type":"integer","description":"Bytes"},"created_at":{"type":"integer"}}},"MarketingAssetStorage":{"type":"object","properties":{"usedBytes":{"type":"integer","description":"Bytes counted against the account storage quota"},"limitBytes":{"type":"integer","description":"Account storage quota in bytes"},"remainingBytes":{"type":"integer","description":"Bytes remaining before uploads are blocked"},"paid":{"type":"boolean","description":"Whether the paid marketing-plan quota applies"}}},"MarketingUnsubPageSettings":{"type":"object","properties":{"logo_url":{"type":"string","description":"https:// logo URL, empty for none"},"heading":{"type":"string","description":"Confirm page heading (empty → default)"},"message":{"type":"string","description":"Confirm page body text (empty → default)"},"button_label":{"type":"string","description":"Confirm button label (empty → default)"},"success_heading":{"type":"string","description":"Success page heading (empty → default)"},"success_message":{"type":"string","description":"Success page body text (empty → default)"},"hide_branding":{"type":"boolean","description":"Hide the \"Powered by JetEmail\" footer (paid plans)"}}},"MarketingSignupFormField":{"type":"object","required":["name","label","type","required","placeholder"],"properties":{"name":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9_]{0,63}$","description":"Built-in field name (`email`, `firstName`, `lastName`) or an existing custom marketing-field key.","example":"email"},"label":{"type":"string","maxLength":100,"example":"Email address"},"type":{"type":"string","enum":["email","text"],"example":"email"},"required":{"type":"boolean","description":"Email is always required.","example":true},"placeholder":{"type":"string","maxLength":150,"example":"you@example.com"}}},"MarketingSignupFormSettings":{"type":"object","properties":{"heading":{"type":"string","maxLength":160,"example":"Stay in the loop"},"description":{"type":"string","maxLength":500,"example":"Get product news and updates delivered to your inbox."},"buttonLabel":{"type":"string","maxLength":80,"example":"Subscribe"},"successMessage":{"type":"string","maxLength":300,"example":"You're subscribed. Thanks for joining!"},"errorMessage":{"type":"string","maxLength":300,"example":"Something went wrong. Please try again."},"requireConsent":{"type":"boolean","default":false},"consentLabel":{"type":"string","maxLength":500,"example":"I agree to receive marketing emails. I can unsubscribe at any time."},"redirectUrl":{"type":"string","format":"uri","maxLength":2048,"description":"Optional http(s) destination after a successful browser submission."},"backgroundColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#ffffff"},"textColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#111827"},"inputColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#ffffff"},"buttonColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#111827"},"buttonTextColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#ffffff"},"borderColor":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#d1d5db"},"fontFamily":{"type":"string","enum":["Arial, sans-serif","Helvetica, Arial, sans-serif","Georgia, serif","Verdana, sans-serif","system-ui, sans-serif"]},"borderRadius":{"type":"integer","minimum":0,"maximum":24,"example":8},"hideBranding":{"type":"boolean","description":"Paid plans may hide JetEmail branding."},"optInMode":{"type":"string","enum":["single","double"],"default":"single"},"pendingMessage":{"type":"string","maxLength":300},"confirmationFromName":{"type":"string","maxLength":64},"confirmationFromEmail":{"type":"string","format":"email","maxLength":320,"description":"Verified sender required for double opt-in."},"confirmationSubject":{"type":"string","maxLength":200},"confirmationMessage":{"type":"string","maxLength":500},"confirmationButtonLabel":{"type":"string","maxLength":80},"confirmationRedirectUrl":{"type":"string","format":"uri","maxLength":2048},"autoProtection":{"type":"boolean","default":true}}},"MarketingSignupFormInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"example":"Website newsletter"},"audienceId":{"type":"string","description":"Owned audience that successful submissions join."},"status":{"type":"string","enum":["active","paused"],"default":"active"},"fields":{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/MarketingSignupFormField"}},"settings":{"$ref":"#/components/schemas/MarketingSignupFormSettings"},"turnstileEnabled":{"type":"boolean","default":false},"turnstileSiteKey":{"type":"string","maxLength":200,"description":"Cloudflare Turnstile widget site key. Required when Turnstile is enabled."},"turnstileSecretKey":{"type":"string","maxLength":500,"writeOnly":true,"description":"Cloudflare Turnstile secret. Required when enabling CAPTCHA or changing the site key."}}},"MarketingSignupForm":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Private management identifier."},"public_id":{"type":"string","pattern":"^form_[A-Za-z0-9_-]{20,64}$","example":"form_oCiNpdGJPDhgV4kFa6t1jeoF"},"name":{"type":"string","maxLength":100,"example":"Website newsletter"},"status":{"type":"string","enum":["active","paused"]},"audience_id":{"type":"string"},"audience_name":{"type":"string"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/MarketingSignupFormField"}},"settings":{"$ref":"#/components/schemas/MarketingSignupFormSettings"},"turnstile_enabled":{"type":"integer","enum":[0,1]},"turnstile_site_key":{"type":"string","maxLength":200},"turnstile_configured":{"type":"boolean","description":"Whether Turnstile is configured."},"subscriber_count":{"type":"integer","description":"Current subscribers in the selected audience."},"opt_in_mode":{"type":"string","enum":["single","double"]},"recent_attempt_count":{"type":"integer"},"recent_blocked_count":{"type":"integer"},"pending_confirmation_count":{"type":"integer"},"form_url":{"type":"string","format":"uri","example":"https://api.jetemail.com/forms/form_oCiNpdGJPDhgV4kFa6t1jeoF"},"created_at":{"type":"integer","description":"Unix seconds."},"updated_at":{"type":"integer","description":"Unix seconds."}}},"PublicSignupFormSubmission":{"type":"object","required":["email"],"additionalProperties":{"type":"string","maxLength":1000},"description":"Configured custom fields are accepted as additional string properties using their field keys.","properties":{"email":{"type":"string","format":"email","maxLength":320},"firstName":{"type":"string","maxLength":64},"lastName":{"type":"string","maxLength":64},"consent":{"type":"string","enum":["yes","true","1","on"],"description":"Required when the form configuration requires consent."},"cf-turnstile-response":{"type":"string","maxLength":2048,"description":"Required when Turnstile is enabled."}}},"PublicSignupFormResult":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"You're subscribed. Thanks for joining!"},"redirect":{"type":"string","format":"uri","description":"Present when a success redirect is configured."}}},"PublicSignupFormError":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Enter a valid email address."}}},"MarketingAssetReferences":{"type":"object","properties":{"total":{"type":"integer"},"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}},"DmarcError":{"type":"object","required":["error"],"properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid domain"},"code":{"type":"string","example":"invalid_domain"},"details":{"type":"string"}}},"DmarcDnsConfiguration":{"type":"object","required":["host","type","value","verified","lastCheckedAt"],"properties":{"host":{"type":"string","example":"_dmarc.example.com"},"type":{"type":"string","enum":["TXT"],"example":"TXT"},"value":{"type":"string","example":"v=DMARC1; p=none; rua=mailto:5e2f617ea64848ab9073@rua.jetsmtp.net"},"verified":{"type":"boolean","example":true},"lastCheckedAt":{"type":"integer","format":"int64","nullable":true,"description":"Unix timestamp in seconds, or null if DNS has not been checked.","example":1786248000}}},"DmarcDomain":{"type":"object","required":["uuid","domain","status","logLocation","ruaAddress","dns","verifiedAt","createdAt","updatedAt"],"properties":{"uuid":{"type":"string","format":"uuid","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"},"domain":{"type":"string","format":"hostname","example":"example.com"},"status":{"type":"string","enum":["pending","verified","disabled"],"example":"verified"},"logLocation":{"type":"string","enum":["au","us","eu"],"example":"au"},"ruaAddress":{"type":"string","format":"email","example":"5e2f617ea64848ab9073@rua.jetsmtp.net"},"dns":{"$ref":"#/components/schemas/DmarcDnsConfiguration"},"verifiedAt":{"type":"integer","format":"int64","nullable":true,"description":"Unix timestamp in seconds."},"createdAt":{"type":"integer","format":"int64","description":"Unix timestamp in seconds."},"updatedAt":{"type":"integer","format":"int64","description":"Unix timestamp in seconds."}}},"DmarcReportSummary":{"type":"object","required":["report_key","domain_uuid","policy_domain","schema_version","reporter_org_name","reporter_email","external_report_id","report_begin","report_end","policy_p","policy_sp","policy_np","policy_adkim","policy_aspf","policy_pct","record_count","total_messages","pass_messages","fail_messages","disposition_none","disposition_quarantine","disposition_reject","received_at"],"properties":{"report_key":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Stable SHA-256 identifier for the normalized aggregate report."},"domain_uuid":{"type":"string","format":"uuid"},"policy_domain":{"type":"string","format":"hostname","example":"example.com"},"schema_version":{"type":"string","example":"1.0"},"reporter_org_name":{"type":"string","example":"Google Inc."},"reporter_email":{"type":"string","example":"noreply-dmarc-support@google.com"},"external_report_id":{"type":"string","example":"1234567890123456789"},"report_begin":{"type":"integer","format":"int64","description":"Beginning of the report interval as Unix seconds."},"report_end":{"type":"integer","format":"int64","description":"End of the report interval as Unix seconds."},"policy_p":{"type":"string","example":"reject"},"policy_sp":{"type":"string","example":"reject"},"policy_np":{"type":"string","example":"reject"},"policy_adkim":{"type":"string","example":"r"},"policy_aspf":{"type":"string","example":"r"},"policy_pct":{"type":"integer","minimum":0,"maximum":100,"example":100},"record_count":{"type":"integer","format":"int32","minimum":0,"example":12},"total_messages":{"type":"integer","format":"int64","minimum":0,"example":1842},"pass_messages":{"type":"integer","format":"int64","minimum":0,"example":1800},"fail_messages":{"type":"integer","format":"int64","minimum":0,"example":42},"disposition_none":{"type":"integer","format":"int64","minimum":0,"example":1800},"disposition_quarantine":{"type":"integer","format":"int64","minimum":0,"example":12},"disposition_reject":{"type":"integer","format":"int64","minimum":0,"example":30},"received_at":{"type":"integer","format":"int64","description":"Time the aggregate email was received as Unix milliseconds."}}},"DmarcReportDetail":{"allOf":[{"$ref":"#/components/schemas/DmarcReportSummary"},{"type":"object","properties":{"dmarc_id":{"type":"string","description":"Private identifier used in the RUA address."},"reporter_extra_contact_info":{"type":"string"},"reporter_generator":{"type":"string"},"report_errors":{"type":"array","items":{"type":"string"}},"policy_discovery_method":{"type":"string"},"policy_fo":{"type":"string"},"policy_testing":{"type":"string"},"recipient":{"type":"string","format":"email"},"peer_ip":{"type":"string","description":"SMTP peer IP address."},"mail_from":{"type":"string"},"header_from":{"type":"string"},"message_id":{"type":"string"},"subject":{"type":"string"},"tls":{"type":"integer","enum":[0,1],"description":"Whether SMTP transport used TLS."},"attachment_filename":{"type":"string"},"attachment_content_type":{"type":"string"},"compressed_bytes":{"type":"integer","format":"int64","minimum":0},"decompressed_bytes":{"type":"integer","format":"int64","minimum":0},"report_extensions_xml":{"type":"string"},"raw_xml":{"type":"string","description":"Original decompressed aggregate report XML."},"raw_xml_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$"}}}]},"DmarcRecord":{"type":"object","properties":{"record_key":{"type":"string"},"source_ip":{"type":"string","example":"192.0.2.10"},"message_count":{"type":"integer","format":"int64","minimum":0,"example":125},"disposition":{"type":"string","enum":["none","quarantine","reject"]},"dkim":{"type":"string","example":"pass"},"spf":{"type":"string","example":"pass"},"policy_reason_types":{"type":"array","items":{"type":"string"}},"policy_reason_comments":{"type":"array","items":{"type":"string"}},"header_from":{"type":"string","format":"hostname"},"envelope_from":{"type":"string"},"envelope_to":{"type":"string"},"dkim_domains":{"type":"array","items":{"type":"string"}},"dkim_selectors":{"type":"array","items":{"type":"string"}},"dkim_results":{"type":"array","items":{"type":"string"}},"dkim_human_results":{"type":"array","items":{"type":"string"}},"spf_domains":{"type":"array","items":{"type":"string"}},"spf_scopes":{"type":"array","items":{"type":"string"}},"spf_results":{"type":"array","items":{"type":"string"}},"spf_human_results":{"type":"array","items":{"type":"string"}},"extensions_xml":{"type":"string"}}},"DmarcMetricTotals":{"type":"object","properties":{"total_messages":{"type":"integer","format":"int64","minimum":0},"pass_messages":{"type":"integer","format":"int64","minimum":0},"fail_messages":{"type":"integer","format":"int64","minimum":0},"dkim_pass_messages":{"type":"integer","format":"int64","minimum":0},"dkim_fail_messages":{"type":"integer","format":"int64","minimum":0},"spf_pass_messages":{"type":"integer","format":"int64","minimum":0},"spf_fail_messages":{"type":"integer","format":"int64","minimum":0},"disposition_none":{"type":"integer","format":"int64","minimum":0},"disposition_quarantine":{"type":"integer","format":"int64","minimum":0},"disposition_reject":{"type":"integer","format":"int64","minimum":0},"report_count":{"type":"integer","format":"int64","minimum":0}}},"DmarcDailyMetric":{"type":"object","properties":{"date":{"type":"string","format":"date","example":"2026-08-09"},"total_messages":{"type":"integer","format":"int64","minimum":0},"pass_messages":{"type":"integer","format":"int64","minimum":0},"fail_messages":{"type":"integer","format":"int64","minimum":0},"dkim_pass_messages":{"type":"integer","format":"int64","minimum":0},"dkim_fail_messages":{"type":"integer","format":"int64","minimum":0},"spf_pass_messages":{"type":"integer","format":"int64","minimum":0},"spf_fail_messages":{"type":"integer","format":"int64","minimum":0}}},"DmarcSourceMetric":{"type":"object","properties":{"source_key":{"type":"string","example":"google-workspace"},"source_name":{"type":"string","example":"Google Workspace"},"source_type":{"type":"string","enum":["provider","unknown_network"]},"source_ip":{"type":"string","example":"192.0.2.10"},"source_ips":{"type":"array","items":{"type":"string"}},"total_messages":{"type":"integer","format":"int64","minimum":0},"pass_messages":{"type":"integer","format":"int64","minimum":0},"fail_messages":{"type":"integer","format":"int64","minimum":0},"dkim_pass_messages":{"type":"integer","format":"int64","minimum":0},"dkim_fail_messages":{"type":"integer","format":"int64","minimum":0},"spf_pass_messages":{"type":"integer","format":"int64","minimum":0},"spf_fail_messages":{"type":"integer","format":"int64","minimum":0},"header_from_domains":{"type":"array","items":{"type":"string"}},"dkim_domains":{"type":"array","items":{"type":"string"}},"spf_domains":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["healthy","needs_attention","unreviewed"]},"recommendation":{"type":"string"}}},"DmarcPolicyMetric":{"type":"object","properties":{"policy_domain":{"type":"string","format":"hostname"},"policy_p":{"type":"string"},"policy_sp":{"type":"string"},"policy_np":{"type":"string"},"policy_adkim":{"type":"string"},"policy_aspf":{"type":"string"},"policy_pct":{"type":"integer","minimum":0,"maximum":100},"received_at":{"type":"integer","format":"int64","description":"Unix milliseconds."}}}}},"security":[{"apiKeyAuth":[]}],"servers":[{"url":"https://api.jetemail.com","description":"Production"}],"tags":[{"name":"Email","description":"Send transactional email"},{"name":"Outbound","description":"Outbound sending: keys, SMTP users, domains, logs, suppression"},{"name":"Inbound","description":"Inbound routing, domains and forward destinations"},{"name":"DMARC","description":"DMARC aggregate-report domain setup, DNS verification and analytics"},{"name":"Marketing","description":"Marketing suite: templates, audiences, contacts, broadcasts, themes, assets and signup forms"},{"name":"Signup Forms","description":"Hosted signup pages and form submissions"}],"paths":{"/dmarc/domains":{"get":{"tags":["DMARC"],"summary":"List monitored DMARC domains","description":"Returns the active DMARC monitoring registrations owned by the current user or organization.","responses":{"200":{"description":"DMARC domains retrieved successfully","content":{"application/json":{"schema":{"type":"object","required":["success","domains"],"properties":{"success":{"type":"boolean","example":true},"domains":{"type":"array","items":{"$ref":"#/components/schemas/DmarcDomain"}}}}}}},"401":{"description":"Unauthorized or account log storage is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"500":{"description":"Failed to load DMARC domains","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}},"post":{"tags":["DMARC"],"summary":"Add a DMARC monitoring domain","description":"Creates a private aggregate-reporting address for a domain. Reports for covered subdomains may use the same RUA destination. The domain is normalized to lowercase and a trailing root dot is removed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"additionalProperties":false,"properties":{"domain":{"type":"string","format":"hostname","maxLength":254,"pattern":"^(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+(?:[A-Za-z]{2,63}|xn--[A-Za-z0-9-]{1,59})\\.?$","example":"example.com"}}}}}},"responses":{"201":{"description":"DMARC domain created","content":{"application/json":{"schema":{"type":"object","required":["success","domain"],"properties":{"success":{"type":"boolean","example":true},"domain":{"$ref":"#/components/schemas/DmarcDomain"}}}}}},"400":{"description":"Malformed JSON or invalid domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized or account log storage is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"403":{"description":"DMARC domain limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"409":{"description":"Domain is already registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"500":{"description":"Failed to create the DMARC domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}}},"/dmarc/domains/{uuid}":{"get":{"tags":["DMARC"],"summary":"Get a monitored DMARC domain","parameters":[{"name":"uuid","in":"path","required":true,"description":"DMARC domain registration UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"DMARC domain retrieved successfully","content":{"application/json":{"schema":{"type":"object","required":["success","domain"],"properties":{"success":{"type":"boolean","example":true},"domain":{"$ref":"#/components/schemas/DmarcDomain"}}}}}},"400":{"description":"Invalid domain UUID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"404":{"description":"DMARC domain not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"500":{"description":"Failed to load the DMARC domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}},"delete":{"tags":["DMARC"],"summary":"Remove a DMARC monitoring domain","description":"Soft-deletes the registration and disables acceptance of new reports sent to its private RUA address.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"DMARC domain removed","content":{"application/json":{"schema":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Invalid domain UUID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"404":{"description":"DMARC domain not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"500":{"description":"Failed to remove the DMARC domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}}},"/dmarc/domains/{uuid}/check":{"post":{"tags":["DMARC"],"summary":"Check DMARC reporting DNS","description":"Looks up the domain DMARC TXT record and verifies that its rua tag contains the assigned JetEmail aggregate-reporting address.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"DNS check completed; inspect verified for the result","content":{"application/json":{"schema":{"type":"object","required":["success","verified","dns"],"properties":{"success":{"type":"boolean","example":true},"verified":{"type":"boolean","example":true},"dns":{"type":"object","required":["host","type","expected","found"],"properties":{"host":{"type":"string","example":"_dmarc.example.com"},"type":{"type":"string","enum":["TXT"]},"expected":{"type":"string","example":"v=DMARC1; p=none; rua=mailto:5e2f617ea64848ab9073@rua.jetsmtp.net"},"found":{"type":"string","nullable":true,"description":"Published TXT value, or null when no record was found."}}}}}}}},"400":{"description":"Invalid domain UUID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"404":{"description":"DMARC domain not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"500":{"description":"DNS lookup or persistence failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}}},"/dmarc/metrics":{"get":{"tags":["DMARC"],"summary":"Get DMARC aggregate metrics","description":"Returns message-weighted DMARC, aligned DKIM, aligned SPF, disposition, daily trend, and sending-source metrics. The default interval is the last 30 days.","parameters":[{"name":"domain_uuid","in":"query","required":false,"description":"Limit metrics to one owned DMARC domain registration.","schema":{"type":"string","format":"uuid"}},{"name":"date_from","in":"query","required":false,"description":"Inclusive interval start as Unix seconds. Defaults to 30 days ago.","schema":{"type":"integer","format":"int64","minimum":0}},{"name":"date_to","in":"query","required":false,"description":"Inclusive interval end as Unix seconds. Defaults to now.","schema":{"type":"integer","format":"int64","minimum":0}}],"responses":{"200":{"description":"DMARC aggregate metrics","content":{"application/json":{"schema":{"type":"object","required":["totals","daily","top_sources","latest_policy"],"properties":{"totals":{"$ref":"#/components/schemas/DmarcMetricTotals"},"daily":{"type":"array","items":{"$ref":"#/components/schemas/DmarcDailyMetric"}},"top_sources":{"type":"array","items":{"$ref":"#/components/schemas/DmarcSourceMetric"}},"latest_policy":{"allOf":[{"$ref":"#/components/schemas/DmarcPolicyMetric"}],"nullable":true}}}}}},"400":{"description":"Invalid domain UUID or date range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"503":{"description":"Regional DMARC metrics service is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}}},"/dmarc/reports":{"get":{"tags":["DMARC"],"summary":"List DMARC aggregate reports","description":"Returns paginated aggregate-report summaries from the account regional log store. The default order is newest first.","parameters":[{"name":"domain_uuid","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"date_from","in":"query","required":false,"description":"Inclusive interval start as Unix seconds. Defaults to 30 days ago.","schema":{"type":"integer","format":"int64","minimum":0,"maximum":4102444800}},{"name":"date_to","in":"query","required":false,"description":"Inclusive interval end as Unix seconds. Defaults to now.","schema":{"type":"integer","format":"int64","minimum":0,"maximum":4102444800}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":10000000,"default":0}},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Paginated DMARC aggregate reports","content":{"application/json":{"schema":{"type":"object","required":["reports","total"],"properties":{"reports":{"type":"array","items":{"$ref":"#/components/schemas/DmarcReportSummary"}},"total":{"type":"integer","format":"int64","minimum":0}}}}}},"400":{"description":"Invalid domain UUID, date range, or pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"503":{"description":"Regional DMARC report service is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}}},"/dmarc/reports/{reportKey}":{"get":{"tags":["DMARC"],"summary":"Get a DMARC aggregate report","description":"Returns complete report metadata, transport details, published policy, raw aggregate XML, and a paginated set of normalized authentication records.","parameters":[{"name":"reportKey","in":"path","required":true,"description":"64-character hexadecimal report key.","schema":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":2000,"default":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Complete DMARC aggregate report","content":{"application/json":{"schema":{"type":"object","required":["success","report","records","total"],"properties":{"success":{"type":"boolean","example":true},"report":{"$ref":"#/components/schemas/DmarcReportDetail"},"records":{"type":"array","items":{"$ref":"#/components/schemas/DmarcRecord"}},"total":{"type":"integer","format":"int64","minimum":0}}}}}},"400":{"description":"Invalid report key or pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"404":{"description":"DMARC report not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}},"503":{"description":"Regional DMARC report service is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DmarcError"}}}}}}},"/marketing/templates":{"get":{"tags":["Marketing"],"summary":"List email templates","description":"Lists the account's marketing email templates. Passing `page` or `limit` switches to a paginated response: rows exclude the body fields (blocks, styles, html, text), optional `q`/`tags` filters apply across all templates, and the response gains `pagination` and `tag_counts` objects.","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Page number (enables pagination)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page (enables pagination)"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by name or subject substring (paginated mode only)"},{"name":"tags","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated tags; matches templates having any of them (paginated mode only)"}],"responses":{"200":{"description":"Templates","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"templates":{"type":"array","items":{"$ref":"#/components/schemas/MarketingTemplate"}},"pagination":{"type":"object","description":"Present in paginated mode","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total_count":{"type":"integer"},"has_next_page":{"type":"boolean"},"showing_from":{"type":"integer"},"showing_to":{"type":"integer"}}},"tag_counts":{"type":"object","description":"Present in paginated mode: account-wide per-tag row counts","additionalProperties":{"type":"integer"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create a template","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketingTemplateInput"}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}}}}}}}}},"/marketing/templates/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Get a template","responses":{"200":{"description":"Template","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"template":{"$ref":"#/components/schemas/MarketingTemplate"}}}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Marketing"],"summary":"Update a template","description":"Only the fields present in the body are updated.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketingTemplateInput"}}}},"responses":{"200":{"description":"Updated"},"404":{"description":"Not found"}}},"delete":{"tags":["Marketing"],"summary":"Delete a template","responses":{"200":{"description":"Deleted"}}}},"/marketing/fields":{"get":{"tags":["Marketing"],"summary":"List custom merge fields","responses":{"200":{"description":"Fields","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/MarketingField"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create a custom merge field","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["key"],"properties":{"key":{"type":"string","example":"companyName"},"label":{"type":"string","example":"Company name"}}}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"field":{"$ref":"#/components/schemas/MarketingField"}}}}}}}}},"/marketing/fields/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["Marketing"],"summary":"Delete a custom field","responses":{"200":{"description":"Deleted"}}}},"/marketing/themes":{"get":{"tags":["Marketing"],"summary":"List themes","description":"Reusable global style sets that can be applied across templates.","responses":{"200":{"description":"Themes","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"themes":{"type":"array","items":{"$ref":"#/components/schemas/MarketingTheme"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create a theme","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"styles":{"type":"object","description":"EmailStyles"}}}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"theme":{"$ref":"#/components/schemas/MarketingTheme"}}}}}}}}},"/marketing/themes/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Get a theme","responses":{"200":{"description":"Theme","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"theme":{"$ref":"#/components/schemas/MarketingTheme"}}}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Marketing"],"summary":"Update a theme","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"styles":{"type":"object"}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Marketing"],"summary":"Delete a theme","responses":{"200":{"description":"Deleted"}}}},"/marketing/audiences":{"get":{"tags":["Marketing"],"summary":"List audiences","responses":{"200":{"description":"Audiences","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"audiences":{"type":"array","items":{"$ref":"#/components/schemas/MarketingAudience"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create an audience","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}}}}}}}}},"/marketing/audiences/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Get an audience","responses":{"200":{"description":"Audience","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"audience":{"$ref":"#/components/schemas/MarketingAudience"}}}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Marketing"],"summary":"Update an audience","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Marketing"],"summary":"Delete an audience","description":"Removes the audience and its memberships (contacts are not deleted).","responses":{"200":{"description":"Deleted"}}}},"/marketing/audiences/{id}/contacts":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"List an audience’s contacts","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":1000,"maximum":5000}}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/MarketingContact"}}}}}}},"404":{"description":"Audience not found"}}},"post":{"tags":["Marketing"],"summary":"Add existing contacts to an audience","description":"Links existing contacts (by id) to the audience. Idempotent; only contacts owned by the account are added.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contactIds"],"properties":{"contactIds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Added","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"added":{"type":"integer"}}}}}},"404":{"description":"Audience not found"}}},"delete":{"tags":["Marketing"],"summary":"Remove a contact from an audience","description":"Unlinks a contact from the audience (the contact itself is not deleted).","parameters":[{"name":"contactId","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Removed"},"404":{"description":"Audience not found"}}}},"/marketing/forms":{"get":{"tags":["Marketing"],"summary":"List signup forms","description":"Returns the account’s signup forms.","responses":{"200":{"description":"Signup forms","content":{"application/json":{"schema":{"type":"object","required":["success","forms"],"properties":{"success":{"type":"boolean","example":true},"forms":{"type":"array","items":{"$ref":"#/components/schemas/MarketingSignupForm"}}}}}}},"401":{"description":"Missing or invalid Bearer token"},"500":{"description":"Unable to list forms"}}},"post":{"tags":["Marketing"],"summary":"Create a signup form","description":"Creates a signup form for an audience. Turnstile credentials are required when CAPTCHA is enabled.","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/MarketingSignupFormInput"},{"type":"object","required":["name","audienceId"]}]}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","required":["success","id","public_id","form_url"],"properties":{"success":{"type":"boolean","example":true},"id":{"type":"string","format":"uuid"},"public_id":{"type":"string","example":"form_oCiNpdGJPDhgV4kFa6t1jeoF"},"form_url":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid name, audience, field configuration or Turnstile credentials"},"401":{"description":"Missing or invalid Bearer token"},"500":{"description":"Unable to create the form"},"503":{"description":"Service temporarily unavailable"}}}},"/marketing/forms/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Private form management identifier."}],"get":{"tags":["Marketing"],"summary":"Get a signup form","description":"Returns a signup form and its configuration.","responses":{"200":{"description":"Signup form","content":{"application/json":{"schema":{"type":"object","required":["success","form"],"properties":{"success":{"type":"boolean","example":true},"form":{"$ref":"#/components/schemas/MarketingSignupForm"}}}}}},"401":{"description":"Missing or invalid Bearer token"},"404":{"description":"Form not found"}}},"patch":{"tags":["Marketing"],"summary":"Update a signup form","description":"Updates a signup form.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketingSignupFormInput"}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid form, audience, field or Turnstile configuration"},"401":{"description":"Missing or invalid Bearer token"},"404":{"description":"Form not found"},"503":{"description":"Service temporarily unavailable"}}},"delete":{"tags":["Marketing"],"summary":"Delete a signup form","description":"Deletes a signup form.","responses":{"200":{"description":"Deleted"},"401":{"description":"Missing or invalid Bearer token"},"404":{"description":"Form not found"}}}},"/marketing/forms/{id}/health":{"get":{"tags":["Marketing"],"summary":"Get signup form health","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Form health summary","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"risk":{"type":"string","enum":["healthy","guarded","elevated","critical"]},"lastHour":{"type":"object","properties":{"attempts":{"type":"integer"},"blocked":{"type":"integer"}}},"last24Hours":{"type":"object","properties":{"attempts":{"type":"integer"},"blocked":{"type":"integer"}}},"pendingConfirmations":{"type":"integer"},"confirmationRate7d":{"type":"number","nullable":true},"registrationProtection":{"type":"object","properties":{"paused":{"type":"boolean"},"restricted":{"type":"boolean"},"pausedUntil":{"type":"integer","nullable":true},"restrictedUntil":{"type":"integer","nullable":true},"dailyCap":{"type":"integer"},"usedToday":{"type":"integer"},"reason":{"type":"string","nullable":true},"ticketId":{"type":"string","nullable":true}}},"outcomes24h":{"type":"object","additionalProperties":{"type":"integer"}},"hourly":{"type":"array","items":{"type":"object","properties":{"bucket":{"type":"integer"},"attempts":{"type":"integer"},"blocked":{"type":"integer"}}}}}}}}},"401":{"description":"Missing or invalid Bearer token"},"404":{"description":"Form not found"}}}},"/forms/{publicId}":{"parameters":[{"name":"publicId","in":"path","required":true,"schema":{"type":"string","pattern":"^form_[A-Za-z0-9_-]{20,64}$"},"example":"form_oCiNpdGJPDhgV4kFa6t1jeoF"}],"get":{"tags":["Signup Forms"],"summary":"Display a hosted signup form","description":"Returns the hosted signup form as HTML.","security":[],"parameters":[{"name":"success","in":"query","required":false,"schema":{"type":"string","enum":["1","pending"]},"description":"Render a submitted or pending-confirmation state."}],"responses":{"200":{"description":"Hosted form HTML","content":{"text/html":{"schema":{"type":"string"}}}},"404":{"description":"Form does not exist or is paused","content":{"text/html":{"schema":{"type":"string"}}}},"503":{"description":"Form service unavailable","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["Signup Forms"],"summary":"Submit a public signup form","description":"Submits signup details. Supports JSON and browser form submissions; a Turnstile response may be required.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormSubmission"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/PublicSignupFormSubmission"}},"multipart/form-data":{"schema":{"$ref":"#/components/schemas/PublicSignupFormSubmission"}}}},"responses":{"200":{"description":"Submission accepted; returned for JSON clients","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormResult"}}}},"303":{"description":"Submission accepted; browser redirected to the next form state","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"400":{"description":"Invalid field, missing consent or failed Turnstile challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"402":{"description":"Subscription unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"403":{"description":"Submission not permitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"404":{"description":"Form does not exist or is paused","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"413":{"description":"Request body exceeds 64 KiB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"429":{"description":"Too many requests","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"500":{"description":"Submission failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}},"503":{"description":"Service temporarily unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSignupFormError"}},"text/html":{"schema":{"type":"string"}}}}}},"options":{"tags":["Signup Forms"],"summary":"Get signup-form CORS policy","description":"Returns the supported request options.","security":[],"responses":{"204":{"description":"CORS preflight accepted"}}}},"/forms/confirm/{token}":{"get":{"tags":["Signup Forms"],"summary":"Confirm a signup","security":[],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","minLength":40,"maxLength":128}}],"responses":{"200":{"description":"Confirmation result","content":{"text/html":{"schema":{"type":"string"}}}},"303":{"description":"Confirmed and redirected","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"404":{"description":"Confirmation not available","content":{"text/html":{"schema":{"type":"string"}}}},"410":{"description":"Confirmation expired","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/marketing/contacts":{"get":{"tags":["Marketing"],"summary":"List contacts","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":500,"maximum":1000}}],"responses":{"200":{"description":"Contacts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/MarketingContact"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create or update a contact","description":"Upserts by email within the account. A contact must belong to at least one audience, so audienceIds is required and non-empty.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","audienceIds"],"properties":{"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"attributes":{"type":"object","description":"Custom merge fields"},"status":{"type":"string","enum":["subscribed","unsubscribed"]},"audienceIds":{"type":"array","items":{"type":"string"},"minItems":1,"description":"At least one audience (required)"}}}}}},"responses":{"200":{"description":"Upserted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}}}}}},"400":{"description":"Invalid email or no audience provided"}}}},"/marketing/contacts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Get a contact","description":"Returns the contact plus its audience membership (audienceIds).","responses":{"200":{"description":"Contact","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contact":{"$ref":"#/components/schemas/MarketingContact"}}}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Marketing"],"summary":"Update / unsubscribe a contact","description":"Update name, merge attributes, status, and audience membership. Setting status=\"unsubscribed\" stamps unsubscribedAt; resubscribing (status=\"subscribed\") re-checks the plan subscriber cap. Supplying audienceIds replaces the full membership set.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"attributes":{"type":"object","description":"Custom merge fields"},"status":{"type":"string","enum":["subscribed","unsubscribed","bounced","complained"]},"audienceIds":{"type":"array","items":{"type":"string"},"description":"Desired full audience membership"}}}}}},"responses":{"200":{"description":"Updated"},"402":{"description":"Subscriber limit reached (on resubscribe)"},"404":{"description":"Not found"}}},"delete":{"tags":["Marketing"],"summary":"Delete a contact","description":"Hard-deletes the contact and its audience memberships.","responses":{"200":{"description":"Deleted"},"404":{"description":"Not found"}}}},"/marketing/contacts/import":{"post":{"tags":["Marketing"],"summary":"Bulk import contacts","description":"Upserts contacts by email within the account. New subscribed contacts count toward the plan subscriber cap; once hit, remaining new contacts are skipped (reported, not fatal). Does NOT emit workflow trigger events — importing a list should not enroll everyone into automations.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contacts","audienceIds"],"properties":{"contacts":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"attributes":{"type":"object"},"status":{"type":"string","enum":["subscribed","unsubscribed"]}}}},"audienceIds":{"type":"array","items":{"type":"string"},"minItems":1,"description":"At least one audience — every imported contact is added to these (required)"}}}}}},"responses":{"200":{"description":"Import summary","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"added":{"type":"integer"},"updated":{"type":"integer"},"skipped":{"type":"integer"},"skippedInvalid":{"type":"integer"},"skippedLimit":{"type":"integer"}}}}}},"400":{"description":"No rows / too many rows / no audience"}}}},"/marketing/contacts/export":{"get":{"tags":["Marketing"],"summary":"Export contacts","description":"Returns contacts (name, status, merge attributes, dates) as JSON for CSV export. With ?audienceId, scopes to that audience’s members.","parameters":[{"name":"audienceId","in":"query","schema":{"type":"string"},"description":"Scope the export to one audience"}],"responses":{"200":{"description":"Contacts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/MarketingContact"}}}}}}}}}},"/marketing/broadcasts":{"get":{"tags":["Marketing"],"summary":"List broadcasts","responses":{"200":{"description":"Broadcasts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"broadcasts":{"type":"array","items":{"$ref":"#/components/schemas/MarketingBroadcast"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create / send / schedule a broadcast","description":"status=\"draft\" saves without sending. status=\"sending\" dispatches now, or holds until scheduledAt if provided. Dispatch resolves recipients from the audience (subscribed contacts only) and snapshots the template, so later template edits do not affect the send. Marketing sends are metered separately from Outbound (free tier 3000/month).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"templateId":{"type":"string"},"audienceId":{"type":"string","description":"Target audience id (required to send)"},"fromName":{"type":"string"},"fromEmail":{"type":"string"},"subject":{"type":"string","description":"Overrides the template subject. Stored with its merge tokens intact and rendered per recipient at send time, from the contact's fields.","example":"A gift for you, {{firstName | friend}}"},"status":{"type":"string","enum":["draft","sending"]},"scheduledAt":{"type":"string","format":"date-time","description":"ISO timestamp; when set with status=sending the broadcast is scheduled"}}}}}},"responses":{"200":{"description":"Created/dispatched","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"},"recipientCount":{"type":"integer"}}}}}}}}},"/marketing/broadcasts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Get a broadcast","responses":{"200":{"description":"Broadcast","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"broadcast":{"$ref":"#/components/schemas/MarketingBroadcast"}}}}}},"404":{"description":"Not found"}}},"delete":{"tags":["Marketing"],"summary":"Delete a draft/scheduled broadcast","description":"Only draft or scheduled broadcasts can be deleted.","responses":{"200":{"description":"Deleted"},"404":{"description":"Not found or already sending"}}}},"/marketing/test-send":{"post":{"tags":["Marketing"],"summary":"Send a test email","description":"Sends a one-off test email. sampleData fills merge tokens for the preview. Does not count toward quota. Limited to 10 test emails per marketing account in a 24-hour window.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to","fromEmail"],"properties":{"to":{"type":"string"},"subject":{"type":"string","description":"Merge tokens here are rendered from sampleData, same as the body."},"html":{"type":"string"},"text":{"type":"string"},"fromName":{"type":"string"},"fromEmail":{"type":"string"},"replyTo":{"type":"string"},"sampleData":{"type":"object","description":"Values for the merge tokens used in the subject, html and text. Omitted tokens render as their fallback, or empty.","example":{"firstName":"Jane"}}}}}}},"responses":{"200":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string","description":"Queued send job id"}}}}}},"429":{"description":"The marketing account has reached its 10 test emails per 24-hour limit."}}}},"/marketing/transactional":{"post":{"tags":["Marketing"],"summary":"Send a transactional email","description":"Sends one email from a marketing template to a single recipient, personalised with dataVariables. Intended for functional messages (password resets, receipts, confirmations): no unsubscribe link, no open or click tracking, and delivery does not depend on the recipient's subscription status.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transactionalId","email"],"properties":{"transactionalId":{"type":"string","description":"Template id to send"},"email":{"type":"string","description":"Recipient","example":"jane@example.com"},"dataVariables":{"type":"object","description":"Merge values for {{firstName}}, {{resetUrl}}, custom fields, … Applied to the subject line as well as the HTML and text bodies. A token with no value falls back to its `{{key | fallback}}` text, or renders empty.","example":{"firstName":"Jane","resetUrl":"https://app.example.com/reset/abc"}},"subject":{"type":"string","description":"Overrides the template subject. Merge tokens are substituted from dataVariables, so `Your {{plan}} receipt` is personalised per send.","example":"Your {{plan}} receipt"},"fromName":{"type":"string","description":"Overrides the template sender name"},"fromEmail":{"type":"string","description":"Overrides the template from address. Defaults to the template sender if omitted. Must be on a verified sending domain."},"replyTo":{"type":"string","description":"Overrides the template reply-to"},"addToAudience":{"type":"boolean","description":"Upsert the recipient as a contact"},"audienceIds":{"type":"array","items":{"type":"string"},"description":"Audiences to add the contact to (with addToAudience)"},"attachments":{"type":"array","description":"Optional file attachments, 25 MB total. Same shape as /email: filename plus base64-encoded data.","items":{"type":"object","required":["filename","data"],"properties":{"filename":{"type":"string","maxLength":255},"data":{"type":"string","description":"Base64-encoded file content"}}}}}}}}},"responses":{"200":{"description":"Sent","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string","description":"Send id"},"messageId":{"type":"string"}}}}}},"400":{"description":"Missing/invalid email or transactionalId, or the message was rejected"},"402":{"description":"Requires a paid marketing plan"},"404":{"description":"Template not found"},"503":{"description":"Temporarily unable to send; safe to retry (response includes retryable: true)"}}}},"/marketing/events":{"post":{"tags":["Marketing"],"summary":"Send a custom event","description":"Records a custom event (\"user did X\") for a contact. Call it server-to-server with an API key from your backend when something happens in your app (signup, purchase, upgrade, …). Any active workflow whose trigger is that event name enrolls the contact. If the email isn't a known contact yet, the event is still recorded and matched once the contact exists. Fire-and-forget — a 200 means the event was accepted, not that a workflow ran. Event names may not contain a colon.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","name"],"properties":{"email":{"type":"string","description":"The contact this event is about","example":"jane@example.com"},"name":{"type":"string","description":"Event name — must match a workflow trigger to do anything","example":"purchase_completed"},"properties":{"type":"object","description":"Arbitrary metadata for the event (available to the workflow)","example":{"plan":"pro","amount":4900}}}}}}},"responses":{"200":{"description":"Event accepted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"description":"Missing/invalid email or name (or name contains a colon)"}}}},"/marketing/workflows":{"get":{"tags":["Marketing"],"summary":"List workflows","responses":{"200":{"description":"Workflows","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"workflows":{"type":"array","items":{"$ref":"#/components/schemas/MarketingWorkflow"}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Create a workflow","description":"Creates an automation (draft). The trigger declares what starts it — including { type:\"event\", config:{ name } } for custom events; the graph is the ordered node list (emails + delays).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"trigger":{"type":"object","description":"{ type, config } — e.g. { type:\"event\", config:{ name:\"signup\" } }"},"graph":{"type":"object","description":"{ entry, nodes }"},"reentry":{"type":"string","enum":["once","after_complete","always"]}}}}}},"responses":{"200":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"id":{"type":"string"}}}}}}}}},"/marketing/workflows/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Get a workflow","responses":{"200":{"description":"Workflow","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"workflow":{"$ref":"#/components/schemas/MarketingWorkflow"}}}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Marketing"],"summary":"Update a workflow","description":"Update name/trigger/graph/reentry, or set status. Activating (status=\"active\") publishes a new version.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"trigger":{"type":"object"},"graph":{"type":"object"},"reentry":{"type":"string"},"status":{"type":"string","enum":["draft","active","paused","archived"]}}}}}},"responses":{"200":{"description":"Updated"},"404":{"description":"Not found"}}},"delete":{"tags":["Marketing"],"summary":"Delete a workflow","responses":{"200":{"description":"Deleted"}}}},"/marketing/logs":{"get":{"tags":["Marketing"],"summary":"Query marketing send logs","description":"Delivery/open/click logs for marketing sends. Optionally filter by broadcast.","parameters":[{"name":"broadcast_id","in":"query","schema":{"type":"string"}},{"name":"to_address","in":"query","schema":{"type":"string"}},{"name":"subject","in":"query","schema":{"type":"string"}},{"name":"uid","in":"query","schema":{"type":"string"}},{"name":"action","in":"query","schema":{"type":"string","enum":["ACCEPTED","DELIVERED","REJECTED","BOUNCE","DEFERRED","SPAM","VIRUS","QUEUED","OPENED","CLICKED"]}},{"name":"from","in":"query","schema":{"type":"string","description":"YYYY-MM-DD or ISO"}},{"name":"to","in":"query","schema":{"type":"string","description":"YYYY-MM-DD or ISO"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":25,"maximum":100}}],"responses":{"200":{"description":"Log rows + pagination","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"pagination":{"type":"object"}}}}}}}}},"/marketing/messages/{uid}":{"parameters":[{"name":"uid","in":"path","required":true,"schema":{"type":"string"},"description":"Message id returned by a send, and the `id` on marketing log rows"}],"get":{"tags":["Marketing"],"summary":"Get a sent message","description":"Returns available content and metadata for a sent marketing message.","responses":{"200":{"description":"Rebuilt message","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"object","properties":{"uid":{"type":"string"},"messageId":{"type":"string","nullable":true,"description":"RFC Message-ID header"},"kind":{"type":"string","enum":["transactional","broadcast","workflow","test"]},"to":{"type":"string"},"from":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"}}},"replyTo":{"type":"string","nullable":true},"contactId":{"type":"string","nullable":true},"sentAt":{"type":"integer","description":"Epoch millis"},"subject":{"type":"string","nullable":true},"html":{"type":"string","nullable":true},"text":{"type":"string","nullable":true},"rebuilt":{"type":"boolean","description":"Whether complete message content is available."},"fidelity":{"type":"object","properties":{"verified":{"type":"boolean"},"reason":{"type":"string"},"redactedKeys":{"type":"array","items":{"type":"string"}}}},"attachments":{"type":"array","items":{"type":"object","properties":{"filename":{"type":"string"},"bytes":{"type":"integer"},"sha256":{"type":"string"}}}},"source":{"type":"object","properties":{"templateId":{"type":"string","nullable":true},"contentHash":{"type":"string","nullable":true},"jobId":{"type":"string","nullable":true},"broadcastId":{"type":"string","nullable":true},"workflowId":{"type":"string","nullable":true},"renderVersion":{"type":"integer"}}}}}}}}}},"404":{"description":"Message not found"}}}},"/marketing/assets":{"get":{"tags":["Marketing"],"summary":"List uploaded images","description":"Lists uploaded images with account storage usage. Passing `page` or `limit` switches to a paginated response: an optional `q` name filter applies across the whole library and the response gains a `pagination` object.","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Page number (enables pagination)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page (enables pagination)"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by file name substring (paginated mode only)"}],"responses":{"200":{"description":"Assets and account storage usage","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"assets":{"type":"array","items":{"$ref":"#/components/schemas/MarketingAsset"}},"storage":{"$ref":"#/components/schemas/MarketingAssetStorage"},"pagination":{"type":"object","description":"Present in paginated mode","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total_count":{"type":"integer"},"has_next_page":{"type":"boolean"},"showing_from":{"type":"integer"},"showing_to":{"type":"integer"}}}}}}}}}},"post":{"tags":["Marketing"],"summary":"Upload an image","description":"Multipart upload of a logo/image (max 5 MB; png, jpeg, gif or webp). Returns the public URL.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Uploaded","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"asset":{"$ref":"#/components/schemas/MarketingAsset"},"storage":{"$ref":"#/components/schemas/MarketingAssetStorage"}}}}}},"413":{"description":"File too large or account storage quota exceeded"},"415":{"description":"Unsupported file type"}}}},"/marketing/assets/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Marketing"],"summary":"Check where an image is used","description":"Returns current template references for an image in the account library.","responses":{"200":{"description":"Template references","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"references":{"$ref":"#/components/schemas/MarketingAssetReferences"}}}}}},"404":{"description":"Not found"}}},"delete":{"tags":["Marketing"],"summary":"Delete an image","description":"Deletes the image. Returns 409 when a current template references the image unless force=true is supplied after confirmation.","parameters":[{"name":"force","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Deleted"},"404":{"description":"Not found"},"409":{"description":"Image is referenced by one or more templates"}}}},"/marketing/unsubscribe-page":{"get":{"tags":["Marketing"],"summary":"Get unsubscribe page settings","description":"Returns the account's unsubscribe confirm/success page customization, the default copy used for empty fields, and whether the plan may hide the \"Powered by JetEmail\" footer.","responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"settings":{"$ref":"#/components/schemas/MarketingUnsubPageSettings"},"defaults":{"type":"object","additionalProperties":{"type":"string"}},"canHideBranding":{"type":"boolean"}}}}}}}},"put":{"tags":["Marketing"],"summary":"Update unsubscribe page settings","description":"Customizes the public unsubscribe confirm/success pages. Empty fields fall back to the defaults. hideBranding requires a paid marketing plan and is forced off otherwise. The logo must be an https:// image URL (typically an uploaded marketing asset).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"logoUrl":{"type":"string"},"heading":{"type":"string","maxLength":150},"message":{"type":"string","maxLength":1000},"buttonLabel":{"type":"string","maxLength":150},"successHeading":{"type":"string","maxLength":150},"successMessage":{"type":"string","maxLength":1000},"hideBranding":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"settings":{"$ref":"#/components/schemas/MarketingUnsubPageSettings"},"canHideBranding":{"type":"boolean"}}}}}},"400":{"description":"Validation error"}}}},"/email":{"post":{"tags":["Email"],"summary":"Send an email","security":[{"transactionalKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":256},"description":"Opaque key (1–256 chars) that makes retries safe. A repeat with the same key and body replays the original response."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","to","subject"],"properties":{"from":{"type":"string","description":"Sender email address in format: \"Name <email@domain.com>\"","example":"John Doe <john@example.com>"},"to":{"oneOf":[{"type":"string","format":"email","description":"Single recipient email address","example":"user@example.com"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50,"description":"List of recipient email addresses"}],"description":"Recipient email address(es)"},"subject":{"type":"string","minLength":1,"description":"Email subject line"},"html":{"type":"string","description":"HTML content of the email. At least one of html or text is required. Can be used together with text to provide a plaintext alternative"},"text":{"type":"string","description":"Plaintext content of the email. At least one of html or text is required. When used with html, serves as the plaintext alternative"},"cc":{"oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50}],"description":"CC recipient(s). Can be plain email or \"Name <email@domain.com>\" format"},"bcc":{"oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50}],"description":"BCC recipient(s). Can be plain email or \"Name <email@domain.com>\" format"},"reply_to":{"oneOf":[{"type":"string","format":"email"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50}],"description":"Reply-to address(es). Can be plain email or \"Name <email@domain.com>\" format"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom email headers"},"attachments":{"type":"array","items":{"type":"object","required":["filename","data"],"properties":{"filename":{"type":"string","description":"Name of the attachment file"},"data":{"type":"string","format":"base64","description":"Base64 encoded file content"}}},"description":"Email attachments (base64 encoded, max total size: 40MB)"},"eu":{"type":"boolean","description":"If true, restricts email delivery to EU region only.","example":false},"scheduledAt":{"oneOf":[{"type":"integer","description":"Unix seconds (UTC).","example":1762435200},{"type":"string","format":"date-time","description":"ISO 8601 / RFC 3339 with offset.","example":"2026-05-15T10:00:00Z"}],"description":"Future send time, up to 30 days out. Accepts unix seconds (e.g. 1762435200) or ISO 8601 (e.g. \"2026-05-15T10:00:00Z\" or \"2026-05-15T10:00:00-04:00\"). `scheduled_at` is also accepted as an alias."}}},"examples":{"Simple Text Email":{"value":{"from":"John Doe <john@example.com>","to":"recipient@example.com","subject":"Test Email","text":"Hello! This is a test email."}},"HTML Email with Plaintext Alternative":{"value":{"from":"John Doe <john@example.com>","to":"recipient@example.com","subject":"Test Email","html":"<h1>Hello!</h1><p>This is the HTML version.</p>","text":"Hello! This is the plaintext version."}},"Scheduled Email (ISO 8601)":{"value":{"from":"John Doe <john@example.com>","to":"recipient@example.com","subject":"Reminder","text":"This will arrive at the scheduled time.","scheduledAt":"2026-05-15T10:00:00Z"}},"Scheduled Email (Unix seconds)":{"value":{"from":"John Doe <john@example.com>","to":"recipient@example.com","subject":"Reminder","text":"This will arrive at the scheduled time.","scheduledAt":1762435200}}}}}},"responses":{"201":{"description":"Email queued successfully","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Unique message ID","example":"19424fd2acd0004210"},"response":{"type":"string","description":"Queue confirmation message","example":"Message queued as 19424fd2acd0004210"}}}}}},"202":{"description":"Email scheduled for future delivery.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Scheduling uuid","example":"0cd0f31f-1234-4abc-8def-1234567890ab"},"response":{"type":"string","example":"Scheduled as 0cd0f31f-… for 1762435200"},"scheduled_at":{"type":"integer","description":"Unix seconds at which the message will send","example":1762435200}}}}}},"400":{"description":"Bad Request - Invalid input"},"401":{"description":"Unauthorized - Missing or invalid API key"},"409":{"description":"Idempotency conflict — key in flight (IDEMPOTENCY_IN_FLIGHT) or reused with a different body (IDEMPOTENCY_BODY_MISMATCH)."}}}},"/email-batch":{"post":{"tags":["Email"],"summary":"Send multiple emails in a batch","description":"Send up to 100 emails in a single batch request","security":[{"transactionalKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emails"],"properties":{"emails":{"type":"array","items":{"type":"object","required":["from","to","subject"],"oneOf":[{"required":["html"]},{"required":["text"]}],"properties":{"from":{"type":"string","description":"Sender email address in format: \"Name <email@domain.com>\"","example":"John Doe <john@example.com>"},"to":{"oneOf":[{"type":"string","format":"email","description":"Single recipient email address","example":"user@example.com"},{"type":"array","items":{"type":"string","format":"email"},"maxItems":50,"description":"List of recipient email addresses"}]},"subject":{"type":"string","maxLength":998,"description":"Email subject line"},"html":{"type":"string","description":"HTML content of the email. At least one of html or text is required."},"text":{"type":"string","description":"Plain text content of the email. At least one of html or text is required."},"cc":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"CC recipient(s)"},"bcc":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"BCC recipient(s)"},"reply_to":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Reply-to address(es)"},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom email headers"},"attachments":{"type":"array","items":{"type":"object","required":["filename","data"],"properties":{"filename":{"type":"string","maxLength":255,"description":"Name of the attachment file"},"data":{"type":"string","format":"base64","description":"Base64 encoded file content"}}},"description":"Email attachments (base64 encoded, max total size: 40MB)"},"eu":{"type":"boolean","description":"If true, restricts email delivery to EU region only.","example":false},"idempotency_key":{"type":"string","minLength":1,"maxLength":256,"description":"Per-email idempotency key. A repeat with the same key and body replays the original result."},"scheduledAt":{"oneOf":[{"type":"integer","description":"Unix seconds (UTC).","example":1762435200},{"type":"string","format":"date-time","description":"ISO 8601 / RFC 3339 with offset.","example":"2026-05-15T10:00:00Z"}],"description":"Future send time, up to 30 days out. Accepts unix seconds (e.g. 1762435200) or ISO 8601 (e.g. \"2026-05-15T10:00:00Z\" or \"2026-05-15T10:00:00-04:00\"). `scheduled_at` is also accepted as an alias."}}},"maxItems":100,"minItems":1}}},"examples":{"Simple Batch":{"value":{"emails":[{"from":"John Doe <john@example.com>","to":"recipient1@example.com","subject":"Test Email 1","text":"Hello! This is test email 1."},{"from":"John Doe <john@example.com>","to":"recipient2@example.com","subject":"Test Email 2","text":"Hello! This is test email 2."}]}},"Mixed Immediate and Scheduled":{"value":{"emails":[{"from":"John Doe <john@example.com>","to":"recipient1@example.com","subject":"Send now","text":"Hello! This sends immediately."},{"from":"John Doe <john@example.com>","to":"recipient2@example.com","subject":"Send later","text":"Hello! This sends at the scheduled time.","scheduledAt":"2026-05-15T10:00:00Z"}]}}}}}},"responses":{"207":{"description":"Batch processing results","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","properties":{"total":{"type":"integer","description":"Total number of emails in batch","example":2},"successful":{"type":"integer","description":"Number of successfully sent emails","example":1},"failed":{"type":"integer","description":"Number of failed emails","example":1}}},"results":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","enum":["success"],"example":"success"},"id":{"type":"string","description":"Message ID, or scheduling uuid for scheduled items.","example":"19424fd2acd0004210"},"response":{"type":"string","description":"Success message","example":"Message queued as 19424fd2acd0004210"},"scheduled_at":{"type":"integer","description":"Unix seconds at which the message will send. Present only when scheduled.","example":1762435200}}},{"type":"object","properties":{"status":{"type":"string","enum":["error"],"example":"error"},"error":{"type":"string","description":"Error message","example":"Invalid email format"},"email":{"type":"object","description":"The original email request that failed"}}}]}}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Maximum batch size is 100 emails"}}}}}},"401":{"description":"Unauthorized - Missing or invalid API key"},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"No healthy email endpoints available"}}}}}}}}},"/outbound/smarthost":{"get":{"tags":["Outbound"],"summary":"Get SMTP users","description":"Retrieves a list of SMTP users","responses":{"200":{"description":"Successfully retrieved SMTP users","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"smarthosts":{"type":"array","items":{"type":"object","properties":{"username":{"type":"string","description":"SMTP username","example":"smtpuser"},"uuid":{"type":"string","description":"Unique identifier for the smarthost","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"status":{"type":"string","enum":["disabled","active","suspended","quota-locked","quota-unlocked"],"description":"Current status of the SMTP user","example":"active"},"allowAnyDomain":{"type":"integer","enum":[0,1],"description":"Whether the user can send from any domain (0=false, 1=true)","example":0},"allowAllDomains":{"type":"integer","enum":[0,1],"description":"Whether the user can send from all verified domains (0=false, 1=true)","example":0},"approvedDomains":{"type":"string","description":"JSON string containing array of approved domains","example":"[\"alloweddomain.com\"]"},"usage":{"type":"integer","description":"Current usage count","example":77},"quota":{"type":"integer","description":"Maximum allowed usage","example":1001},"ipRestrictions":{"type":"string","description":"JSON string containing array of allowed IP addresses","example":"[\"1.1.1.1\"]"},"ip_auth":{"type":"string","nullable":true,"description":"IP-based SMTP authentication address (pro only). A single IPv4 bound to this account, globally unique across all accounts; null if not set. Username and password are still required.","example":"1.1.1.1"},"tags":{"type":"string","description":"JSON string containing an array of free-form tags used to organise/filter SMTP users","example":"[\"production\",\"billing\"]"},"created_date":{"type":"string","description":"Creation timestamp in milliseconds or seconds (with decimal)","example":"1724113774000"},"last_modified":{"type":"integer","description":"Last modification timestamp in seconds","example":1735937552}}}}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch SMTP users"}}}}}}}},"post":{"tags":["Outbound"],"summary":"Create new SMTP user","description":"Creates a new SMTP user for outbound email sending","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username"],"properties":{"username":{"type":"string","description":"SMTP username (will be sanitized to lowercase alphanumeric with hyphens)","example":"smtp-user1","minLength":1,"maxLength":64,"pattern":"^[a-z0-9-]+$"},"password":{"type":"string","description":"Optional password (will be generated if not provided)","example":"mySecurePassword123","minLength":8,"maxLength":72},"allowAnyDomain":{"type":"boolean","description":"Whether to allow sending from any domain (requires paid subscription). Cannot be enabled together with allowAllDomains.","default":false},"allowAllDomains":{"type":"boolean","description":"Whether to allow sending from all verified domains. Cannot be enabled together with allowAnyDomain.","default":false},"approvedDomains":{"type":"array","items":{"type":"string","pattern":"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,}$"},"description":"List of approved domains for sending","default":[],"example":["example.com","mydomain.com"],"maxItems":50},"quota":{"type":"number","description":"Email sending quota","default":0,"example":1000,"minimum":0},"ipRestrictions":{"type":"array","items":{"type":"string","pattern":"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"},"description":"List of allowed IP addresses","default":[],"example":["192.168.1.1","10.0.0.1"],"maxItems":50},"ip_auth":{"type":"string","nullable":true,"pattern":"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$","description":"IP-based SMTP authentication address (requires paid subscription). A single IPv4 (no CIDR) bound to this account; must be globally unique across all accounts. Username and password are still required. Omit or set null/empty to leave unset.","default":null,"example":"1.1.1.1"},"tags":{"type":"array","items":{"type":"string","pattern":"^[\\w- ]+$","maxLength":32},"description":"Free-form tags used to organise/filter SMTP users. Trimmed and de-duplicated (case-insensitive) server-side.","default":[],"example":["production","billing"],"maxItems":20}}}}}},"responses":{"200":{"description":"SMTP user created successfully. If no password was provided in the request, a generated password will be included in the response.","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"SMTP user created successfully"},"password":{"type":"string","description":"Only present if no password was provided in the request","example":"generated-secure-password"}}},"examples":{"With provided password":{"value":{"success":true,"message":"SMTP user created successfully"}},"With generated password":{"value":{"success":true,"message":"SMTP user created successfully","password":"generated-secure-password"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"SMTP username is required"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"403":{"description":"Forbidden - Feature not available","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Allow Any Domain feature requires a paid subscription"}}}}}},"409":{"description":"Conflict - Username already exists","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"This SMTP username is already in use"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create SMTP user"}}}}}}}},"patch":{"tags":["Outbound"],"summary":"Update SMTP user","description":"Updates an existing SMTP user configuration","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["currentUsername"],"properties":{"currentUsername":{"type":"string","description":"Current SMTP username to update","example":"existing-user"},"newUsername":{"type":"string","description":"New SMTP username (will be sanitized to lowercase alphanumeric with hyphens)","example":"new-user-name","minLength":1,"maxLength":64,"pattern":"^[a-z0-9-]+$"},"password":{"type":"string","description":"New password","example":"newSecurePassword123","minLength":8,"maxLength":72},"allowAnyDomain":{"type":"boolean","description":"Whether to allow sending from any domain (requires paid subscription). Cannot be enabled together with allowAllDomains.","example":false},"allowAllDomains":{"type":"boolean","description":"Whether to allow sending from all verified domains. Cannot be enabled together with allowAnyDomain.","example":false},"approvedDomains":{"type":"array","items":{"type":"string","pattern":"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,}$"},"description":"List of approved domains for sending","example":["example.com","mydomain.com"],"maxItems":253},"quota":{"type":"number","description":"Email sending quota","example":1000,"minimum":0},"ipRestrictions":{"type":"array","items":{"type":"string","pattern":"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"},"description":"List of allowed IP addresses","example":["192.168.1.1","10.0.0.1"],"maxItems":50},"ip_auth":{"type":"string","nullable":true,"pattern":"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$","description":"IP-based SMTP authentication address (requires paid subscription). A single IPv4 (no CIDR) bound to this account; must be globally unique across all accounts. Username and password are still required. Pass null or empty string to clear it.","example":"1.1.1.1"},"tags":{"type":"array","items":{"type":"string","pattern":"^[\\w- ]+$","maxLength":32},"description":"Free-form tags used to organise/filter SMTP users. Replaces the existing set; trimmed and de-duplicated (case-insensitive) server-side. Pass [] to clear all tags.","example":["production","billing"],"maxItems":20},"status":{"type":"string","enum":["inactive","active","suspended","quota-locked","quota-unlocked"],"description":"Status of the SMTP user"}}},"examples":{"Update username":{"value":{"currentUsername":"old-user","newUsername":"new-user"}},"Update multiple fields":{"value":{"currentUsername":"existing-user","allowAnyDomain":true,"approvedDomains":["newdomain.com"],"quota":2000,"ipRestrictions":["192.168.1.100"],"ip_auth":"1.1.1.1","tags":["production","billing"]}},"Update status":{"value":{"currentUsername":"existing-user","status":"active"}}}}}},"responses":{"200":{"description":"SMTP user updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Smarthost updated successfully"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No valid updates provided"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"403":{"description":"Forbidden - Feature not available","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Allow Any Domain feature requires a paid subscription"}}}}}},"404":{"description":"Not Found - Smarthost not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Smarthost not found or access denied"}}}}}},"409":{"description":"Conflict - New username already exists","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"This SMTP username is already in use"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update smarthost"}}}}}}}},"delete":{"tags":["Outbound"],"summary":"Delete SMTP user","description":"Deletes an SMTP user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username"],"properties":{"username":{"type":"string","description":"SMTP username to delete","example":"smtp-user1"}}}}}},"responses":{"200":{"description":"SMTP user deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Smarthost deleted successfully"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Username is required"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"404":{"description":"Not Found - Smarthost not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Smarthost not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete smarthost"}}}}}}}}},"/outbound/transactional-keys":{"get":{"tags":["Outbound"],"summary":"Get transactional API keys","description":"Retrieves a list of transactional API keys","responses":{"200":{"description":"Successfully retrieved transactional keys","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"transactionalKeys":{"type":"array","items":{"type":"object","properties":{"api_token":{"type":"string","description":"API key","example":"transactional_1111111"},"uuid":{"type":"string","description":"Unique identifier for the transactional key","example":"a1b2c3d4-e5f6-7890-abcd-ef1234567890"},"name":{"type":"string","description":"Name for the transactional key","example":"Production API Key"},"status":{"type":"string","enum":["disabled","active","suspended","quota-locked","quota-unlocked"],"description":"Current status of the API key","example":"active"},"allowAllDomains":{"type":"integer","enum":[0,1],"description":"Whether the key can send from all verified domains (0=false, 1=true)","example":0},"approvedDomains":{"type":"string","description":"JSON string containing array of approved domains","example":"[\"alloweddomain.com\"]"},"usage":{"type":"integer","description":"Current usage count","example":77},"quota":{"type":"integer","description":"Maximum allowed usage","example":1001},"ipRestrictions":{"type":"string","description":"JSON string containing array of allowed IP addresses","example":"[\"1.1.1.1\"]"},"tags":{"type":"string","description":"JSON string containing an array of free-form tags used to organise/filter transactional keys","example":"[\"production\",\"billing\"]"},"created_date":{"type":"string","description":"Creation timestamp","example":"1724113774000"},"last_modified":{"type":"integer","description":"Last modification timestamp","example":1735937552}}}}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch SMTP users"}}}}}}}},"post":{"tags":["Outbound"],"summary":"Create new transactional API key","description":"Creates a new transactional API key for sending emails via the API","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name for the transactional key","example":"Production API Key","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9-_\\s]+$"},"allowAllDomains":{"type":"boolean","description":"Whether to allow sending from all verified domains","default":false},"approvedDomains":{"type":"array","items":{"type":"string","pattern":"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,}$"},"description":"List of approved domains for sending","default":[],"example":["example.com","mydomain.com"],"maxItems":253},"quota":{"type":"integer","description":"Email sending quota (0 for unlimited)","default":0,"example":1000,"minimum":0,"maximum":1000000},"ipRestrictions":{"type":"array","items":{"type":"string","pattern":"^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:/(?:3[0-2]|[12]?[0-9]))?)|(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,7}:(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|:(?::[0-9a-fA-F]{1,4}){1,7}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|::(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?)$"},"description":"List of allowed IP addresses/CIDR ranges (IPv4 and IPv6)","default":[],"example":["192.168.1.1","10.0.0.0/24","2001:db8::1","2001:db8::/32"],"maxItems":50},"tags":{"type":"array","items":{"type":"string","pattern":"^[\\w- ]+$","maxLength":32},"description":"Free-form tags used to organise/filter transactional keys. Trimmed and de-duplicated (case-insensitive) server-side.","default":[],"example":["production","billing"],"maxItems":20}}},"examples":{"Basic Key":{"value":{"name":"Development API Key"}},"Full Configuration":{"value":{"name":"Production API Key","allowAllDomains":true,"approvedDomains":["example.com"],"quota":10000,"ipRestrictions":["192.168.1.1","10.0.0.0/24"],"tags":["production","billing"]}}}}}},"responses":{"200":{"description":"Transactional key created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Transactional key created successfully"},"api_token":{"type":"string","description":"The generated API token","example":"transactional_a1b2c3d4"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Name is required and must be a string"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"403":{"description":"Forbidden - Limit reached","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Free accounts are limited to 50 transactional keys"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create transactional key"}}}}}}}},"patch":{"tags":["Outbound"],"summary":"Update transactional API key","description":"Updates an existing transactional API key configuration or changes the status","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["api_token"],"properties":{"api_token":{"type":"string","description":"The API token to update","example":"transactional_a1b2c3d4"},"status":{"type":"integer","enum":[0,1],"description":"Toggle key status (0 = disabled, 1 = enabled). If provided, other update fields will be ignored.","example":1},"name":{"type":"string","description":"New name for the transactional key","example":"Updated API Key","minLength":1,"maxLength":64,"pattern":"^[a-zA-Z0-9-_\\s]+$"},"allowAllDomains":{"type":"boolean","description":"Whether to allow sending from all verified domains","example":false},"approvedDomains":{"type":"array","items":{"type":"string","pattern":"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,}$"},"description":"List of approved domains for sending","example":["example.com","mydomain.com"],"maxItems":253},"quota":{"type":"integer","description":"Email sending quota (0 for unlimited)","example":1000,"minimum":0,"maximum":1000000},"ipRestrictions":{"type":"array","items":{"type":"string","pattern":"^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:/(?:3[0-2]|[12]?[0-9]))?)|(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,7}:(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|:(?::[0-9a-fA-F]{1,4}){1,7}(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?|::(?:/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9]))?)$"},"description":"List of allowed IP addresses/CIDR ranges","example":["192.168.1.1","10.0.0.0/24"],"maxItems":50},"tags":{"type":"array","items":{"type":"string","pattern":"^[\\w- ]+$","maxLength":32},"description":"Free-form tags used to organise/filter transactional keys. Replaces the existing set; trimmed and de-duplicated (case-insensitive) server-side. Pass [] to clear all tags.","example":["production","billing"],"maxItems":20}}},"examples":{"Toggle Disable":{"value":{"api_token":"transactional_a1b2c3d4","status":0},"summary":"Disable a key"},"Toggle Enable":{"value":{"api_token":"transactional_a1b2c3d4","status":1},"summary":"Enable a key"},"Update Name":{"value":{"api_token":"transactional_a1b2c3d4","name":"New API Key Name"}},"Update Multiple Fields":{"value":{"api_token":"transactional_a1b2c3d4","name":"Production API","allowAllDomains":true,"approvedDomains":["newdomain.com"],"quota":5000,"ipRestrictions":["192.168.1.100","10.0.0.0/24"],"tags":["production","billing"]}}}}}},"responses":{"200":{"description":"Transactional key updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Transactional key updated successfully"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid name format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"404":{"description":"Not Found - Transactional key not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Transactional key not found or unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update transactional key"}}}}}}}},"delete":{"tags":["Outbound"],"summary":"Delete transactional API key","description":"Deletes a transactional API key","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["api_token"],"properties":{"api_token":{"type":"string","description":"The API token to delete","example":"transactional_a1b2c3d4"}}}}}},"responses":{"200":{"description":"Transactional key deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Transactional key deleted successfully"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"API token is required"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"404":{"description":"Not Found - Transactional key not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Transactional key not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete transactional key"}}}}}}}}},"/outbound/transactional-keys/rotate":{"post":{"tags":["Outbound"],"summary":"Rotate transactional API key","description":"Generates a new API token for an existing transactional key. The old token is immediately invalidated and a new one is returned. All other configuration (name, approved domains, quota, IP restrictions) remains unchanged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["api_token"],"properties":{"api_token":{"type":"string","description":"The current API token to rotate","example":"transactional_a1b2c3d4"}}}}}},"responses":{"200":{"description":"Transactional key rotated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Transactional key rotated successfully"},"api_token":{"type":"string","description":"The new API token","example":"transactional_e5f6a7b8"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"api_token is required"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"403":{"description":"Forbidden - Key cannot be rotated in its current state","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Cannot rotate a disabled transactional key. Enable it first."}}}}}},"404":{"description":"Not Found - Transactional key not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Transactional key not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to rotate transactional key"}}}}}}}}},"/outbound/logs":{"get":{"tags":["Outbound"],"summary":"Get outbound email logs","description":"Retrieves logs of outbound email activity with comprehensive filtering options","parameters":[{"name":"limit","in":"query","description":"Number of records to return (1-100)","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"page","in":"query","description":"Page number for pagination (starts from 1)","schema":{"type":"integer","minimum":1,"default":1}},{"name":"offset","in":"query","description":"Number of records to skip (alternative to page)","schema":{"type":"integer","minimum":0,"default":0}},{"name":"sort_by","in":"query","description":"Field to sort by","schema":{"type":"string","default":"date","maxLength":50}},{"name":"sort_order","in":"query","description":"Sort order","schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"}},{"name":"id","in":"query","description":"Filter by record ID","schema":{"type":"string","maxLength":100}},{"name":"uid","in":"query","description":"Filter by unique identifier","schema":{"type":"string","pattern":"^[A-Za-z0-9-_]{1,100}$"}},{"name":"action","in":"query","description":"Filter by email action status","schema":{"type":"string","enum":["ACCEPTED","REJECTED","BOUNCED_HARD","BOUNCED_SOFT","DEFERRED","SPAM","VIRUS","QUEUED","COMPLAINT"]}},{"name":"zone","in":"query","description":"Filter by zone","schema":{"type":"string","maxLength":50}},{"name":"message_id","in":"query","description":"Filter by message ID","schema":{"type":"string","maxLength":100}},{"name":"from_address","in":"query","description":"Filter by sender email address","schema":{"type":"string","format":"email"}},{"name":"to_address","in":"query","description":"Filter by recipient email address","schema":{"type":"string","format":"email"}},{"name":"mx","in":"query","description":"Filter by MX server","schema":{"type":"string","maxLength":100}},{"name":"host","in":"query","description":"Filter by host server","schema":{"type":"string","maxLength":100}},{"name":"ip","in":"query","description":"Filter by IP address","schema":{"type":"string","pattern":"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"}},{"name":"response","in":"query","description":"Filter by server response","schema":{"type":"string","maxLength":500}},{"name":"user","in":"query","description":"Filter by username","schema":{"type":"string","format":"email"}},{"name":"protocol","in":"query","description":"Filter by protocol","schema":{"type":"string","enum":["smtp","http","https"]}},{"name":"src","in":"query","description":"Filter by source","schema":{"type":"string","maxLength":50}},{"name":"subject","in":"query","description":"Filter by email subject","schema":{"type":"string","maxLength":500}},{"name":"md5","in":"query","description":"Filter by MD5 hash","schema":{"type":"string","pattern":"^[a-fA-F0-9]{32}$"}},{"name":"interface","in":"query","description":"Filter by interface","schema":{"type":"string","maxLength":50}},{"name":"originhost","in":"query","description":"Filter by origin host","schema":{"type":"string","maxLength":100}},{"name":"transtype","in":"query","description":"Filter by transport type","schema":{"type":"string","enum":["smtp","http","api"]}},{"name":"headerFrom","in":"query","description":"Filter by header From field","schema":{"type":"string","format":"email"}},{"name":"date_from","in":"query","description":"Filter by start date (Unix timestamp)","schema":{"type":"integer","minimum":0}},{"name":"date_to","in":"query","description":"Filter by end date (Unix timestamp)","schema":{"type":"integer","minimum":0}},{"name":"from","in":"query","description":"Filter by start date (YYYY-MM-DD or ISO format)","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","description":"Filter by end date (YYYY-MM-DD or ISO format)","schema":{"type":"string","format":"date"}},{"name":"rule_id","in":"query","description":"Filter by rule ID","schema":{"type":"string","maxLength":100}},{"name":"search","in":"query","description":"General search term (searches across email fields)","schema":{"type":"string","maxLength":200}}],"responses":{"200":{"description":"Successfully retrieved logs grouped by message uid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"pagination":{"type":"object","properties":{"total_count":{"type":"integer","description":"Total number of matching messages"},"total_pages":{"type":"integer"},"current_page":{"type":"integer"},"per_page":{"type":"integer"},"offset":{"type":"integer"},"has_next_page":{"type":"boolean"},"has_previous_page":{"type":"boolean"},"next_offset":{"type":"integer","nullable":true},"previous_offset":{"type":"integer","nullable":true},"showing_from":{"type":"integer"},"showing_to":{"type":"integer"},"count_limited":{"type":"boolean","description":"True when total_count was truncated at max_count_limit; the real total may be higher"},"max_count_limit":{"type":"integer"}}},"data":{"type":"array","description":"One entry per message, aggregated from all events recorded against its uid","items":{"type":"object","properties":{"uid":{"type":"string","example":"abc123","description":"Unique message identifier"},"id":{"type":"string"},"message_id":{"type":"string"},"subject":{"type":"string"},"from_address":{"type":"string","format":"email"},"to_address":{"type":"string","format":"email"},"sender":{"type":"string"},"receiver":{"type":"string"},"user":{"type":"string"},"src":{"type":"string"},"originhost":{"type":"string"},"transtype":{"type":"string"},"headerFrom":{"type":"string"},"rule_id":{"type":"string"},"first_seen":{"type":"integer","format":"int64","description":"Milliseconds since epoch when the message was first recorded"},"last_updated":{"type":"integer","format":"int64","description":"Milliseconds since epoch of the most recent event for this message"},"action_count":{"type":"integer","description":"Total number of events recorded against this message"},"delivery_status":{"type":"string","enum":["queued_pending","deferred","delivered","opened","clicked","bounced","rejected","dropped","spam","virus_detected","unknown"],"description":"Overall message status"},"was_queued":{"type":"integer","enum":[0,1]},"was_delivered":{"type":"integer","enum":[0,1]},"was_deferred":{"type":"integer","enum":[0,1]},"was_rejected":{"type":"integer","enum":[0,1]},"was_bounced":{"type":"integer","enum":[0,1]},"was_dropped":{"type":"integer","enum":[0,1]},"was_spam":{"type":"integer","enum":[0,1]},"was_virus":{"type":"integer","enum":[0,1]},"was_opened":{"type":"integer","enum":[0,1],"description":"1 if the message has been opened at least once"},"was_clicked":{"type":"integer","enum":[0,1],"description":"1 if a tracked link in the message has been clicked at least once"},"final_mx":{"type":"string","description":"MX server used for the final delivery attempt"},"final_host":{"type":"string","description":"Receiving host of the final delivery attempt"},"final_ip":{"type":"string","description":"IP of the final delivery attempt"},"final_protocol":{"type":"string"},"final_response":{"type":"string","description":"Server response from the final delivery attempt"},"bounce_reason":{"type":"string","nullable":true,"description":"Response body of the bounce, if the message bounced"},"bounce_mx":{"type":"string","nullable":true},"bounce_host":{"type":"string","nullable":true},"delivery_attempts":{"type":"array","description":"Every delivery attempt against this message, oldest first","items":{"type":"object","properties":{"action":{"type":"string","description":"Outcome of this attempt (ACCEPTED, DELIVERED, DEFERRED, REJECTED, BOUNCED_HARD, BOUNCED_SOFT, BOUNCED_UNKNOWN, DROP, DROPPED)"},"receiver":{"type":"string"},"mx":{"type":"string"},"host":{"type":"string"},"ip":{"type":"string"},"response":{"type":"string"},"protocol":{"type":"string"},"date":{"type":"integer","format":"int64","description":"Milliseconds since epoch"},"timestamp":{"type":"string","format":"date-time","description":"Same instant as `date`, in RFC3339 form"}}}},"delivery_summary":{"type":"object","properties":{"total_attempts":{"type":"integer"},"successful_deliveries":{"type":"integer"},"failed_deliveries":{"type":"integer"},"unique_recipients":{"type":"integer"}}},"opens":{"type":"array","description":"Every recorded open of the message, oldest first. Absent if the message has not been opened.","items":{"type":"object","required":["date"],"properties":{"date":{"type":"integer","format":"int64","description":"Milliseconds since epoch when the open occurred"},"country":{"type":"string","description":"Approximate location of the reader (e.g. \"Brisbane, QLD, AU\")"},"email_client":{"type":"string","description":"Email client that loaded the message (e.g. \"Gmail\", \"Outlook (web)\")"}}}},"clicks":{"type":"array","description":"Every recorded click on a tracked link in the message, oldest first. Absent if no links have been clicked.","items":{"type":"object","required":["date"],"properties":{"date":{"type":"integer","format":"int64","description":"Milliseconds since epoch when the click occurred"},"country":{"type":"string","description":"Approximate location of the clicker"},"email_client":{"type":"string","description":"Browser or email client that made the request"},"user_agent":{"type":"string","description":"Raw User-Agent header of the request that loaded the link"},"original_url":{"type":"string","description":"Destination URL of the clicked link, when known"}}}}}}}}}}}},"400":{"description":"Bad Request - Invalid parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid parameter format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User authentication, log location, or db_uuid not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch outbound logs"},"details":{"type":"string","description":"Additional error details"}}}}}}}}},"/outbound/logs/uid":{"get":{"tags":["Outbound"],"summary":"Get outbound email logs by UID","description":"Retrieves detailed log information for a specific message UID. This will only return data about whether the email was delivered.","parameters":[{"name":"uid","in":"query","required":true,"description":"Unique identifier of the message","schema":{"type":"string","pattern":"^[A-Za-z0-9-_]{1,50}$"}}],"responses":{"200":{"description":"Successfully retrieved log details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"uid":{"type":"string","description":"Unique identifier","example":"abc123"},"action":{"type":"string","description":"Action taken on the message","example":"ACCEPTED"},"message_id":{"type":"string","description":"Email message ID","example":"<abc123@server.local>"},"response":{"type":"string","description":"Server response","example":"250 2.0.0 Ok: queued"},"user":{"type":"string","description":"Username","example":"smtp_user1"},"from_address":{"type":"string","description":"Sender email address","example":"sender@example.com"},"to_address":{"type":"string","description":"Recipient email address","example":"recipient@example.com"},"date":{"type":"string","description":"Transaction date","example":"2024-03-20T15:30:00Z"},"mx":{"type":"string","description":"MX server used","example":"mx.recipient.com"},"host":{"type":"string","description":"Host server name","example":"outbound1.server.local"},"outbound_ip":{"type":"string","description":"IP address used for sending","example":"192.168.1.1"}}}}}}}}},"400":{"description":"Bad Request - Invalid UID format","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid or missing UID"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Failed to fetch logs"}}}}}}}}},"/outbound/domains":{"get":{"tags":["Outbound"],"summary":"Get domains","description":"Retrieves a list of domains associated with the user or organization","responses":{"200":{"description":"Successfully retrieved domains","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"domains":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","description":"Unique identifier for the domain","example":"550e8400-e29b-41d4-a716-446655440000"},"domain":{"type":"string","description":"Domain name","example":"example.com"},"status":{"type":"string","enum":["inactive","active","disabled","unknown"],"description":"Current status of the domain","example":"active"},"created_date":{"type":"integer","description":"Creation timestamp in seconds","example":1735689600},"last_modified":{"type":"integer","description":"Last modification timestamp in seconds","example":1735689600},"dns":{"type":"object","properties":{"dkim":{"type":"object","properties":{"host":{"type":"string","description":"DKIM record hostname","example":"jetemail._domainkey.example.com"},"value":{"type":"string","description":"DKIM record value","example":"dkim.jetsmtp.net"},"verified":{"type":"boolean","description":"Whether the DKIM record is verified","example":true}}},"spf":{"type":"object","properties":{"host":{"type":"string","description":"SPF CNAME record hostname","example":"em12345.example.com"},"value":{"type":"string","description":"SPF CNAME record target","example":"return.jetsmtp.net"},"type":{"type":"string","description":"DNS record type","example":"CNAME"},"verified":{"type":"boolean","description":"Whether the SPF record is verified","example":true}}},"dmarc":{"type":"object","properties":{"host":{"type":"string","description":"DMARC record hostname","example":"_dmarc.example.com"},"value":{"type":"string","description":"DMARC record value","example":"v=DMARC1; p=none"},"verified":{"type":"boolean","description":"Whether the DMARC record is verified","example":true}}},"tracking":{"type":"object","description":"Optional tracking CNAME. Present only when tracking_domain is set on the domain.","properties":{"host":{"type":"string","example":"links.example.com"},"value":{"type":"string","example":"link-us.jete.ml"},"type":{"type":"string","example":"CNAME"},"required":{"type":"boolean","example":false},"verified":{"type":"boolean","example":true}}}}}}}}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch domains"}}}}}}}},"post":{"tags":["Outbound"],"summary":"Add new domain","description":"Adds a new domain for sending email","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","description":"Domain name to add","example":"example.com","pattern":"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,}$"}}}}}},"responses":{"200":{"description":"Domain added successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Domain added successfully"},"domain":{"type":"string","description":"The added domain name","example":"example.com"},"uuid":{"type":"string","description":"Unique identifier for the domain","example":"550e8400-e29b-41d4-a716-446655440000"},"status":{"type":"integer","description":"Domain status code","example":0},"created_date":{"type":"integer","description":"Creation timestamp","example":1735689600},"dns":{"type":"object","properties":{"dkim":{"type":"object","properties":{"host":{"type":"string","description":"DKIM record hostname","example":"jetemail._domainkey.example.com"},"value":{"type":"string","description":"DKIM record value","example":"dkim.jetsmtp.net"},"verified":{"type":"boolean","description":"Whether the DKIM record is verified","example":false}}},"spf":{"type":"object","properties":{"host":{"type":"string","description":"SPF CNAME record hostname","example":"em12345.example.com"},"value":{"type":"string","description":"SPF CNAME record target","example":"return.jetsmtp.net"},"type":{"type":"string","description":"DNS record type","example":"CNAME"},"verified":{"type":"boolean","description":"Whether the SPF record is verified","example":false}}},"dmarc":{"type":"object","properties":{"host":{"type":"string","description":"DMARC record hostname","example":"_dmarc.example.com"},"value":{"type":"string","description":"DMARC record value","example":"v=DMARC1; p=none"},"verified":{"type":"boolean","description":"Whether the DMARC record is verified","example":false}}}}}}}}}},"400":{"description":"Bad Request - Invalid domain format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid domain format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"409":{"description":"Conflict - Domain already exists","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain already exists"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to add domain"}}}}}}}},"delete":{"tags":["Outbound"],"summary":"Delete domain","description":"Marks a domain as deleted","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uuid"],"properties":{"uuid":{"type":"string","description":"UUID of the domain to delete","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"}}}}}},"responses":{"200":{"description":"Domain deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Domain deleted successfully"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain UUID is required"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not Found - Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found or already deleted"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete domain"}}}}}}}}},"/outbound/domains/{uuid}":{"get":{"tags":["Outbound"],"summary":"Get a domain","description":"Returns a single outbound domain by UUID.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"}}],"responses":{"200":{"description":"Domain found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"domain":{"type":"object","properties":{"uuid":{"type":"string","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"},"domain":{"type":"string","example":"example.com"},"status":{"type":"string","enum":["inactive","active","disabled","unknown"],"example":"active"},"created_date":{"type":"string","example":"1735689600.0"},"last_modified":{"type":"string","example":"1735689600.0"},"dns":{"type":"object","properties":{"dkim":{"type":"object","properties":{"host":{"type":"string","example":"jetemail._domainkey.example.com"},"value":{"type":"string","example":"dkim.jetsmtp.net"},"verified":{"type":"boolean","example":true}}},"spf":{"type":"object","properties":{"host":{"type":"string","example":"em12345.example.com"},"value":{"type":"string","example":"return.jetsmtp.net"},"type":{"type":"string","example":"CNAME"},"verified":{"type":"boolean","example":true}}},"dmarc":{"type":"object","properties":{"host":{"type":"string","example":"_dmarc.example.com"},"value":{"type":"string","example":"v=DMARC1; p=none"},"verified":{"type":"boolean","example":true}}},"tracking":{"type":"object","description":"Optional tracking CNAME. Present only when tracking_domain is set on the domain.","properties":{"host":{"type":"string","example":"links.example.com"},"value":{"type":"string","example":"link-us.jete.ml"},"type":{"type":"string","example":"CNAME"},"required":{"type":"boolean","example":false},"verified":{"type":"boolean","example":false}}}}}}}}}}}},"400":{"description":"Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID format"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch domain"}}}}}}}}},"/outbound/domains/{uuid}/check":{"post":{"tags":["Outbound"],"summary":"Check domain DNS records","description":"Verifies the DNS records for a domain","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain to check","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"}}],"responses":{"200":{"description":"DNS check completed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"DNS check completed"}}}}}},"400":{"description":"Bad Request - Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not Found - Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to check domain DNS"}}}}}}}}},"/outbound/domains/{uuid}/settings":{"get":{"tags":["Outbound"],"summary":"Get domain settings","description":"Retrieves email settings for a specific domain including BCC emails, open tracking, and click tracking","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain to get settings for","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"}}],"responses":{"200":{"description":"Domain settings retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"settings":{"type":"object","properties":{"uuid":{"type":"string","description":"Domain UUID","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"},"domain":{"type":"string","description":"Domain name","example":"example.com"},"bccEmails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"BCC email address"},"status":{"type":"integer","enum":[0,1],"description":"Verification status (0 = pending verification, 1 = verified)"}},"required":["email","status"]},"description":"Array of BCC email addresses with verification status","example":[{"email":"admin@example.com","status":1},{"email":"pending@example.com","status":0}]},"openTracking":{"type":"boolean","description":"Whether open tracking is enabled","example":true},"clickTracking":{"type":"boolean","description":"Whether click tracking is enabled","example":false},"tracking_domain":{"type":"string","nullable":true,"example":"links.example.com"},"tracking_verified":{"type":"boolean","example":false}}}}}}}},"400":{"description":"Bad Request - Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not Found - Domain not found or access denied","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to retrieve domain settings"}}}}}}}},"post":{"tags":["Outbound"],"summary":"Update domain settings","description":"Updates email settings for a specific domain including BCC emails, open tracking, and click tracking","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain to update settings for","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$","example":"b814c25d-b18c-4044-ae31-49e22ce908b5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"bccEmails":{"type":"array","items":{"type":"string","format":"email"},"description":"Array of BCC email addresses (maximum 5). New emails will require verification.","example":["admin@example.com","backup@example.com"],"maxItems":5,"nullable":true},"openTracking":{"type":"boolean","description":"Enable or disable open tracking for emails sent from this domain","example":true},"clickTracking":{"type":"boolean","description":"Enable or disable click tracking for emails sent from this domain","example":false},"tracking_domain":{"type":"string","nullable":true,"description":"Fully qualified hostname to CNAME to link-{logLocation}.jete.ml for click/open tracking. Pass null or an empty string to clear.","example":"links.example.com"}}}}}},"responses":{"200":{"description":"Domain settings updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Domain settings updated successfully"},"bccEmails":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"BCC email address"},"status":{"type":"integer","enum":[0,1],"description":"Verification status (0 = pending verification, 1 = verified)"}},"required":["email","status"]},"description":"Updated BCC emails with verification status (only present when bccEmails were updated)","example":[{"email":"admin@example.com","status":1},{"email":"new@example.com","status":0}]}}}}}},"400":{"description":"Bad Request - Invalid input or UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not Found - Domain not found or access denied","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found or access denied"}}}}}},"429":{"description":"Too Many Requests - Too many verification attempts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Too many verification attempts for email@example.com. Please try again later."}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update domain settings"}}}}}}}}},"/inbound/domains":{"get":{"tags":["Inbound"],"summary":"Get inbound domains","description":"Retrieves a list of inbound domains","responses":{"200":{"description":"Successfully retrieved domains","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","description":"Unique identifier for the domain","example":"550e8400-e29b-41d4-a716-446655440000"},"domain":{"type":"string","description":"Domain name","example":"example.com"},"delivery_type":{"type":"string","enum":["smtp","webhook","forward"],"description":"How emails are delivered for this domain","example":"smtp"},"status":{"type":"integer","enum":[0,1],"description":"Domain status (0 = inactive, 1 = active)","example":1},"last_modified":{"type":"integer","description":"Last modification timestamp in seconds","example":1735937552},"created_at":{"type":"integer","description":"Creation timestamp in seconds","example":1735937552}}}}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"No domains found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No domains found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch domains"}}}}}}}},"post":{"tags":["Inbound"],"summary":"Add new inbound domain","description":"Adds a new inbound domain with SMTP, webhook, or forward delivery. For forward delivery, use POST /inbound/domains/{uuid}/forward-rules to register routing rules after the domain is created and DNS is verified. Mode-specific fields are strictly enforced: smtp_servers is only allowed for delivery_type=smtp, the webhook_* fields are only allowed for delivery_type=webhook, and delivery_type=forward accepts neither. Sending fields from the wrong mode returns 400.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain","delivery_type"],"properties":{"domain":{"type":"string","description":"Primary domain name to add (e.g., example.com, not mail.example.com)","example":"example.com","pattern":"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?.)+[a-zA-Z]{2,}$"},"delivery_type":{"type":"string","enum":["smtp","webhook","forward"],"description":"How emails should be delivered for this domain. For \"forward\", inbound mail is forwarded to per-recipient destinations defined via POST /inbound/domains/{uuid}/forward-rules."},"smtp_servers":{"type":"array","description":"Only for delivery_type=smtp (required). Rejected with 400 if sent with webhook or forward.","items":{"oneOf":[{"type":"string","description":"Server URL","example":"mail.example.com:25"},{"type":"object","properties":{"url":{"type":"string","description":"Server URL","example":"mail.example.com:25"},"priority":{"type":"integer","description":"Server priority (lower = higher priority)","example":1},"tls_enabled":{"type":"boolean","description":"Enable TLS","default":false},"timeout":{"type":"integer","description":"Timeout in milliseconds","default":30000}},"required":["url"]}]}},"webhook_url":{"type":"string","format":"uri","description":"Only for delivery_type=webhook (required). Webhook URL to receive emails. Rejected with 400 if sent with smtp or forward.","example":"https://example.com/webhook/inbound"},"webhook_method":{"type":"string","enum":["POST","PUT"],"default":"POST","description":"Only for delivery_type=webhook. HTTP method for webhook. Rejected with 400 if sent with smtp or forward."},"webhook_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Only for delivery_type=webhook. Custom headers to send with webhook requests. Rejected with 400 if sent with smtp or forward."},"webhook_timeout":{"type":"integer","default":30000,"description":"Only for delivery_type=webhook. Webhook timeout in milliseconds. Rejected with 400 if sent with smtp or forward."},"webhook_retry_count":{"type":"integer","default":3,"description":"Only for delivery_type=webhook. Number of retry attempts for failed webhook calls. Rejected with 400 if sent with smtp or forward."},"webhook_auth_header":{"type":"string","description":"Only for delivery_type=webhook. Authorization header value for webhook. Rejected with 400 if sent with smtp or forward."}}},"examples":{"SMTP Delivery":{"value":{"domain":"example.com","delivery_type":"smtp","smtp_servers":[{"url":"mail.example.com:25","priority":1,"tls_enabled":true}]}},"Webhook Delivery":{"value":{"domain":"example.com","delivery_type":"webhook","webhook_url":"https://example.com/webhook/inbound"}},"Forwarding Delivery":{"value":{"domain":"example.com","delivery_type":"forward"}}}}}},"responses":{"200":{"description":"Domain added successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"object","properties":{"domain":{"type":"string","example":"example.com"},"delivery_type":{"type":"string","enum":["smtp","webhook","forward"],"example":"smtp"},"status":{"type":"string","example":"active"},"uuid":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"},"webhook_secret":{"type":"string","description":"Only present for webhook delivery_type. Secret for HMAC validation of webhook payloads.","example":"whsec_..."},"forward_mx_verified":{"type":"integer","enum":[0,1],"description":"Only present for forward delivery_type. DNS verification flag for the customer's MX record. Starts at 0; flipped to 1 by an external verifier once the customer publishes the required record. Inbound mail is rejected with 550 until all four forward_*_verified flags are 1.","example":0},"forward_dkim_verified":{"type":"integer","enum":[0,1],"description":"Only present for forward delivery_type. DNS verification flag for the customer's DKIM CNAME.","example":0},"forward_spf_verified":{"type":"integer","enum":[0,1],"description":"Only present for forward delivery_type. DNS verification flag for the customer's SPF record.","example":0},"forward_dmarc_verified":{"type":"integer","enum":[0,1],"description":"Only present for forward delivery_type. DNS verification flag for the customer's DMARC record.","example":0}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid domain format"}}},"examples":{"Invalid domain format":{"value":{"success":false,"error":"Invalid primary domain format. Please provide a primary domain (e.g., example.com) rather than a subdomain (e.g., mail.example.com)."}},"Wrong fields for delivery_type=forward":{"summary":"smtp_servers or webhook_* sent with delivery_type=forward","value":{"success":false,"error":"Fields not allowed for delivery_type=forward: smtp_servers, webhook_url"}},"Wrong fields for delivery_type=smtp":{"summary":"webhook_* sent with delivery_type=smtp","value":{"success":false,"error":"Fields not allowed for delivery_type=smtp: webhook_url"}},"Wrong fields for delivery_type=webhook":{"summary":"smtp_servers sent with delivery_type=webhook","value":{"success":false,"error":"Fields not allowed for delivery_type=webhook: smtp_servers"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Quota exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain quota exceeded"},"quota":{"type":"number","example":1},"current":{"type":"number","example":1}}}}}},"409":{"description":"Domain already exists","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"This domain is already configured. Please use a different domain."}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create domain"}}}}}}}},"delete":{"tags":["Inbound"],"summary":"Delete inbound domain","description":"Deletes an inbound domain configuration","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uuid"],"properties":{"uuid":{"type":"string","description":"UUID of the domain to delete","example":"550e8400-e29b-41d4-a716-446655440000","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}}}}},"responses":{"200":{"description":"Domain deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Domain deleted successfully"}}}}}},"400":{"description":"Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID format"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found or already deleted"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete domain"}}}}}}}}},"/inbound/domains/{uuid}/check":{"post":{"tags":["Inbound"],"summary":"Run a DNS check for an inbound forwarding domain","description":"Runs a DNS check against the domain.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the inbound forwarding domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"responses":{"200":{"description":"DNS check completed.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"DNS check completed"}}}}}},"400":{"description":"Invalid UUID, or domain is not delivery_type=forward","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"DNS check is only available for domains with delivery_type=forward"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Domain not found or access denied","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to check domain DNS"}}}}}}}}},"/inbound/domains/{uuid}/forward-rules":{"get":{"tags":["Inbound"],"summary":"List forwarding rules for a domain","description":"Returns every active and inactive (but not deleted) forwarding rule for the specified domain. Only valid for domains with delivery_type=forward.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"responses":{"200":{"description":"Rules listed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"7c1f7c14-1234-4abc-8def-0123456789ab"},"localpart":{"type":"string","description":"Address prefix to match. The literal \"*\" is the catch-all sentinel. Plus-addressing is handled at match time.","example":"support"},"destination":{"type":"string","description":"Bare email address or wildcard destination (*@domain) that becomes the outbound RCPT TO.","example":"team@theirinbox.com"},"active":{"type":"integer","enum":[0,1],"description":"Inactive rules are ignored at RCPT TO. Use this for soft-disable.","example":1},"verified":{"type":"integer","enum":[0,1],"description":"Set to 1 once the destination address owner has clicked the verification link. Wildcard destinations are verified by sending the verification email to postmaster. Until 1, inbound-edge will not deliver mail to this rule.","example":1},"last_modified":{"type":"integer","example":1735937552},"created_at":{"type":"integer","example":1735937552}}}}}}}}},"400":{"description":"Invalid UUID, or domain is not delivery_type=forward","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forwarding rules apply only to domains with delivery_type=forward"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to list forwarding rules"}}}}}}}},"post":{"tags":["Inbound"],"summary":"Add a forwarding rule to a domain","description":"Creates a forwarding rule.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["localpart","destination"],"properties":{"localpart":{"type":"string","description":"Address prefix to match. Use the literal \"*\" for catch-all. Otherwise must be a valid RFC 5321 local-part (max 64 chars). Stored lowercased; plus-addressing is handled at match time, so a rule for \"support\" also matches \"support+anything\".","example":"support"},"destination":{"type":"string","description":"Bare email address (local@domain), or wildcard destination (*@domain). No display names, no quoted local-parts.","example":"team@theirinbox.com"},"active":{"type":"boolean","default":true,"description":"Inactive rules are stored but ignored at RCPT TO. Use this for soft-disable rather than DELETE if you plan to re-enable."}}},"examples":{"Targeted alias":{"value":{"localpart":"support","destination":"team@theirinbox.com"}},"Catch-all":{"value":{"localpart":"*","destination":"inbox@theirinbox.com"}},"Wildcard destination":{"value":{"localpart":"*","destination":"*@theirinbox.com"}}}}}},"responses":{"201":{"description":"Rule created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"localpart":{"type":"string"},"destination":{"type":"string","example":"*@theirinbox.com"},"active":{"type":"integer","enum":[0,1]},"verified":{"type":"integer","enum":[0,1],"description":"Set to 1 once the destination address owner has clicked the verification link sent on rule create. Wildcard destinations are verified by sending the verification email to postmaster. Until 1, inbound-edge will not deliver mail to this rule (the matching index filters verified = 1)."},"last_modified":{"type":"integer"},"created_at":{"type":"integer"}}}}}}}},"400":{"description":"Invalid input or domain is not delivery_type=forward","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"destination must be a bare email address (local@domain) or wildcard destination (*@domain)"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"409":{"description":"A rule with this (localpart, destination) already exists for this domain","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"A forwarding rule with this localpart and destination already exists"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create forwarding rule"}}}}}}}}},"/inbound/domains/{uuid}/forward-rules/{ruleUuid}":{"get":{"tags":["Inbound"],"summary":"Get a single forwarding rule","description":"Returns one forwarding rule by UUID. Returns 404 if the rule has been deleted.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}},{"name":"ruleUuid","in":"path","required":true,"description":"UUID of the forwarding rule","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"responses":{"200":{"description":"Rule found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"localpart":{"type":"string"},"destination":{"type":"string","example":"*@theirinbox.com"},"active":{"type":"integer","enum":[0,1]},"verified":{"type":"integer","enum":[0,1],"description":"Set to 1 once the destination address owner has clicked the verification link sent on rule create. Wildcard destinations are verified by sending the verification email to postmaster. Until 1, inbound-edge will not deliver mail to this rule (the matching index filters verified = 1)."},"last_modified":{"type":"integer"},"created_at":{"type":"integer"}}}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Rule or domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forwarding rule not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch forwarding rule"}}}}}}}},"patch":{"tags":["Inbound"],"summary":"Update a forwarding rule","description":"Updates a forwarding rule.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}},{"name":"ruleUuid","in":"path","required":true,"description":"UUID of the forwarding rule","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destination":{"type":"string","description":"New destination email or wildcard destination. Validated as local@domain or *@domain."},"active":{"type":"boolean","description":"Toggle the rule on/off without deleting it."}}},"examples":{"Re-target destination":{"value":{"destination":"newteam@theirinbox.com"}},"Re-target wildcard destination":{"value":{"destination":"*@theirinbox.com"}},"Pause the rule":{"value":{"active":false}}}}}},"responses":{"200":{"description":"Rule updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"localpart":{"type":"string"},"destination":{"type":"string","example":"*@theirinbox.com"},"active":{"type":"integer","enum":[0,1]},"verified":{"type":"integer","enum":[0,1],"description":"Set to 1 once the destination address owner has clicked the verification link sent on rule create. Wildcard destinations are verified by sending the verification email to postmaster. Until 1, inbound-edge will not deliver mail to this rule (the matching index filters verified = 1)."},"last_modified":{"type":"integer"},"created_at":{"type":"integer"}}}}}}}},"400":{"description":"Invalid input, or attempt to change immutable localpart","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"localpart cannot be changed; delete the rule and create a new one to rename it"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Rule or domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forwarding rule not found"}}}}}},"409":{"description":"Update would collide with another rule on (localpart, destination)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Another forwarding rule already exists with this localpart and destination"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update forwarding rule"}}}}}}}},"delete":{"tags":["Inbound"],"summary":"Delete a forwarding rule","description":"Deletes the rule. Inbound-edge stops considering it on next sync.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}},{"name":"ruleUuid","in":"path","required":true,"description":"UUID of the forwarding rule","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"responses":{"200":{"description":"Rule deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Forwarding rule deleted"}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Rule or domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forwarding rule not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete forwarding rule"}}}}}}}}},"/inbound/forward-destinations":{"get":{"tags":["Inbound"],"summary":"List verified (and pending) forwarding destinations","description":"Lists forwarding destinations and their verification status.","responses":{"200":{"description":"Destinations listed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"7c1f7c14-1234-4abc-8def-0123456789ab"},"email":{"type":"string","format":"email","example":"team@theirinbox.com"},"verified":{"type":"integer","enum":[0,1],"description":"1 once the destination owner has clicked the verification link. Until 1, no inbound mail is delivered to rules pointing at this address.","example":1},"verified_at":{"type":"integer","nullable":true,"description":"Unix seconds when the destination was verified. Null while pending.","example":1735937552},"created_at":{"type":"integer","example":1735937552},"last_modified":{"type":"integer","example":1735937552}}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to list verified destinations"}}}}}}}}},"/inbound/forward-destinations/{uuid}/resend":{"post":{"tags":["Inbound"],"summary":"Resend the verification email for a pending destination","description":"Resends the verification email for a pending destination.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the verified_destinations row","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"responses":{"200":{"description":"Verification email sent","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Verification email sent"},"result":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"}}}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid destination UUID"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Destination not found for this owner","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Destination not found"}}}}}},"409":{"description":"Destination is already verified","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Destination is already verified"}}}}}},"429":{"description":"Per-destination resend cap hit","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Too many verification emails sent for this destination in the last 24 hours"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to resend verification email"}}}}}}}}},"/inbound/forward-destinations/verify":{"post":{"tags":["Inbound"],"summary":"Consume a forwarding-destination verification token","description":"Verifies a forwarding destination via the token from the email link. Public — no auth.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Opaque verification token from the email link's ?token= query parameter.","example":"lkM2_oXk-OQAAAAA..."}}}}}},"responses":{"200":{"description":"Token consumed (or was already consumed for this destination)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"status":{"type":"string","enum":["verified","already_verified"],"example":"verified"},"email":{"type":"string","format":"email","example":"team@theirinbox.com"},"rules_updated":{"type":"integer","description":"Number of forwarding rules flipped to verified = 1 by this request. Only present when status = verified.","example":3}}}}}},"400":{"description":"Invalid request body or malformed token","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid token"}}}}}},"404":{"description":"Token not recognized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"status":{"type":"string","example":"invalid"},"error":{"type":"string","example":"Verification link is invalid or has been revoked."}}}}}},"410":{"description":"Token expired (TTL is 48h)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"status":{"type":"string","example":"expired"},"error":{"type":"string","example":"Verification link has expired. Ask the JetEmail account owner to resend it."}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to verify destination"}}}}}}}}},"/inbound/settings/{uuid}":{"get":{"tags":["Inbound"],"summary":"Get inbound domain settings","description":"Returns the full configuration for a specific inbound domain. Mode-specific fields (smtp_servers, webhook_url and friends, forward_*_verified) are only present when relevant to the domain's delivery_type.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"responses":{"200":{"description":"Successfully retrieved domain settings","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"result":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"domain":{"type":"string","example":"example.com"},"delivery_type":{"type":"string","enum":["smtp","webhook","forward"],"example":"smtp"},"status":{"type":"string","enum":["active","disabled"],"example":"active"},"smtp_servers":{"type":"array","nullable":true,"description":"Only populated for delivery_type=smtp; null otherwise.","items":{"type":"object","properties":{"url":{"type":"string","example":"mail.example.com:25"},"priority":{"type":"integer","example":1},"tls_enabled":{"type":"boolean","example":false},"timeout":{"type":"integer","example":30000}}}},"webhook_url":{"type":"string","format":"uri","nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise.","example":"https://example.com/webhook/inbound"},"webhook_method":{"type":"string","enum":["POST","PUT"],"nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise."},"webhook_headers":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise."},"webhook_timeout":{"type":"integer","nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise.","example":30000},"webhook_retry_count":{"type":"integer","nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise.","example":3},"webhook_auth_header":{"type":"string","nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise."},"webhook_secret":{"type":"string","nullable":true,"description":"Only populated for delivery_type=webhook; null otherwise. Used to validate the HMAC signature on webhook payloads."},"forward_mx_verified":{"type":"integer","enum":[0,1],"description":"Only present for delivery_type=forward. DNS verification flag for the customer's MX record. Inbound mail is rejected with 550 until all four forward_*_verified flags are 1.","example":0},"forward_dkim_verified":{"type":"integer","enum":[0,1],"description":"Only present for delivery_type=forward. DNS verification flag for the customer's DKIM CNAME.","example":0},"forward_spf_verified":{"type":"integer","enum":[0,1],"description":"Only present for delivery_type=forward. DNS verification flag for the customer's SPF record.","example":0},"forward_dmarc_verified":{"type":"integer","enum":[0,1],"description":"Only present for delivery_type=forward. DNS verification flag for the customer's DMARC record.","example":0},"last_modified":{"type":"integer","nullable":true,"description":"Unix epoch seconds.","example":1735937552},"created_at":{"type":"integer","nullable":true,"description":"Unix epoch seconds.","example":1735937552}}}}}}}},"400":{"description":"Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UUID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch domain settings"}}}}}}}},"patch":{"tags":["Inbound"],"summary":"Update inbound domain settings","description":"Updates the configuration of an inbound domain. Mode-specific fields are strictly enforced: smtp_servers is only allowed when the effective delivery_type is smtp, the webhook_* fields are only allowed when it is webhook, and forward accepts neither. The \"effective\" type is the new delivery_type if you are changing it in this request, otherwise the current one. Sending fields from the wrong mode returns 400. The forward_*_verified DNS flags are read-only and cannot be set via this endpoint.","parameters":[{"name":"uuid","in":"path","required":true,"description":"UUID of the inbound domain","schema":{"type":"string","format":"uuid","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Any subset of the listed fields. At least one updatable field is required; sending an empty body returns 400.","properties":{"status":{"type":"string","enum":["active","disabled"],"description":"Domain status. \"disabled\" causes inbound-edge to stop accepting mail for the domain."},"delivery_type":{"type":"string","enum":["smtp","webhook","forward"],"description":"Switch the domain's delivery mode. The body may also include the new mode's fields in the same request."},"smtp_servers":{"type":"array","description":"Only for delivery_type=smtp. Rejected with 400 if sent on a webhook or forward domain.","items":{"oneOf":[{"type":"string","example":"mail.example.com:25"},{"type":"object","required":["url"],"properties":{"url":{"type":"string","example":"mail.example.com:25"},"priority":{"type":"integer","example":1},"tls_enabled":{"type":"boolean","default":false},"timeout":{"type":"integer","default":30000}}}]}},"webhook_url":{"type":"string","format":"uri","nullable":true,"description":"Only for delivery_type=webhook. Rejected with 400 if sent on an smtp or forward domain. Pass null to clear.","example":"https://example.com/webhook/inbound"},"webhook_method":{"type":"string","enum":["POST","PUT"],"description":"Only for delivery_type=webhook. Rejected with 400 if sent on an smtp or forward domain."},"webhook_headers":{"type":"object","additionalProperties":{"type":"string"},"nullable":true,"description":"Only for delivery_type=webhook. Rejected with 400 if sent on an smtp or forward domain. Pass null to clear."},"webhook_timeout":{"type":"integer","nullable":true,"description":"Only for delivery_type=webhook. Rejected with 400 if sent on an smtp or forward domain."},"webhook_retry_count":{"type":"integer","nullable":true,"description":"Only for delivery_type=webhook. Rejected with 400 if sent on an smtp or forward domain."},"webhook_auth_header":{"type":"string","nullable":true,"description":"Only for delivery_type=webhook. Rejected with 400 if sent on an smtp or forward domain."}}},"examples":{"Disable a domain":{"value":{"status":"disabled"}},"Update SMTP servers":{"value":{"smtp_servers":[{"url":"mail.example.com:587","priority":1,"tls_enabled":true}]}},"Switch from smtp to webhook":{"summary":"Atomic mode change with new mode's fields in the same request","value":{"delivery_type":"webhook","webhook_url":"https://example.com/webhook/inbound"}},"Switch to forwarding":{"summary":"Forward delivery accepts no further config; rules are added separately via /forward-rules","value":{"delivery_type":"forward"}}}}}},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Domain updated successfully"}}}}}},"400":{"description":"Bad Request - Invalid input or cross-mode field bleed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid input format"}}},"examples":{"No fields to update":{"value":{"success":false,"error":"No fields to update"}},"Wrong fields for delivery_type=forward":{"summary":"smtp_servers or webhook_* sent on a forward domain","value":{"success":false,"error":"Fields not allowed for delivery_type=forward: smtp_servers, webhook_url"}},"Wrong fields for delivery_type=smtp":{"summary":"webhook_* sent on an smtp domain","value":{"success":false,"error":"Fields not allowed for delivery_type=smtp: webhook_url"}},"Wrong fields for delivery_type=webhook":{"summary":"smtp_servers sent on a webhook domain","value":{"success":false,"error":"Fields not allowed for delivery_type=webhook: smtp_servers"}},"Invalid delivery_type":{"value":{"success":false,"error":"delivery_type must be smtp, webhook, or forward"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not Found - Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update domain"}}}}}}}}},"/inbound/logs":{"get":{"tags":["Inbound"],"summary":"Get inbound email logs","description":"Retrieves logs of inbound email activity with filtering options. Either uuid (for domain) or subdomain_id parameter is required.","parameters":[{"name":"uuid","in":"query","description":"UUID of the inbound domain to fetch logs for. Either uuid or subdomain_id is required.","schema":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"}},{"name":"subdomain_id","in":"query","description":"ID of the subdomain to fetch logs for. Either uuid or subdomain_id is required.","schema":{"type":"integer","minimum":1}},{"name":"limit","in":"query","description":"Number of records to return (1-1000)","schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}},{"name":"page","in":"query","description":"Page number for pagination","schema":{"type":"integer","minimum":1,"default":1}},{"name":"offset","in":"query","description":"Number of records to skip (alternative to page)","schema":{"type":"integer","minimum":0,"default":0}},{"name":"domains[]","in":"query","description":"Widen the query from the domain identified by uuid to that domain plus its subdomains. Repeat once per domain. Values outside the authorised domain and its subdomains are ignored; if none are authorised the request is rejected.","schema":{"type":"array","items":{"type":"string"}}},{"name":"uid","in":"query","description":"Filter by unique identifier","schema":{"type":"string","pattern":"^[A-Za-z0-9-_]{1,100}$"}},{"name":"logtype","in":"query","description":"Filter to messages that reached this stage. The full timeline of a matched message is still returned.","schema":{"type":"string","enum":["spam","delivery","inbound","outbound","blocked","rejected"]}},{"name":"subject","in":"query","description":"Filter by email subject","schema":{"type":"string","maxLength":500}},{"name":"from","in":"query","description":"Filter by sender email","schema":{"type":"string","format":"email"}},{"name":"from_domain","in":"query","description":"Filter by the sender's domain. Matches the domain itself and any subdomain of it. Distinct from the recipient domain the message arrived on, which is selected with uuid/subdomain_id.","schema":{"type":"string","maxLength":253,"example":"example.com"}},{"name":"to","in":"query","description":"Filter by recipient email","schema":{"type":"string","format":"email"}},{"name":"spamscore_min","in":"query","description":"Filter by minimum spam score","schema":{"type":"number","minimum":0}},{"name":"spamscore_max","in":"query","description":"Filter by maximum spam score","schema":{"type":"number","minimum":0}},{"name":"host","in":"query","description":"Filter by the delivery host a message was forwarded to. Only delivery events carry a host; use from_domain to filter by the sending domain.","schema":{"type":"string","maxLength":100}},{"name":"ip","in":"query","description":"Filter by IP address","schema":{"type":"string","pattern":"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"}},{"name":"date_from","in":"query","description":"Filter by start date (Unix timestamp in milliseconds; values that look like seconds are scaled up)","schema":{"type":"integer","minimum":0}},{"name":"date_to","in":"query","description":"Filter by end date (Unix timestamp in milliseconds; values that look like seconds are scaled up)","schema":{"type":"integer","minimum":0}},{"name":"sort_by","in":"query","description":"Field to sort by","schema":{"type":"string","default":"date","maxLength":50}},{"name":"sort_order","in":"query","description":"Sort order","schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"}}],"responses":{"200":{"description":"Successfully retrieved logs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","description":"Consolidated log entries. Each entry represents a single inbound email (keyed by uid) with aggregated delivery/rejection counts and an actions array containing the individual underlying log rows.","items":{"type":"object","properties":{"uid":{"type":"string","description":"Unique identifier for the email","example":"67020a88e9ab3a023e12"},"status":{"type":"string","description":"Overall status of the email across all actions (e.g. delivered, rejected, pending)","example":"delivered"},"from":{"type":"string","description":"Sender email address","example":"sender@example.com"},"to":{"type":"string","description":"Recipient email address","example":"recipient@example.com"},"subject":{"type":"string","description":"Email subject","example":"Re: Online afspraken"},"rejected_count":{"type":"integer","description":"Number of rejected delivery attempts aggregated into this entry","example":12},"delivery_count":{"type":"integer","description":"Number of successful delivery attempts aggregated into this entry","example":1},"delivered_timestamp":{"type":"integer","format":"int64","description":"Millisecond Unix timestamp of the successful delivery. 0 or null if never delivered.","example":1776972847891},"rejected_response":{"type":"string","description":"Representative SMTP response for the most recent rejection, if any","example":"RCPT TO failed for info@example.com: 450 4.1.8 ..."},"response":{"type":"string","description":"Representative SMTP response for the successful delivery, if any","example":"250 2.0.0 Ok: queued as 638B63A5AD5"},"actions":{"type":"array","description":"Individual log actions that make up this consolidated entry, in chronological order. Each item is a single underlying log row (inbound receipt, rejection, delivery attempt, spam evaluation, etc.).","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this action row","example":"bc1ca372-0000-0000-0000-000000000000"},"logtype":{"type":"string","description":"Type of action. Known values include: inbound, delivery, REJECTED, spam, outbound.","example":"inbound"},"response":{"type":"string","description":"SMTP or processing response for this action","example":"250 2.0.0 Ok: queued as 638B63A5AD5"},"date":{"type":"integer","format":"int64","description":"Millisecond Unix timestamp of the action","example":1776933973950},"timestamp":{"type":"string","format":"date-time","description":"ISO-8601 timestamp of the action","example":"2026-04-23T08:46:13.950Z"},"host":{"type":"string","description":"Host involved in the action","example":""},"ip":{"type":"string","description":"IP address associated with the action","example":""},"port":{"type":"integer","description":"Port number used","example":0},"mode":{"type":"string","description":"Connection mode (smtp, http, https)","example":""},"delay":{"type":"number","description":"Delay in seconds before this action","example":0},"spam_score":{"type":"number","description":"Spam score evaluated for this action","example":0},"spam_report":{"type":"string","description":"Spam report text for this action","example":""}}}}}}},"count":{"type":"integer","description":"Number of entries returned in this response","example":1}}}}}},"400":{"description":"Bad Request - Invalid parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid parameter format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Required information not found"}}}}}},"404":{"description":"Not Found - No results found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No results found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Failed to fetch logs"}}}}}}}}},"/inbound/filters/blocklist":{"get":{"tags":["Inbound"],"summary":"Get domain blocklist rules","description":"Retrieves blocklist rules for a specific domain. Provide exactly one of: domain, subdomain_id, or subdomain_uuid.","parameters":[{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Fully qualified domain name"},{"name":"subdomain_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric subdomain ID"},{"name":"subdomain_uuid","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Subdomain UUID"}],"responses":{"200":{"description":"Successfully retrieved blocklist rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rules":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"userId":{"type":"string","nullable":true},"organizationId":{"type":"string","nullable":true},"domain":{"type":"string","example":"example.com"},"action":{"type":"string","enum":["DENY"]},"name":{"type":"string","example":"Block spam senders"},"description":{"type":"string","nullable":true},"enabled":{"type":"integer","enum":[0,1],"example":1},"deleted":{"type":"integer","enum":[0,1],"example":0},"last_modified":{"type":"integer","example":1735689600},"conditions":{"type":"object","properties":{"senders":{"type":"array","items":{"type":"object","properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string"}}}},"recipients":{"type":"array","items":{"type":"object","properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"body":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["contains","regex"]},"body_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1]},"max_body_size":{"type":"integer","nullable":true}}}},"headers":{"type":"array","items":{"type":"object","properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"ips":{"type":"array","items":{"type":"object","properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"192.168.1.0/24"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true},"max_size":{"type":"integer","nullable":true}}},"attachments":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","none","has_attachments"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}}}}}}}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"domain, subdomain_id, or subdomain_uuid is required"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch blocklist rules"}}}}}}}},"post":{"tags":["Inbound"],"summary":"Create domain blocklist rule","description":"Creates a new blocklist rule for a domain. Provide the target via one of: domain (body or query param), subdomain_id (query), or subdomain_uuid (query).","parameters":[{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Domain (alternative to body.domain)"},{"name":"subdomain_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric subdomain ID"},{"name":"subdomain_uuid","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Subdomain UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Rule name (alphanumeric, spaces, hyphens, underscores, periods)","example":"Block spam senders"},"description":{"type":"string","maxLength":500,"description":"Optional rule description"},"domain":{"type":"string","description":"Domain to apply the rule to (alternative to query param)","example":"example.com"},"senders":{"type":"array","items":{"type":"object","required":["sender_type","sender_value"],"properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string","example":"spam-domain.com"}}}},"recipients":{"type":"array","items":{"type":"object","required":["recipient_type","recipient_value"],"properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","required":["match_type","subject_value"],"properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"body":{"type":"array","items":{"type":"object","required":["match_type","body_value"],"properties":{"match_type":{"type":"string","enum":["contains","regex"]},"body_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0},"max_body_size":{"type":"integer","nullable":true}}}},"headers":{"type":"array","items":{"type":"object","required":["header_name","match_type"],"properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"ips":{"type":"array","items":{"type":"object","required":["ip_type","ip_value"],"properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"10.0.0.1"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true},"max_size":{"type":"integer","nullable":true}}},"attachments":{"type":"array","items":{"type":"object","required":["match_type"],"properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","none","has_attachments"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}}}},"examples":{"Block by sender domain":{"value":{"name":"Block spam domain","domain":"example.com","senders":[{"sender_type":"domain","sender_value":"spam-domain.com"}]}},"Block by IP":{"value":{"name":"Block suspicious IP","domain":"example.com","ips":[{"ip_type":"single","ip_value":"192.168.1.100"}]}}}}}},"responses":{"200":{"description":"Rule created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"uuid":{"type":"string","format":"uuid","description":"UUID of the created rule","example":"550e8400-e29b-41d4-a716-446655440000"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Missing rule name"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create blocklist rule"}}}}}}}}},"/inbound/quarantine-release":{"post":{"tags":["Inbound"],"summary":"Release email from quarantine","description":"Releases a quarantined email for delivery using its UID.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uid"],"properties":{"uid":{"type":"string","pattern":"^[A-Za-z0-9-_.]{1,100}$","description":"Unique identifier of the quarantined message","example":"DE398F73-6CBC-4333-B394-6DAA6792525B.1"}}}}}},"responses":{"200":{"description":"Successfully retrieved and processed quarantined email","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"EML file successfully released from quarantine and sent to mail server"},"data":{"type":"object","properties":{"uid":{"type":"string","description":"Original UID of the message","example":"DE398F73-6CBC-4333-B394-6DAA6792525B.1"},"domain_uuid":{"type":"string","format":"uuid","description":"UUID of the domain the message belonged to","example":"12345678-1234-4321-abcd-123456789012"},"domain_name":{"type":"string","description":"Name of the domain the message belonged to","example":"example.com"}}}}}}}},"400":{"description":"Bad request - Invalid UID format or missing UID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid UID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User authentication, log location, or db_uuid not found"}}}}}},"404":{"description":"UID not found in logs or EML file not found in quarantine","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"UID not found in any authorized domain logs"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to send EML to mail server (502)"},"details":{"type":"string","description":"Additional error details when available","example":"Bad Gateway: Upstream server error"}}}}}}}}},"/inbound/filters/blocklist/{uuid}":{"get":{"tags":["Inbound"],"summary":"Get domain blocklist rule","description":"Retrieves a single domain blocklist rule with all its conditions","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the blocklist rule"}],"responses":{"200":{"description":"Successfully retrieved rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rule":{"type":"object","description":"Rule object with conditions (same schema as list response items)"}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid uuid"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}},"patch":{"tags":["Inbound"],"summary":"Update domain blocklist rule","description":"Updates an existing domain blocklist rule. Can update name, description, enabled, and/or conditions. When updating conditions, the entire condition type is replaced.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the blocklist rule to update"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500,"nullable":true},"enabled":{"type":"boolean"},"senders":{"type":"array","items":{"type":"object"}},"recipients":{"type":"array","items":{"type":"object"}},"subjects":{"type":"array","items":{"type":"object"}},"body":{"type":"array","items":{"type":"object"}},"headers":{"type":"array","items":{"type":"object"}},"ips":{"type":"array","items":{"type":"object"}},"size":{"type":"object","nullable":true},"attachments":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Rule updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No fields to update"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update blocklist rule"}}}}}}}},"delete":{"tags":["Inbound"],"summary":"Delete domain blocklist rule","description":"Deletes a domain blocklist rule","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the blocklist rule to delete"}],"responses":{"200":{"description":"Rule deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid uuid"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete blocklist rule"}}}}}}}}},"/inbound/filters/allowlist":{"get":{"tags":["Inbound"],"summary":"Get domain allowlist rules","description":"Retrieves allowlist rules for a specific domain. Provide exactly one of: domain, subdomain_id, or subdomain_uuid.","parameters":[{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Fully qualified domain name"},{"name":"subdomain_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric subdomain ID"},{"name":"subdomain_uuid","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Subdomain UUID"}],"responses":{"200":{"description":"Successfully retrieved allowlist rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rules":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"userId":{"type":"string","nullable":true},"organizationId":{"type":"string","nullable":true},"domain":{"type":"string","example":"example.com"},"action":{"type":"string","enum":["ALLOW"]},"name":{"type":"string","example":"Allow trusted senders"},"description":{"type":"string","nullable":true},"enabled":{"type":"integer","enum":[0,1],"example":1},"deleted":{"type":"integer","enum":[0,1],"example":0},"last_modified":{"type":"integer","example":1735689600},"conditions":{"type":"object","properties":{"senders":{"type":"array","items":{"type":"object","properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string"}}}},"recipients":{"type":"array","items":{"type":"object","properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"body":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["contains","regex"]},"body_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1]},"max_body_size":{"type":"integer","nullable":true}}}},"headers":{"type":"array","items":{"type":"object","properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"ips":{"type":"array","items":{"type":"object","properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"192.168.1.0/24"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true},"max_size":{"type":"integer","nullable":true}}},"attachments":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","none","has_attachments"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}}}}}}}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"domain, subdomain_id, or subdomain_uuid is required"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch allowlist rules"}}}}}}}},"post":{"tags":["Inbound"],"summary":"Create domain allowlist rule","description":"Creates a new allowlist rule for a domain. Provide the target via one of: domain (body or query param), subdomain_id (query), or subdomain_uuid (query).","parameters":[{"name":"domain","in":"query","required":false,"schema":{"type":"string"},"description":"Domain (alternative to body.domain)"},{"name":"subdomain_id","in":"query","required":false,"schema":{"type":"integer"},"description":"Numeric subdomain ID"},{"name":"subdomain_uuid","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"description":"Subdomain UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Rule name (alphanumeric, spaces, hyphens, underscores, periods)","example":"Allow trusted senders"},"description":{"type":"string","maxLength":500,"description":"Optional rule description"},"domain":{"type":"string","description":"Domain to apply the rule to (alternative to query param)","example":"example.com"},"senders":{"type":"array","items":{"type":"object","required":["sender_type","sender_value"],"properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string","example":"partner.com"}}}},"recipients":{"type":"array","items":{"type":"object","required":["recipient_type","recipient_value"],"properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","required":["match_type","subject_value"],"properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"body":{"type":"array","items":{"type":"object","required":["match_type","body_value"],"properties":{"match_type":{"type":"string","enum":["contains","regex"]},"body_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0},"max_body_size":{"type":"integer","nullable":true}}}},"headers":{"type":"array","items":{"type":"object","required":["header_name","match_type"],"properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"ips":{"type":"array","items":{"type":"object","required":["ip_type","ip_value"],"properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"10.0.0.1"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true},"max_size":{"type":"integer","nullable":true}}},"attachments":{"type":"array","items":{"type":"object","required":["match_type"],"properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","none","has_attachments"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}}}},"examples":{"Allow by sender domain":{"value":{"name":"Allow partner emails","domain":"example.com","senders":[{"sender_type":"domain","sender_value":"partner.com"}]}},"Allow by IP range":{"value":{"name":"Allow office IPs","domain":"example.com","ips":[{"ip_type":"cidr","ip_value":"10.0.0.0/8"}]}}}}}},"responses":{"200":{"description":"Rule created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"uuid":{"type":"string","format":"uuid","description":"UUID of the created rule","example":"550e8400-e29b-41d4-a716-446655440000"}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Missing rule name"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Domain not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Domain not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create allowlist rule"}}}}}}}}},"/inbound/filters/allowlist/{uuid}":{"get":{"tags":["Inbound"],"summary":"Get domain allowlist rule","description":"Retrieves a single domain allowlist rule with all its conditions","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the allowlist rule"}],"responses":{"200":{"description":"Successfully retrieved rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rule":{"type":"object","description":"Rule object with conditions (same schema as list response items)"}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid uuid"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}},"patch":{"tags":["Inbound"],"summary":"Update domain allowlist rule","description":"Updates an existing domain allowlist rule. Can update name, description, enabled, and/or conditions. When updating conditions, the entire condition type is replaced.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the allowlist rule to update"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500,"nullable":true},"enabled":{"type":"boolean"},"senders":{"type":"array","items":{"type":"object"}},"recipients":{"type":"array","items":{"type":"object"}},"subjects":{"type":"array","items":{"type":"object"}},"body":{"type":"array","items":{"type":"object"}},"headers":{"type":"array","items":{"type":"object"}},"ips":{"type":"array","items":{"type":"object"}},"size":{"type":"object","nullable":true},"attachments":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Rule updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No fields to update"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update allowlist rule"}}}}}}}},"delete":{"tags":["Inbound"],"summary":"Delete domain allowlist rule","description":"Deletes a domain allowlist rule","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the allowlist rule to delete"}],"responses":{"200":{"description":"Rule deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Invalid UUID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid uuid"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete allowlist rule"}}}}}}}}},"/inbound/account/allowlist":{"get":{"tags":["Inbound"],"summary":"Get account-level allowlist rules","description":"Retrieves all allowlist rules that apply across all domains in the authenticated user's account. These rules are scoped by userId/organizationId and are not tied to any specific domain.","responses":{"200":{"description":"Successfully retrieved account allowlist rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rules":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Unique identifier for the rule","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","description":"Rule name","example":"Allow partner emails"},"description":{"type":"string","nullable":true,"description":"Optional rule description","example":"Allow all emails from partner domain"},"action":{"type":"string","enum":["ALLOW"]},"userId":{"type":"string","nullable":true,"description":"User UUID who owns this rule"},"organizationId":{"type":"string","nullable":true,"description":"Organization UUID this rule belongs to"},"enabled":{"type":"integer","enum":[0,1],"description":"Whether the rule is enabled","example":1},"deleted":{"type":"integer","enum":[0,1],"example":0},"last_modified":{"type":"integer","description":"Unix timestamp of last modification","example":1735689600},"conditions":{"type":"object","properties":{"senders":{"type":"array","items":{"type":"object","properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string","example":"partner.com"}}}},"recipients":{"type":"array","items":{"type":"object","properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"headers":{"type":"array","items":{"type":"object","properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"ips":{"type":"array","items":{"type":"object","properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"192.168.1.0/24"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true,"description":"Minimum size in bytes"},"max_size":{"type":"integer","nullable":true,"description":"Maximum size in bytes"}}},"attachments":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","none"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}}}}}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch account allowlist rules"}}}}}}}},"post":{"tags":["Inbound"],"summary":"Create account-level allowlist rule","description":"Creates a new allowlist rule that applies across all domains in the authenticated user's account. Supports all condition types: senders, recipients, subjects, body, headers, IPs, size, and attachments.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Rule name (alphanumeric, spaces, hyphens, underscores, periods)","example":"Allow partner emails"},"description":{"type":"string","maxLength":500,"description":"Optional rule description","example":"Allow all emails from partner domain across all our domains"},"senders":{"type":"array","items":{"type":"object","required":["sender_type","sender_value"],"properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string","example":"partner.com"}}}},"recipients":{"type":"array","items":{"type":"object","required":["recipient_type","recipient_value"],"properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","required":["match_type","subject_value"],"properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"body":{"type":"array","items":{"type":"object","required":["match_type","body_value"],"properties":{"match_type":{"type":"string","enum":["contains","regex"]},"body_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"headers":{"type":"array","items":{"type":"object","required":["header_name","match_type"],"properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"ips":{"type":"array","items":{"type":"object","required":["ip_type","ip_value"],"properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"10.0.0.1"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true,"description":"Minimum size in bytes"},"max_size":{"type":"integer","nullable":true,"description":"Maximum size in bytes"}}},"attachments":{"type":"array","items":{"type":"object","required":["match_type"],"properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","none"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}}}},"examples":{"Allow by sender domain":{"value":{"name":"Allow partner emails","description":"Allow all emails from partner.com across all domains","senders":[{"sender_type":"domain","sender_value":"partner.com"}]}},"Allow by IP range":{"value":{"name":"Allow office IPs","ips":[{"ip_type":"cidr","ip_value":"10.0.0.0/8"}]}}}}}},"responses":{"200":{"description":"Rule created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"uuid":{"type":"string","format":"uuid","description":"UUID of the created rule","example":"550e8400-e29b-41d4-a716-446655440000"}}}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Missing rule name"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create account allowlist rule"}}}}}}}}},"/inbound/account/allowlist/{uuid}":{"get":{"tags":["Inbound"],"summary":"Get account-level allowlist rule","description":"Retrieves a single account-level allowlist rule with all its conditions","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the account allowlist rule"}],"responses":{"200":{"description":"Successfully retrieved rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rule":{"type":"object","description":"Rule object with conditions (same schema as list response items)"}}}}}},"403":{"description":"Forbidden - Rule not owned by caller","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}},"patch":{"tags":["Inbound"],"summary":"Update account-level allowlist rule","description":"Updates an existing account-level allowlist rule. Can update metadata (name, description, enabled) and/or conditions. When updating conditions, the entire condition type is replaced.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the account allowlist rule to update"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500,"nullable":true},"enabled":{"type":"boolean"},"senders":{"type":"array","items":{"type":"object"}},"recipients":{"type":"array","items":{"type":"object"}},"subjects":{"type":"array","items":{"type":"object"}},"body":{"type":"array","items":{"type":"object"}},"headers":{"type":"array","items":{"type":"object"}},"ips":{"type":"array","items":{"type":"object"}},"size":{"type":"object","nullable":true},"attachments":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Rule updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No fields to update"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}},"delete":{"tags":["Inbound"],"summary":"Delete account-level allowlist rule","description":"Deletes an account-level allowlist rule","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the account allowlist rule to delete"}],"responses":{"200":{"description":"Rule deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}}},"/inbound/account/blocklist":{"get":{"tags":["Inbound"],"summary":"Get account-level blocklist rules","description":"Retrieves all blocklist rules that apply across all domains in the authenticated user's account.","responses":{"200":{"description":"Successfully retrieved account blocklist rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rules":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000"},"name":{"type":"string","example":"Block spam domain"},"description":{"type":"string","nullable":true,"example":"Block all emails from known spam domain"},"action":{"type":"string","enum":["DENY"]},"userId":{"type":"string","nullable":true},"organizationId":{"type":"string","nullable":true},"enabled":{"type":"integer","enum":[0,1],"example":1},"deleted":{"type":"integer","enum":[0,1],"example":0},"last_modified":{"type":"integer","example":1735689600},"conditions":{"type":"object","properties":{"senders":{"type":"array","items":{"type":"object","properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string","example":"spam-domain.com"}}}},"recipients":{"type":"array","items":{"type":"object","properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"headers":{"type":"array","items":{"type":"object","properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}},"ips":{"type":"array","items":{"type":"object","properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"192.168.1.100"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true},"max_size":{"type":"integer","nullable":true}}},"attachments":{"type":"array","items":{"type":"object","properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","has_attachments"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1]}}}}}}}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch account blocklist rules"}}}}}}}},"post":{"tags":["Inbound"],"summary":"Create account-level blocklist rule","description":"Creates a new blocklist rule that applies across all domains in the authenticated user's account. The action is automatically set to DENY. Supports all condition types.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Rule name","example":"Block spam domain"},"description":{"type":"string","maxLength":500,"description":"Optional rule description","example":"Block all emails from known spam domain"},"senders":{"type":"array","items":{"type":"object","required":["sender_type","sender_value"],"properties":{"sender_type":{"type":"string","enum":["email","domain","pattern"]},"sender_value":{"type":"string","example":"spam-domain.com"}}}},"recipients":{"type":"array","items":{"type":"object","required":["recipient_type","recipient_value"],"properties":{"recipient_type":{"type":"string","enum":["email","domain","pattern"]},"recipient_value":{"type":"string"}}}},"subjects":{"type":"array","items":{"type":"object","required":["match_type","subject_value"],"properties":{"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex"]},"subject_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"body":{"type":"array","items":{"type":"object","required":["match_type","body_value"],"properties":{"match_type":{"type":"string","enum":["contains","regex"]},"body_value":{"type":"string"},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"headers":{"type":"array","items":{"type":"object","required":["header_name","match_type"],"properties":{"header_name":{"type":"string"},"match_type":{"type":"string","enum":["exact","contains","starts_with","ends_with","regex","exists"]},"header_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}},"ips":{"type":"array","items":{"type":"object","required":["ip_type","ip_value"],"properties":{"ip_type":{"type":"string","enum":["single","cidr","range"]},"ip_value":{"type":"string","example":"192.168.1.100"}}}},"size":{"type":"object","nullable":true,"properties":{"min_size":{"type":"integer","nullable":true},"max_size":{"type":"integer","nullable":true}}},"attachments":{"type":"array","items":{"type":"object","required":["match_type"],"properties":{"match_type":{"type":"string","enum":["filename","extension","mimetype","has_attachments"]},"match_value":{"type":"string","nullable":true},"case_sensitive":{"type":"integer","enum":[0,1],"default":0}}}}}},"examples":{"Block by sender domain":{"value":{"name":"Block spam domain","description":"Block all emails from spam-domain.com","senders":[{"sender_type":"domain","sender_value":"spam-domain.com"}]}},"Block by IP":{"value":{"name":"Block suspicious IP","ips":[{"ip_type":"single","ip_value":"192.168.1.100"}]}}}}}},"responses":{"200":{"description":"Rule created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"uuid":{"type":"string","format":"uuid","description":"UUID of the created rule","example":"550e8400-e29b-41d4-a716-446655440000"}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Missing rule name"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create account blocklist rule"}}}}}}}}},"/inbound/account/blocklist/{uuid}":{"get":{"tags":["Inbound"],"summary":"Get account-level blocklist rule","description":"Retrieves a single account-level blocklist rule with all its conditions","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the account blocklist rule"}],"responses":{"200":{"description":"Successfully retrieved rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rule":{"type":"object","description":"Rule object with conditions (same schema as list response items, includes action field)"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}},"patch":{"tags":["Inbound"],"summary":"Update account-level blocklist rule","description":"Updates an existing account-level blocklist rule. Can update metadata and/or conditions. When updating conditions, the entire condition type is replaced.","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the account blocklist rule to update"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500,"nullable":true},"enabled":{"type":"boolean"},"senders":{"type":"array","items":{"type":"object"}},"recipients":{"type":"array","items":{"type":"object"}},"subjects":{"type":"array","items":{"type":"object"}},"body":{"type":"array","items":{"type":"object"}},"headers":{"type":"array","items":{"type":"object"}},"ips":{"type":"array","items":{"type":"object"}},"size":{"type":"object","nullable":true},"attachments":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Rule updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"No fields to update"}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}},"delete":{"tags":["Inbound"],"summary":"Delete account-level blocklist rule","description":"Deletes an account-level blocklist rule","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the account blocklist rule to delete"}],"responses":{"200":{"description":"Rule deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Forbidden"}}}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}}}}},"/inbound/account/logs":{"get":{"tags":["Inbound"],"summary":"Get logs for all account domains","description":"Retrieves inbound logs across all domains and subdomains owned by the authenticated user/organization. Fans out requests to the logs API for each domain, merges results, and returns a unified sorted and paginated response. Supports the same filter parameters as the per-domain logs endpoint. Limited to 20 domains per request; use the domains parameter to target specific domains if you have more.","parameters":[{"name":"domains","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated list of domain names to filter to (e.g. \"example.com,mail.example.com\"). May also be supplied as a repeated \"domains[]\" parameter. If omitted, queries all domains in the account (up to 20)."},{"name":"logtype","in":"query","required":false,"schema":{"type":"string","enum":["spam","delivery","inbound","outbound","blocked","rejected"]},"description":"Filter to messages that reached this stage. The full timeline of a matched message is still returned."},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"email"},"description":"Filter by recipient email"},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"email"},"description":"Filter by sender email"},{"name":"from_domain","in":"query","required":false,"schema":{"type":"string","maxLength":253,"example":"example.com"},"description":"Filter by the sender's domain. Matches the domain itself and any subdomain of it. Distinct from the recipient domain the message arrived on, which is filtered with the domains parameter."},{"name":"subject","in":"query","required":false,"schema":{"type":"string","maxLength":500},"description":"Filter by subject"},{"name":"ip","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by IP address"},{"name":"date_from","in":"query","required":false,"schema":{"type":"integer"},"description":"Start of date range (Unix timestamp in milliseconds; values that look like seconds are scaled up)"},{"name":"date_to","in":"query","required":false,"schema":{"type":"integer"},"description":"End of date range (Unix timestamp in milliseconds; values that look like seconds are scaled up)"},{"name":"spamscore_min","in":"query","required":false,"schema":{"type":"number"},"description":"Minimum spam score filter"},{"name":"spamscore_max","in":"query","required":false,"schema":{"type":"number"},"description":"Maximum spam score filter"},{"name":"host","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by the delivery host a message was forwarded to. Only delivery events carry a host; use from_domain to filter by the sending domain."},{"name":"port","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":65535},"description":"Filter by port number"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["smtp","http","https"]},"description":"Filter by connection mode"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":100},"description":"Number of entries to return (applied after merging all domains)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"Number of entries to skip"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1},"description":"Page number (alternative to offset, takes precedence)"},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","default":"date"},"description":"Field to sort by"},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","enum":["ASC","DESC"],"default":"DESC"},"description":"Sort direction"}],"responses":{"200":{"description":"Successfully retrieved account-wide logs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","description":"Merged and sorted consolidated log entries from all queried domains. Each entry represents a single inbound email (keyed by uid) with aggregated delivery/rejection counts and an actions array of underlying log rows. Entries are tagged with _domain, _domain_uuid, and _domain_type identifying the source domain.","items":{"type":"object","properties":{"_domain":{"type":"string","description":"Domain this log entry belongs to","example":"example.com"},"_domain_uuid":{"type":"string","description":"UUID of the domain this entry belongs to","example":"550e8400-e29b-41d4-a716-446655440000"},"_domain_type":{"type":"string","enum":["domain","subdomain"],"description":"Whether this is a domain or subdomain"},"uid":{"type":"string","description":"Unique identifier for the email","example":"67020a88e9ab3a023e12"},"status":{"type":"string","description":"Overall status of the email across all actions (e.g. delivered, rejected, pending)","example":"delivered"},"from":{"type":"string","description":"Sender email address","example":"sender@example.com"},"to":{"type":"string","description":"Recipient email address","example":"recipient@example.com"},"subject":{"type":"string","description":"Email subject","example":"Re: Online afspraken"},"rejected_count":{"type":"integer","description":"Number of rejected delivery attempts aggregated into this entry","example":12},"delivery_count":{"type":"integer","description":"Number of successful delivery attempts aggregated into this entry","example":1},"delivered_timestamp":{"type":"integer","format":"int64","description":"Millisecond Unix timestamp of the successful delivery. 0 or null if never delivered.","example":1776972847891},"rejected_response":{"type":"string","description":"Representative SMTP response for the most recent rejection, if any","example":"RCPT TO failed for info@example.com: 450 4.1.8 ..."},"response":{"type":"string","description":"Representative SMTP response for the successful delivery, if any","example":"250 2.0.0 Ok: queued as 638B63A5AD5"},"actions":{"type":"array","description":"Individual log actions that make up this consolidated entry, in chronological order. Each item is a single underlying log row (inbound receipt, rejection, delivery attempt, spam evaluation, etc.).","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for this action row","example":"bc1ca372-0000-0000-0000-000000000000"},"logtype":{"type":"string","description":"Type of action. Known values include: inbound, delivery, REJECTED, spam, outbound.","example":"inbound"},"response":{"type":"string","description":"SMTP or processing response for this action","example":"250 2.0.0 Ok: queued as 638B63A5AD5"},"date":{"type":"integer","format":"int64","description":"Millisecond Unix timestamp of the action","example":1776933973950},"timestamp":{"type":"string","format":"date-time","description":"ISO-8601 timestamp of the action","example":"2026-04-23T08:46:13.950Z"},"host":{"type":"string","description":"Host involved in the action","example":""},"ip":{"type":"string","description":"IP address associated with the action","example":""},"port":{"type":"integer","description":"Port number used","example":0},"mode":{"type":"string","description":"Connection mode (smtp, http, https)","example":""},"delay":{"type":"number","description":"Delay in seconds before this action","example":0},"spam_score":{"type":"number","description":"Spam score evaluated for this action","example":0},"spam_report":{"type":"string","description":"Spam report text for this action","example":""}}}}}}},"pagination":{"type":"object","properties":{"total":{"type":"integer","description":"Total entries across all domains (before pagination)","example":450},"limit":{"type":"integer","example":100},"offset":{"type":"integer","example":0},"returned":{"type":"integer","description":"Number of entries in this response","example":100}}},"domains_queried":{"type":"array","description":"Status of each domain query","items":{"type":"object","properties":{"domain":{"type":"string","example":"example.com"},"domain_uuid":{"type":"string"},"domain_type":{"type":"string","enum":["domain","subdomain"]},"count":{"type":"integer","description":"Number of entries returned for this domain"},"status":{"type":"string","enum":["success","error"]}}}},"total_domains":{"type":"integer","description":"Total number of domains in the account","example":5},"domains_included":{"type":"integer","description":"Number of domains actually queried (may be capped at 20)","example":5}}}}}},"400":{"description":"Bad Request - Invalid filter parameters","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid logtype value. Must be: spam, delivery, inbound, or outbound"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User authentication not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch account inbound logs"}}}}}}}}},"/outbound/suppression":{"get":{"tags":["Outbound"],"summary":"Get suppression rules","description":"Retrieves all suppression rules for the authenticated user","responses":{"200":{"description":"Successfully retrieved suppression rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"target_value":{"type":"string","example":"user@example.com"},"status":{"type":"integer","description":"1 = active, 0 = inactive","example":1},"created_date":{"type":"string","example":"2024-01-15 10:30:00"}}}}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch suppression rules"}}}}}}}},"post":{"tags":["Outbound"],"summary":"Create suppression rule","description":"Suppresses outbound mail to the given recipient email.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_value"],"properties":{"target_value":{"type":"string","format":"email","example":"user@example.com"},"reason":{"type":"string","nullable":true,"example":"Spam reports"}}}}}},"responses":{"200":{"description":"Suppression rule created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"rule":{"type":"object","properties":{"id":{"type":"integer","example":42},"target_value":{"type":"string","example":"user@example.com"},"status":{"type":"integer","example":1},"created_date":{"type":"string","example":"2026-05-11 10:30:00"}}}}}}}},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"target_value \"not-an-email\" is not a valid email"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"409":{"description":"Matching active rule already exists","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"A matching active suppression rule already exists"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create suppression rule"}}}}}}}}},"/outbound/suppression/{id}":{"delete":{"tags":["Outbound"],"summary":"Release suppression rule","description":"Releases a suppression rule, removing it from active suppression","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","minimum":1,"description":"ID of the suppression rule to delete"},"description":"ID of the suppression rule to release"}],"responses":{"200":{"description":"Suppression rule released successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}},"400":{"description":"Bad request - Invalid ID","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid id"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"403":{"description":"Forbidden - User does not have permission to delete this rule","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"You do not have permission to delete this suppression rule"}}}}}},"404":{"description":"Not found - Suppression rule not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Not found"}}}}}},"410":{"description":"Gone - Suppression rule already deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Suppression rule is already deleted"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete suppression rule"}}}}}}}}},"/outbound/suppression/export":{"get":{"tags":["Outbound"],"summary":"Export suppression rules as CSV","description":"Returns active suppression rules as a CSV file.","responses":{"200":{"description":"CSV file of active suppression rules","content":{"text/csv":{"schema":{"type":"string","example":"target_value,status\r\nuser@example.com,1\r\n"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to export suppression rules"}}}}}}}}},"/outbound/suppression/import":{"post":{"tags":["Outbound"],"summary":"Import suppression rules from CSV","description":"Imports recipient emails from a CSV with a target_value column; skips rows that match an existing active rule.","requestBody":{"required":true,"content":{"text/csv":{"schema":{"type":"string","example":"target_value\r\nuser@example.com\r\nother@example.com\r\n"}}}},"responses":{"200":{"description":"Import processed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"inserted":{"type":"integer","example":12},"skipped":{"type":"integer","example":3},"failed":{"type":"array","items":{"type":"object","properties":{"row":{"type":"integer","example":5},"reason":{"type":"string","example":"target_value \"not-an-email\" is not a valid email"}}}}}}}}},"400":{"description":"Invalid CSV or missing columns","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Missing required column \"target_value\""}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Unauthorized"}}}}}},"413":{"description":"Payload too large","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Body exceeds 5242880 bytes"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to load existing rules"}}}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhooks","description":"Returns all webhook configurations for the authenticated user","responses":{"200":{"description":"List of webhooks retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"webhooks":{"type":"array","items":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Unique webhook UUID","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","description":"Human-readable webhook name/identifier","maxLength":64,"example":"Production Webhook"},"url":{"type":"string","format":"uri","description":"Webhook endpoint URL","example":"https://example.com/webhook"},"secret":{"type":"string","description":"Webhook signing secret","example":"whsec_abc123def456..."},"events":{"type":"array","items":{"type":"string","enum":["outbound.delivered","outbound.bounced","outbound.rejected","outbound.deferred","outbound.spam","outbound.dropped","outbound.virus","outbound.opened","outbound.clicked","outbound.complaint","inbound.received","inbound.delivered","inbound.spam","inbound.blocked"]},"description":"List of event types this webhook subscribes to","example":["outbound.delivered","outbound.bounced","inbound.received"]},"status":{"type":"string","enum":["enabled","disabled"],"description":"Webhook status","example":"enabled"},"filter_users":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Filter outbound events by username (null = all)","example":null},"filter_domains":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Filter inbound events by domain (null = all)","example":["example.com"]},"created_at":{"type":"integer","description":"Unix timestamp of creation","example":1736524800},"last_modified":{"type":"integer","description":"Unix timestamp of last modification","example":1736524800}}}}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch webhooks"}}}}}}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook","description":"Creates a new webhook configuration. A signing secret will be automatically generated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","url","events"],"properties":{"name":{"type":"string","maxLength":64,"pattern":"^[a-zA-Z0-9-_\\s]+$","description":"Human-readable webhook name. Only letters, numbers, hyphens, underscores, and spaces allowed.","example":"Production Webhook"},"url":{"type":"string","format":"uri","description":"Webhook endpoint URL (must be http or https)","example":"https://example.com/webhook"},"events":{"type":"array","items":{"type":"string","enum":["outbound.delivered","outbound.bounced","outbound.rejected","outbound.deferred","outbound.spam","outbound.dropped","outbound.virus","outbound.opened","outbound.clicked","outbound.complaint","inbound.received","inbound.delivered","inbound.spam","inbound.blocked"]},"minItems":1,"description":"List of event types to subscribe to. Must only include allowed event types.","example":["outbound.delivered","outbound.bounced","inbound.received"]},"status":{"type":"integer","enum":[0,1],"default":1,"description":"Webhook status: 0 = disabled, 1 = enabled","example":1},"filter_users":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Filter outbound events by username. Must be transactional keys or smarthosts you own. (null = all)","example":null},"filter_domains":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Filter inbound events by domain. Must be inbound domains you own. (null = all)","example":["example.com"]}}},"examples":{"Basic Webhook":{"value":{"name":"My Webhook","url":"https://example.com/webhook","events":["outbound.delivered","outbound.bounced"]}},"Webhook with Filters":{"value":{"name":"Production Webhook","url":"https://example.com/webhook","events":["outbound.delivered","outbound.bounced","inbound.received"],"status":1,"filter_domains":["example.com","test.com"]}}}}}},"responses":{"200":{"description":"Webhook created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Webhook created successfully"},"webhook":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Unique webhook UUID","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","description":"Human-readable webhook name","example":"Production Webhook"},"url":{"type":"string","example":"https://example.com/webhook"},"secret":{"type":"string","description":"The webhook signing secret. Store this securely - it will not be shown again.","example":"whsec_abc123def456..."},"events":{"type":"array","items":{"type":"string","enum":["outbound.queued","outbound.delivered","outbound.bounced","outbound.rejected","outbound.deferred","outbound.spam","outbound.dropped","outbound.virus","outbound.opened","outbound.clicked","outbound.complaint","inbound.received","inbound.delivered","inbound.spam","inbound.blocked"]},"example":["outbound.delivered","outbound.bounced"]},"status":{"type":"string","example":"enabled"},"filter_users":{"type":"array","items":{"type":"string"},"nullable":true,"example":null},"filter_domains":{"type":"array","items":{"type":"string"},"nullable":true,"example":null},"created_at":{"type":"integer","example":1736524800},"last_modified":{"type":"integer","example":1736524800}}}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"URL is required and must be a string"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"403":{"description":"Forbidden - Invalid filter values (users/domains not owned by caller)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid filter_domains: example.com. You can only filter by domains that you own."}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to create webhook"}}}}}}}},"patch":{"tags":["Webhooks"],"summary":"Update a webhook","description":"Updates an existing webhook configuration. Only provided fields will be updated.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uuid"],"properties":{"uuid":{"type":"string","format":"uuid","description":"UUID of the webhook to update","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","maxLength":64,"pattern":"^[a-zA-Z0-9-_\\s]+$","description":"New webhook name. Only letters, numbers, hyphens, underscores, and spaces allowed.","example":"Updated Webhook Name"},"url":{"type":"string","format":"uri","description":"New webhook endpoint URL","example":"https://example.com/new-webhook"},"events":{"type":"array","items":{"type":"string","enum":["outbound.delivered","outbound.bounced","outbound.rejected","outbound.deferred","outbound.spam","outbound.dropped","outbound.virus","outbound.opened","outbound.clicked","outbound.complaint","inbound.received","inbound.delivered","inbound.spam","inbound.blocked"]},"minItems":1,"description":"New list of event types. Must only include allowed event types.","example":["outbound.delivered","outbound.bounced","inbound.received"]},"status":{"type":"integer","enum":[0,1],"description":"New webhook status: 0 = disabled, 1 = enabled","example":1},"filter_users":{"type":"array","items":{"type":"string"},"nullable":true,"description":"New filter for outbound events by username. Must be transactional keys or smarthosts you own.","example":null},"filter_domains":{"type":"array","items":{"type":"string"},"nullable":true,"description":"New filter for inbound events by domain. Must be inbound domains you own.","example":["example.com"]}}},"examples":{"Update URL":{"value":{"uuid":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","url":"https://example.com/new-webhook"}},"Disable Webhook":{"value":{"uuid":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","status":0}},"Update Events and Filters":{"value":{"uuid":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","events":["outbound.bounced","outbound.complaint"],"filter_domains":["example.com"]}}}}}},"responses":{"200":{"description":"Webhook updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Webhook updated successfully"}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Webhook uuid is required and must be a string"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"403":{"description":"Forbidden - Invalid filter values (users/domains not owned by caller)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid filter_users: my_key. You can only filter by users/keys that you own."}}}}}},"404":{"description":"Not found - Webhook not found or access denied","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Webhook not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to update webhook"}}}}}}}}},"/webhooks/{uuid}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook","description":"Returns a single webhook configuration by UUID","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the webhook to retrieve"}],"responses":{"200":{"description":"Webhook retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"webhook":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"name":{"type":"string","description":"Human-readable webhook name","example":"Production Webhook"},"url":{"type":"string","example":"https://example.com/webhook"},"secret":{"type":"string","example":"whsec_abc123def456..."},"events":{"type":"array","items":{"type":"string","enum":["outbound.queued","outbound.delivered","outbound.bounced","outbound.rejected","outbound.deferred","outbound.spam","outbound.dropped","outbound.virus","outbound.opened","outbound.clicked","outbound.complaint","inbound.received","inbound.delivered","inbound.spam","inbound.blocked"]},"example":["outbound.delivered","outbound.bounced"]},"status":{"type":"string","example":"enabled"},"filter_users":{"type":"array","items":{"type":"string"},"nullable":true,"example":null},"filter_domains":{"type":"array","items":{"type":"string"},"nullable":true,"example":null},"created_at":{"type":"integer","example":1736524800},"last_modified":{"type":"integer","example":1736524800}}}}}}}},"400":{"description":"Bad request - Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid webhook UUID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not found - Webhook not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Webhook not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to fetch webhook"}}}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","description":"Deletes a webhook configuration","parameters":[{"name":"uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID of the webhook to delete"}],"responses":{"200":{"description":"Webhook deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Webhook deleted successfully"}}}}}},"400":{"description":"Bad request - Invalid UUID format","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid webhook UUID format"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User information not found"}}}}}},"404":{"description":"Not found - Webhook not found or access denied","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Webhook not found or access denied"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to delete webhook"}}}}}}}}},"/webhooks/query":{"post":{"tags":["Webhooks"],"summary":"Query webhook events","description":"Query webhook events with filtering. Returns webhook events that have been triggered for your account.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid","description":"Filter by webhook config UUID","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"event_id":{"type":"string","description":"Filter by specific event ID","example":"evt_xyz789"},"event_type":{"type":"string","enum":["outbound.queued","outbound.delivered","outbound.bounced","outbound.rejected","outbound.deferred","outbound.spam","outbound.dropped","outbound.virus","outbound.opened","outbound.clicked","outbound.complaint","inbound.received","inbound.delivered","inbound.spam","inbound.blocked"],"description":"Filter by event type","example":"outbound.delivered"},"source_uid":{"type":"string","description":"Filter by source message UID","example":"message-uid-123"},"status":{"type":"string","enum":["success","failed","retry","pending"],"description":"Filter by delivery status","example":"success"},"date_from":{"type":"integer","description":"Filter from Unix timestamp","example":1704825600},"date_to":{"type":"integer","description":"Filter to Unix timestamp","example":1704912000},"limit":{"type":"integer","minimum":1,"maximum":1000,"default":50,"description":"Maximum results to return","example":50},"offset":{"type":"integer","minimum":0,"default":0,"description":"Pagination offset","example":0}}},"examples":{"Query by webhook":{"value":{"uuid":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d","limit":50}},"Query by event type and date":{"value":{"event_type":"outbound.delivered","date_from":1704825600,"date_to":1704912000,"limit":100}},"Query failed deliveries":{"value":{"status":"failed","limit":50}}}}}},"responses":{"200":{"description":"Webhook events retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Event ID","example":"evt_xyz789"},"uuid":{"type":"string","format":"uuid","description":"Webhook config UUID","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"},"service":{"type":"string","enum":["outbound","inbound"],"description":"Service that triggered the event","example":"outbound"},"event_type":{"type":"string","description":"Event type","example":"outbound.delivered"},"source_uid":{"type":"string","description":"Source message UID","example":"message-uid-123"},"source_action":{"type":"string","description":"Original action or logtype","example":"ACCEPTED"},"payload":{"type":"object","description":"Event payload sent to webhook","example":{"to":"recipient@example.com","from":"sender@example.com"}},"webhook_url":{"type":"string","format":"uri","description":"Target webhook URL","example":"https://example.com/webhook"},"created_at":{"type":"integer","description":"Unix timestamp when event was created","example":1704825600},"latest_status":{"type":"string","enum":["success","failed","retry"],"description":"Latest delivery status","example":"success"},"total_attempts":{"type":"integer","description":"Total delivery attempts","example":1},"last_response_code":{"type":"integer","description":"HTTP response code from last attempt","example":200}}}},"total":{"type":"integer","description":"Total number of matching events","example":150},"limit":{"type":"integer","description":"Limit used for this query","example":50},"offset":{"type":"integer","description":"Offset used for this query","example":0}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Invalid event_type"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User authentication not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to query webhook events"}}}}}}}}},"/webhooks/replay":{"post":{"tags":["Webhooks"],"summary":"Replay a webhook event","description":"Replay a previously sent webhook event. The event will be re-queued for delivery to the configured webhook URL.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event_id":{"type":"string","description":"Event ID to replay","example":"evt_abc123"},"source_uid":{"type":"string","description":"Source message UID to replay events for","example":"message-uid-xyz"},"uuid":{"type":"string","format":"uuid","description":"Optional: Replay to a specific webhook config","example":"a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"}}},"examples":{"Replay by event ID":{"value":{"event_id":"evt_abc123"}},"Replay by source UID":{"value":{"source_uid":"message-uid-xyz"}}}}}},"responses":{"200":{"description":"Event re-queued for delivery","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"event_id":{"type":"string","description":"Event ID that was replayed","example":"evt_abc123"},"status":{"type":"string","enum":["enqueued"],"description":"Status of the replay request","example":"enqueued"},"message":{"type":"string","description":"Human-readable message","example":"Event re-queued for delivery"}}}}}},"400":{"description":"Bad request - Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Either event_id or source_uid is required"}}}}}},"401":{"description":"Unauthorized - User not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"User authentication not found"}}}}}},"404":{"description":"Event not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Event not found"}}}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Failed to replay webhook event"}}}}}}}}}}}