Integration endpoints
| Method & path | Body | Notes | |||
|---|---|---|---|---|---|
GET /api-keys | — | name, prefix, scopes, expiry, last used — never the key | |||
POST /api-keys | name, scopes[] (permission keys or "*"), expires_at? | Returns the key once (zk_…) | |||
DELETE /api-keys/:id | — | Revokes immediately | |||
GET /webhooks · POST /webhooks | url (https), description?, events[] | Returns the signing secret once | |||
PATCH /webhooks/:id | url?, 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: item | work_order | stock_movement, kind: photo | signature` | Read permission of the parent record |
POST /attachments | multipart 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) |
Workspace e-mail sender, outbound e-mails, document links
| Method & path | Body / query | Permission |
|---|---|---|
GET /tenant/mail-sender | the sender (never its credentials), which providers this server offers, the fallback setting | signed in |
POST /tenant/mail-sender/detect | { email } → provider: google \| microsoft \| zoho \| smtp, smtp { host, port, secure, note }, available | settings.manage |
GET /mail/oauth/start/:provider | 302 to the consent page (state + PKCE, send scopes only); open in a popup | settings.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 it | settings.manage |
POST /tenant/mail-sender/smtp/verify | { code } (3 tries, 10 min) | settings.manage |
POST /tenant/mail-sender/test | sends 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-sender | disconnects (revokes the token where supported) | settings.manage |
GET /mail/outbound?status=&category=&entity_type=&entity_id= · GET /:id | the log (owners: everything; others: their own sends, or by record) | signed in |
GET /mail/outbound/:id/manual | the rendered e-mail, draft links (Gmail / Outlook / mailto), the document link | signed in |
GET /mail/outbound/:id/attachment | the PDF | signed 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/pdf | the branded PO PDF | purchasing.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/emails | the order's e-mail history | purchasing.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