{"openapi":"3.1.0","info":{"title":"eimailar API","version":"1.0.0","description":"Transactional email and marketing campaigns for your workspace. Authenticated requests use a Bearer API key from Developer → API keys. Base URL: https://api.eimailar.com"},"servers":[{"url":"https://api.eimailar.com","description":"Production"}],"security":[{"ApiKey":[]}],"tags":[{"name":"Emails","description":"Send transactional email and read its delivery timeline."},{"name":"Domains","description":"Register sending domains, prove DNS ownership, and inspect activation state."},{"name":"Contacts","description":"Manage contacts, consent, and CSV imports."},{"name":"Connections","description":"Receive signups and signed lifecycle streams from forms, products, stores, Zapier, Make, and custom platforms."},{"name":"Lists","description":"Group contacts into lists."},{"name":"Segments","description":"Rule-based dynamic audiences."},{"name":"Campaigns","description":"One-off marketing sends to lists/segments."},{"name":"Automations","description":"Linear journeys triggered by contact events."},{"name":"Templates","description":"Reusable visual email templates."},{"name":"Webhooks","description":"Receive signed delivery/engagement events."}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","description":"Your API key, e.g. `Authorization: Bearer eim_live_…`"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}},"paths":{"/v1/conversion-goals":{"post":{"tags":["Campaigns"],"summary":"Create a conversion objective","description":"Requires campaigns scope. Sources must belong to the workspace. Attribution configuration is fixed after creation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","eventType"],"properties":{"name":{"type":"string","maxLength":100},"eventType":{"type":"string","maxLength":80},"windowDays":{"type":"integer","minimum":1,"maximum":90,"default":7},"basis":{"type":"string","enum":["click","delivered"]},"currency":{"type":"string","default":"USD"},"campaignIds":{"type":"array","maxItems":100,"items":{"type":"string"}},"automationIds":{"type":"array","maxItems":100,"items":{"type":"string"}},"allSources":{"type":"boolean","default":false,"description":"Count every marketing send, including ones created later."}}}}}},"responses":{"201":{"description":"Objective created"},"400":{"description":"Invalid objective or foreign sources"}}}},"/v1/conversion-goals/{id}":{"get":{"tags":["Campaigns"],"summary":"Read objective and conversion totals","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Objective and deduplicated event, person and value totals"},"404":{"description":"Not found in this workspace"}}}},"/v1/conversions":{"post":{"tags":["Contacts"],"summary":"Record a business conversion","description":"Requires contacts scope. Identify the person by contactId or email. Omit goalId to record against every objective with this event type. Exact duplicate externalEventId is idempotent; changed identity, time or value is refused. Times before objective creation, older than 90 days or more than five minutes ahead are refused. No sending authority is created.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["eventType","externalEventId","occurredAt"],"properties":{"goalId":{"type":"string"},"eventType":{"type":"string"},"contactId":{"type":"string"},"email":{"type":"string","format":"email"},"externalEventId":{"type":"string","maxLength":200},"occurredAt":{"type":"string","format":"date-time"},"valueMinor":{"type":"integer","minimum":0,"maximum":1000000000,"default":0}}}}}},"responses":{"200":{"description":"Exact duplicate"},"201":{"description":"Recorded"},"409":{"description":"Refused, with a reason: unknown_contact, no_objective, too_old, future, before_objective or changed_event"}}}},"/v1/emails":{"post":{"tags":["Emails"],"summary":"Send a transactional email","description":"Queues a transactional email. Production requests must attest the business trigger and recipient relationship in `transactional`. Marketing email must use the campaign API so audience consent, suppression, sender identity, and unsubscribe controls are enforced. The `from` domain must be a verified transactional sending domain. Pass an `Idempotency-Key` header to make retries safe: the same key and body replays the original message (200, `idempotent_replay: true`, also under concurrent retries); the same key with a different body is refused with 409 `idempotency_key_reused`. Keys do not expire. Set `expires_at` or `ttl_seconds` so mail that cannot be handed to the provider in time fails with reason `expired` instead of arriving late.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","to","subject","transactional"],"properties":{"from":{"type":"string","example":"Meetumo <hello@send.meetumo.ai>"},"to":{"type":"string","format":"email","example":"user@example.com"},"subject":{"type":"string","example":"Welcome to Meetumo"},"html":{"type":"string"},"text":{"type":"string"},"reply_to":{"oneOf":[{"type":"string","format":"email"},{"type":"array","maxItems":1,"items":{"type":"string","format":"email"}}],"description":"A single reply address, preserved through delivery."},"headers":{"type":"object","additionalProperties":{"type":"string","maxLength":998},"description":"Allow-listed custom headers, matched case-insensitively: List-Unsubscribe (comma-separated <https:…>/<mailto:…> URIs), List-Unsubscribe-Post (exactly `List-Unsubscribe=One-Click`, requires an https List-Unsubscribe), List-Id, X-Entity-Ref-ID, References, In-Reply-To. Any other header is refused with 400.","example":{"X-Entity-Ref-ID":"order_123","List-Unsubscribe":"<https://meetumo.ai/u/abc>"}},"attachments":{"type":"array","maxItems":10,"description":"Up to 25 MiB of decoded content in total. Stored with the message for durable delivery. Remote URLs are not accepted. Set `content_id` to send a part inline and reference it from the HTML as `cid:<content_id>`.","items":{"type":"object","additionalProperties":false,"required":["filename","content"],"properties":{"filename":{"type":"string","maxLength":255},"content":{"type":"string","contentEncoding":"base64"},"content_type":{"type":"string"},"content_id":{"type":"string","maxLength":128,"description":"Inline content id, unique within the message; surrounding angle brackets are removed."}}}},"expires_at":{"type":"string","format":"date-time","description":"Deadline for provider handoff, at most 7 days ahead. Queued mail still waiting at this time is marked failed with reason `expired`."},"ttl_seconds":{"type":"integer","minimum":60,"maximum":604800,"description":"Relative alternative to expires_at; provide one or the other."},"stream":{"type":"string","enum":["transactional"],"default":"transactional"},"tags":{"type":"array","items":{"type":"string"}},"transactional":{"type":"object","required":["category","trigger_id","recipient_relationship"],"additionalProperties":false,"properties":{"category":{"type":"string","enum":["account","authentication","billing","event","order","receipt","security","service"]},"trigger_id":{"type":"string","maxLength":128},"recipient_relationship":{"type":"string","enum":["account_holder","attendee","customer","employee","requested_recipient"]}}}}},"example":{"from":"Meetumo <hello@send.meetumo.ai>","to":"user@example.com","subject":"Welcome to Meetumo","html":"<p>Thanks for signing up.</p>","transactional":{"category":"account","trigger_id":"signup_01j...","recipient_relationship":"account_holder"}}}}},"responses":{"201":{"description":"Accepted and queued","content":{"application/json":{"example":{"id":"msg_01j…","status":"queued"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key"},"403":{"description":"Workspace sending is not approved, or the from domain is not an approved transactional sending domain"},"409":{"description":"The Idempotency-Key was already used with a different body (`idempotency_key_reused`)"},"422":{"description":"Marketing content must use the campaign API"},"503":{"description":"Delivery is paused; delivery_paused confirms this request queued nothing. Existing idempotency receipts still replay."}}}},"/v1/emails/batch":{"post":{"tags":["Emails"],"summary":"Send up to 100 transactional emails","description":"Resend-compatible batch. The body is a JSON array of 1-100 objects, each exactly the `POST /v1/emails` body and validated by the same rules. Validation is all-or-nothing: an invalid item rejects the whole batch with its `index` and nothing is queued. With an `Idempotency-Key` header (max 250 characters) item i uses the key `<key>:<i>`, so retrying the whole batch replays every item; a retried batch whose item i changed is refused with 409 and that `index`.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object"}}}}},"responses":{"200":{"description":"Every item was an idempotent replay; each carries `idempotent_replay: true`"},"201":{"description":"At least one email newly queued","content":{"application/json":{"example":{"data":[{"id":"msg_01j…","status":"queued"},{"id":"msg_01k…","status":"queued"}]}}}},"400":{"description":"Validation error; `error.index` names the first invalid item"},"403":{"description":"Workspace or from-domain gate refused an item"},"409":{"description":"An item's derived Idempotency-Key was used with a different body"},"422":{"description":"An item is marketing content or lacks the transactional attestation"},"503":{"description":"delivery_paused confirms no acceptance; delivery_paused_after_partial_acceptance requires message review and must not be bisected or retried with a new key."}}}},"/v1/emails/health":{"get":{"tags":["Emails"],"summary":"Check transactional sending readiness","description":"Read-only, send-scoped check of workspace approval and an active verified transactional identity. Does not send an email or expose message content. Returns 503 when sending is unavailable.","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Ready","content":{"application/json":{"schema":{"type":"object","properties":{"ready":{"type":"boolean"}}}}}},"401":{"description":"Authentication required"},"403":{"description":"Send access required"},"503":{"description":"Sending is not ready"}}}},"/v1/emails/{id}":{"get":{"tags":["Emails"],"summary":"Get an email and its event timeline","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Message with events","content":{"application/json":{"example":{"id":"msg_01j…","to":"user@example.com","status":"delivered","events":[{"type":"queued","at":"2026-07-18T07:48:16Z"},{"type":"sent","at":"2026-07-18T07:48:16Z"},{"type":"delivered","at":"2026-07-18T07:48:19Z"}]}}}},"404":{"description":"Not found"}}}},"/v1/domains":{"get":{"tags":["Domains"],"summary":"List sending domains","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Domains"],"summary":"Add a sending domain","description":"Returns the DNS records (DKIM, SPF, DMARC, MAIL FROM) to publish. eimailar re-checks them automatically. Follow the dashboard setup guide to complete domain activation.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"domain":"send.meetumo.ai","stream":"transactional"}}}},"responses":{"201":{"description":"Created with DNS records to publish"}}}},"/v1/domains/{id}/verify":{"post":{"tags":["Domains"],"summary":"Re-check DNS now","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated verification state"}}}},"/v1/contacts":{"get":{"tags":["Contacts"],"summary":"List contacts","security":[{"ApiKey":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["active","pending","unsubscribed","bounced","complained","suppressed"]}},{"name":"list_id","in":"query","schema":{"type":"string"}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Search by email"}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Contacts"],"summary":"Create a contact","description":"Every contact carries a consent basis. `double_opt_in` creates a pending contact and sends a confirmation email. Direct single opt-in and customer soft opt-in require a bounded attestation, source, and capture time before marketing eligibility is recorded.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"email":"user@example.com","attributes":{"name":"Ada","company":"Acme"},"list_ids":["lst_01j…"],"consent":{"method":"single_opt_in","evidence":{"attested":true,"source":"Product signup form","captured_at":"2026-08-06T12:00:00Z","policy_version":"2026-08"}}}}}},"responses":{"201":{"description":"Created"},"409":{"description":"Already exists or suppressed"}}}},"/v1/contacts/import":{"post":{"tags":["Contacts"],"summary":"Bulk import contacts","description":"Requires explicit consent attestation. Reuses existing active contacts without changing attributes, records consent and joins the selected list. Inactive contacts remain unchanged. Skips suppressed, invalid and repeated addresses. Returns counts and a durable import report ID in the X-Eimailar-Import-Id header.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"contacts":[{"email":"a@example.com","attributes":{"name":"A"}}],"list_id":"lst_01j…","consent":{"attested":true,"evidence":{"source":"Event registration export","captured_at":"2026-08-06T12:00:00Z","policy_version":"2026-08"}}}}}},"responses":{"200":{"description":"Import counts","headers":{"X-Eimailar-Import-Id":{"description":"Workspace-scoped report ID, available under People > Imports","schema":{"type":"string"}}},"content":{"application/json":{"example":{"created":2,"existing":0,"suppressed":1,"invalid":0,"duplicates":1}}}}}}},"/v1/contacts/upsert":{"post":{"tags":["Contacts"],"summary":"Create or update a contact","description":"Retry-safe contact ingestion by normalized email. Merges attributes and list memberships, but never reactivates unsubscribed, bounced, complained, or suppressed contacts.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"email":"user@example.com","attributes":{"name":"Ada","plan":"pro"},"source":"product-signup","list_ids":["lst_01j…"],"consent":{"method":"single_opt_in","evidence":{"attested":true,"source":"Product signup form","captured_at":"2026-08-06T12:00:00Z","policy_version":"2026-08"}}}}}},"responses":{"200":{"description":"Existing contact updated or unchanged"},"201":{"description":"Contact created"},"409":{"description":"Suppressed or non-mailable contact"}}}},"/v1/connections":{"get":{"tags":["Connections"],"summary":"List inbound signup connections","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Connections"],"summary":"Create an inbound signup connection","description":"Returns a connection-scoped secret exactly once. It cannot send email or access any other API resource.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Website signups","source":"website-signup","list_id":"lst_01j…","consent":{"method":"double_opt_in","scope":"marketing"},"mapping":{"email":"data.customer.email","event_id":"event.id","attributes":{"first_name":"data.customer.first_name","plan":"data.plan"}}}}}},"responses":{"201":{"description":"Connection created; save the returned secret"}}}},"/v1/connections/{id}":{"get":{"tags":["Connections"],"summary":"Get a connection and recent processing events","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}},"patch":{"tags":["Connections"],"summary":"Update or pause a connection","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Connections"],"summary":"Delete a connection","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"}}}},"/v1/connections/lifecycle":{"get":{"tags":["Connections"],"summary":"List lifecycle source connections","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Source-neutral lifecycle connections"}}},"post":{"tags":["Connections"],"summary":"Create a lifecycle source connection","description":"Returns a source-scoped HMAC signing secret exactly once. Identity is scoped by tenant, source, and external user ID.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Partner product","source":"partner_product","feedback_url":"https://partner.example/hooks/eimailar"}}}},"responses":{"201":{"description":"Connection created; save the returned signing secret"},"409":{"description":"Source key already connected"}}}},"/hooks/lifecycle/v1/{connectionId}":{"post":{"tags":["Connections"],"summary":"Receive a signed lifecycle event","description":"Source-neutral HMAC receiver. Sign `<unix-seconds>.<raw-body>` and keep event IDs stable for safe retries.","security":[],"parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Eimailar-Signature","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Eimailar-Key-Id","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"example":{"version":"1.0","event_id":"evt_01","event_type":"user.registered","occurred_at":"2026-08-01T12:00:00.000Z","source":"partner_product","external_user_id":"user_123","subject":{"type":"user"},"roles":["registered_user"],"data":{"email":"person@example.com"},"trace_id":"trace_01","suppress_automation":false,"allow_send":true}}}},"responses":{"200":{"description":"Accepted, projected, or duplicate delivery"},"401":{"description":"Invalid signature"},"409":{"description":"Identity or idempotency conflict"}}}},"/hooks/contacts/{id}":{"post":{"tags":["Connections"],"summary":"Receive an external signup","description":"Public ingestion endpoint for one connection. Send its one-time secret as `X-Eimailar-Secret` (or a Bearer token). `X-Eimailar-Event-Id` can override the mapped event ID for replay protection.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Eimailar-Secret","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Eimailar-Event-Id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"example":{"event":{"id":"signup_123"},"data":{"customer":{"email":"user@example.com","first_name":"Ada"}}}}}},"responses":{"200":{"description":"Updated, unchanged, replayed, or safely rejected"},"201":{"description":"Contact created"},"401":{"description":"Invalid connection secret"}}}},"/v1/lists":{"get":{"tags":["Lists"],"summary":"List lists","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Lists"],"summary":"Create a list","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Newsletter","double_opt_in":true}}}},"responses":{"201":{"description":"Created"}}}},"/v1/lists/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"patch":{"tags":["Lists"],"summary":"Edit list metadata","description":"Preserves contacts, membership, double opt-in and campaign references. Requires name; an omitted description is preserved and null clears it. Conflicting list names return 409.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","nullable":true,"maxLength":500}}},"example":{"name":"Product updates","description":"Subscribers to product news"}}}},"responses":{"200":{"description":"Updated list including member count"},"400":{"description":"Invalid metadata"},"404":{"description":"List not found in this workspace"},"409":{"description":"Another list uses the name"}}},"delete":{"tags":["Lists"],"summary":"Delete an unused list","description":"Preserves contacts. Refuses deletion while a campaign, segment rule or automation trigger/action references the list, with workspace-scoped dependencies in the response.","security":[{"ApiKey":[]}],"responses":{"204":{"description":"Deleted"},"404":{"description":"List not found in this workspace"},"409":{"description":"List in use","content":{"application/json":{"example":{"error":{"code":"list_in_use","message":"Remove this list from its campaigns, segments and automations before deleting it."},"dependencies":[{"kind":"segment","id":"seg_01j…","name":"Engaged subscribers"}]}}}}}}},"/v1/segments":{"get":{"tags":["Segments"],"summary":"List segments","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Segments"],"summary":"Create a segment","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Engaged pros","rules":{"match":"all","conditions":[{"kind":"attribute","field":"plan","op":"eq","value":"pro"},{"kind":"activity","op":"opened","days":30}]}}}}},"responses":{"201":{"description":"Created"}}}},"/v1/segments/preview":{"post":{"tags":["Segments"],"summary":"Preview a rule set","description":"Returns the matching count and a sample without saving.","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"count":128,"sample":[{"email":"a@x.com","status":"active"}]}}}}}}},"/v1/campaigns":{"get":{"tags":["Campaigns"],"summary":"List campaigns","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Campaigns"],"summary":"Create a campaign (draft)","description":"Audience is one or more lists and/or a segment. Content is inline html/text.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"July update","subject":"Hi {{name}} — what's new","from":"Meetumo <news@mail.meetumo.ai>","audience":{"list_ids":["lst_01j…"],"segment_id":"seg_01j…"},"html":"<p>Big news, {{name}}!</p>"}}}},"responses":{"201":{"description":"Draft created"}}}},"/v1/campaigns/{id}/send":{"post":{"tags":["Campaigns"],"summary":"Send now","description":"Materializes the audience and starts the resumable send.","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sending"}}}},"/v1/campaigns/{id}/schedule":{"post":{"tags":["Campaigns"],"summary":"Schedule a send","description":"Preflight-validates the campaign and schedules it for a future instant. Re-scheduling an already-scheduled campaign replaces the time.","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"example":{"send_at":"2026-09-01T14:00:00Z"}}}},"responses":{"200":{"description":"Scheduled"},"400":{"description":"send_at invalid or in the past"},"422":{"description":"Preflight failed"}}}},"/v1/campaigns/{id}/unschedule":{"post":{"tags":["Campaigns"],"summary":"Cancel a scheduled send","description":"Returns the campaign to draft and drops the pending start. 409 unless the campaign is scheduled.","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Back to draft"},"409":{"description":"Not scheduled"}}}},"/v1/campaigns/{id}/pause":{"post":{"tags":["Campaigns"],"summary":"Pause a sending campaign","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Paused"}}}},"/v1/automations":{"get":{"tags":["Automations"],"summary":"List automations","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Automations"],"summary":"Create an automation (draft)","description":"A trigger plus linear steps (wait / send). Activate it to enroll matching contacts.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Welcome series","trigger":{"kind":"list_joined","listId":"lst_01j…"},"steps":[{"kind":"send","from":"hello@mail.meetumo.ai","subject":"Welcome {{name}}","html":"<p>Hi {{name}}</p>"},{"kind":"wait","minutes":1440},{"kind":"send","from":"hello@mail.meetumo.ai","subject":"Getting started","html":"<p>…</p>"}]}}}},"responses":{"201":{"description":"Draft created"}}}},"/v1/automations/{id}/activate":{"post":{"tags":["Automations"],"summary":"Activate","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Active"}}}},"/v1/media/upload-intents":{"post":{"summary":"Create a media upload intent","description":"Registers an image (JPEG/PNG/WebP/GIF, ≤10 MB; SVG unsupported) and returns a short-lived presigned PUT. Upload the raw bytes to `upload.url`, then call complete. The API never accepts binary bodies directly.","tags":["Media"],"responses":{"201":{"description":"Asset registered; upload target returned"}}}},"/v1/media/{id}/complete":{"post":{"summary":"Finalize an upload","description":"Verifies the uploaded object server-side (magic bytes, dimensions, size) and marks the asset ready. Failed verification archives the object and returns 422.","tags":["Media"],"responses":{"200":{"description":"Asset ready"},"422":{"description":"Verification failed"}}}},"/v1/media":{"get":{"summary":"List media assets","tags":["Media"],"responses":{"200":{"description":"Ready assets, newest first; `q` searches filename and alt text"}}}},"/v1/templates":{"get":{"tags":["Templates"],"summary":"List templates","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Templates"],"summary":"Create a template","description":"Provide a block `design`; eimailar renders it to html and text.","security":[{"ApiKey":[]}],"responses":{"201":{"description":"Created"}}}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","security":[{"ApiKey":[]}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["Webhooks"],"summary":"Register a webhook endpoint","description":"Returns a signing secret once. Each delivery is signed with `eimailar-signature: t=<unix>,v1=<hmac-sha256>` over `<t>.<body>`. The body is `{ id, type, created_at, data }`; `id` is a stable event id, identical on every retry and endpoint, also sent as the `eimailar-event-id` header (with `eimailar-event-type`) so receivers can deduplicate. Event types: `email.delivered`, `email.bounced`, `email.complained`, `email.opened`, `email.clicked`, and for transactional API mail `email.failed` (provider rejection, final soft bounce, expiry, domain or workspace gate; `data.reason`), `email.suppressed` (send-time suppression; `data.reason`) and `email.delivery_delayed` (SES DeliveryDelay; `data.delay`). Use `*` for all.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"example":{"url":"https://api.yourservice.com/eimailar-hook","event_types":["email.bounced","email.complained"]}}}},"responses":{"201":{"description":"Created; secret returned once"}}}}}}