Zudo Works

Integration endpoints

Method & pathBodyNotes
GET /api-keys—name, prefix, scopes, expiry, last used — never the key
POST /api-keysname, scopes[] (permission keys or "*"), expires_at?Returns the key once (zk_…)
DELETE /api-keys/:id—Revokes immediately
GET /webhooks · POST /webhooksurl (https), description?, events[]Returns the signing secret once
PATCH /webhooks/:idurl?, description?, events?, active?Pause with active: false
DELETE /webhooks/:id · POST /webhooks/:id/test—Test sends a ping
GET /attachments?entity_type=&entity_id=&kind=`entity_type: itemwork_orderstock_movement, kind: photosignature`Read permission of the parent record
POST /attachmentsmultipart file + entity_type, entity_id, kind?, signer_name? (≤ 8 MB)Write permission of the parent; counts against storage
DELETE /attachments/:id—
GET /uploads/:kind/:tenant/:file [public]—Local-storage file serving (R2 serves directly in production)
Method & pathBody / queryPermission
GET /tenant/mail-senderthe sender (never its credentials), which providers this server offers, the fallback settingsigned in
POST /tenant/mail-sender/detect{ email } → provider: google \| microsoft \| zoho \| smtp, smtp { host, port, secure, note }, availablesettings.manage
GET /mail/oauth/start/:provider302 to the consent page (state + PKCE, send scopes only); open in a popupsettings.manage
GET /mail/oauth/callback/:provider [public]the provider's redirect; the single-use state names tenant and user; HTML page + bridge.js posts { type: 'zudo-mail-connected', ok, email, error } to the web origins—
POST /tenant/mail-sender/smtp{ email, host, port, secure, username, password } → tests the login, sends a six-digit code through itsettings.manage
POST /tenant/mail-sender/smtp/verify{ code } (3 tries, 10 min)settings.manage
POST /tenant/mail-sender/testsends a test to the mailbox itself (5 / 10 min)settings.manage
PUT /tenant/mail-sender/fallback{ mail_fallback: ask \| zudo \| never }settings.manage
DELETE /tenant/mail-senderdisconnects (revokes the token where supported)settings.manage
GET /mail/outbound?status=&category=&entity_type=&entity_id= · GET /:idthe log (owners: everything; others: their own sends, or by record)signed in
GET /mail/outbound/:id/manualthe rendered e-mail, draft links (Gmail / Outlook / mailto), the document linksigned in
GET /mail/outbound/:id/attachmentthe PDFsigned in
POST /mail/outbound/:id/decision{ choice: zudo \| manual \| reconnect_retry }signed in (reconnect: settings.manage)
POST /mail/outbound/:id/retry · POST /:id/sent-manually—signed in
GET /d/:token [public]the document PDF behind a secure link (inline, noindex, 60 views / min per address; 404 when expired / revoked)—
POST /mail/webhooks/resend [public]Resend delivery events (email.delivered, email.bounced, email.complained), Svix-signed—
GET /purchase-orders/:id/pdfthe branded PO PDFpurchasing.read
POST /purchase-orders/:id/email/preview{ to?, cc?, subject?, message? } → { to, cc, subject, html, text, attachment_name, vendor_email }purchasing.write
POST /purchase-orders/:id/email{ to[] (≤ 20), cc[]?, subject, message? } → the outbound row (status sent / queued / awaiting_decision)purchasing.write
GET /purchase-orders/:id/emailsthe order's e-mail historypurchasing.read

Which e-mails use which sender. Through the company mailbox (or, by decision / setting, "{Org} via Zudo Works"): purchase orders, workflow Send e-mail steps, and the coming quotes, sales orders, invoices, job cards and statements — anything addressed to vendors or customers. Always from Zudo Works, never the company mailbox: signup codes, password resets, welcome e-mails, security alerts, plan usage warnings, feedback to the admin, and anything before a tenant exists.

Outbound statuses: queued → sending → sent (or bounced / failed later); a final failure → awaiting_decision → sent (via Zudo Works or after a retry) or sent_manually. Retries after a temporary failure: 1 min, 5 min, 30 min, then the decision.

Last updated