About this guide
How Campaign Composer relates to APIs and delivery.
Campaign Composer (the email editor in each project) is where you author and save HTML templates. Sending can happen in three complementary ways: (1) operators use the Send email flow in the UI with recipients and folders; (2) marketers schedule scheduled emails against a template and audience folders; (3) developers call HTTP APIs (or the documented SDK pattern) to send transactional or bulk mail using the same project, SMTP, and template IDs.
This document mirrors the structure of the personalization technical guide: concise reference for fields, endpoints, and guardrails—not a substitute for your deployed app’s exact base URL or admin policies.
Base URL
Replace https://YOUR_APP_HOST with your production or staging origin (for example where the Next.js app is served). Paths below are rooted at that host.
Prerequisites
What must exist before a send succeeds.
- A PRZIO project. You need the project ID (MongoDB
_id) shown in the workspace and API flows. Template lookups are always scoped to that project when using API-key style auth. - SMTP configuration. Add at least one SMTP profile under project email settings (user SMTP), or rely on a platform admin SMTP if your deployment provides one. The send pipeline needs host, port, credentials, and a from address.
- Authentication. Server scripts can send
Authorization: Bearer <JWT>after a normal login. The browser Email SDK instead posts your project API key toPOST /api/auth/api-key; on success the app sets an HTTP-onlyprzio_api_tokencookie so follow-upfetchcalls to/api/emails/send-bulk(withcredentials: 'include') are authorized.
Note: Never expose long-lived JWTs or API keys in public front-end bundles without a backend proxy. Prefer server-side calls for bulk sends.
SMTP & project defaults
How the API picks a mail transport.
Each send resolves an SMTP configuration in this order: an explicit smtpId on the request; else the project’s default SMTP if set; else an active admin default SMTP on the deployment. User-owned SMTP records are referenced by their document id; admin SMTP ids are sent as strings prefixed with admin_ plus the admin SMTP document id.
You can test connectivity from the app using the Send test email action on an SMTP profile (POST /api/user/smtp/test when logged in). Fix TLS/port and app-password issues before relying on the same profile from send-bulk.
Project API keys
Create and list keys scoped to one project.
Owners and Project admins can mint keys. Keys are opaque strings prefixed with przio_ (implementation detail—treat as secret).
| Method & path | Purpose |
|---|---|
GET /api/projects/{projectId}/api-keys |
List keys (metadata; the full secret is not shown again after creation). |
POST /api/projects/{projectId}/api-keys |
Body: {"name": "Production website"}. Response includes the key once—copy it immediately. |
DELETE /api/projects/{projectId}/api-keys?keyId=... |
Revoke a key by id. |
All of the above require an authenticated session (same JWT cookie/header model as the rest of the dashboard API).
REST: POST /api/emails/send-bulk
Bulk or single-shot sends with HTML or a saved template.
The route accepts JSON and returns per-request results after attempting delivery in batches. It records email history rows when a projectId is present so operators can audit sends from the email dashboard.
Headers
Content-Type: application/json- Cookie session — after
POST /api/auth/api-key(Email SDKconnect()), theprzio_api_tokencookie is sent automatically whencredentials: 'include'. - Or
Authorization: Bearer <JWT>— dashboard user token for server-side calls you control.
JSON body
| Field | Required | Notes |
|---|---|---|
subject |
Yes | Email subject line. |
recipients |
Yes | Non-empty array of recipient email strings. |
html or templateId |
One required | Provide raw HTML, or a template id (Mongo _id or customTemplateId) to load HTML from Campaign Composer. Project default template is used if templateId is omitted and a default is configured. |
projectId |
Recommended | Scopes template lookup and history. Must match the token’s project when using API-key style embeds. |
smtpId |
No | Overrides default SMTP for this send. |
sendSource |
No | "test" or "manual" (default). Affects how history labels the send. |
Rate limiting
Requests are rate-limited (currently 15 requests per minute per client key prefix). Expect 429 with retry guidance when exceeded.
Example (curl)
curl -X POST "https://YOUR_APP_HOST/api/emails/send-bulk" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT" \
-d '{
"projectId": "YOUR_PROJECT_ID",
"subject": "Order shipped",
"templateId": "YOUR_TEMPLATE_ID_OR_CUSTOM_ID",
"recipients": ["buyer@example.com"],
"sendSource": "manual"
}'
Templates vs raw HTML
How templateId resolves.
When templateId is a valid MongoDB id, the service loads the template belonging to the authenticated user (or project, for API-key flows) and uses its stored HTML if you did not pass html. If the value is not an ObjectId, the same field is interpreted as a custom template id string you set in the editor.
Merge tags such as {{bannerImageUrl}} / {{baseUrl}} may be rewritten server-side before SMTP submission so older templates keep working.
Single source of truth
Design once in Campaign Composer; send many times from automation, schedules, or API with the same id.
Ad hoc content
Pass html for one-off transactional bodies generated by your app, still using project SMTP and history when projectId is set.
PRZIO Email SDK (PrzioSDK.Email)
Trigger sends from the browser using the bundled script—wraps connect + send-bulk + templates/history APIs.
The unified bundle sdk.js exposes the email client as new PrzioSDK.Email({ apiKey, projectId, baseUrl }) (see file header comments in public/sdk.js). You must call connect() once before sending; it exchanges the API key for a session cookie used on subsequent requests.
1. Load the script
<script src="https://YOUR_APP_HOST/sdk.js"></script>
Use your real app origin (same host you pass as baseUrl below) so cookies and CORS line up.
2. Construct the client
| Option | Required | Description |
|---|---|---|
apiKey |
Yes | Project API key (przio_…) from the dashboard. |
projectId |
Yes | Project MongoDB id; must match the key’s project. |
baseUrl |
No | Defaults to window.location.origin. Set explicitly when the page is not served from PRZIO (e.g. https://app.przio.com). |
const przio = new PrzioSDK.Email({
apiKey: 'YOUR_API_KEY',
projectId: 'YOUR_PROJECT_ID',
baseUrl: 'https://YOUR_APP_HOST' // optional if same origin
});
3. connect()
Resolves when POST /api/auth/api-key succeeds. The server validates apiKey + projectId, issues a JWT, and sets the przio_api_token cookie (httpOnly, ~30 days). All SDK fetch calls use credentials: 'include' so that cookie is attached.
await przio.connect(); // przio.isConnected() === true
4. sendEmail(options) — trigger a send
Maps to POST /api/emails/send-bulk with projectId set from the client instance. Throws if not connected.
| Property | Required | Notes |
|---|---|---|
recipients | Yes | Non-empty array of email strings. |
subject | Yes | Subject line. |
html | One of html / templateId / default | Raw HTML body. |
templateId | 〃 | Mongo id or customTemplateId from Campaign Composer. |
smtpId | No | Override SMTP; otherwise project default / admin default applies server-side. |
The SDK requires at least one of html or templateId unless the project has a default template configured (same rule as the REST API).
await przio.sendEmail({
recipients: ['user@example.com'],
subject: 'Order confirmation',
templateId: 'YOUR_TEMPLATE_ID'
});
await przio.sendEmail({
recipients: ['a@example.com', 'b@example.com'],
subject: 'Alert',
html: '<html><body><p>Hello</p></body></html>',
smtpId: 'YOUR_SMTP_DOCUMENT_ID' // optional
});
5. getTemplates()
GET /api/templates?projectId=… — returns templates for the project (requires connect() first).
const res = await przio.getTemplates(); console.log(res);
6. getEmailHistory(options)
GET /api/projects/{projectId}/emails with query parameters page, limit, and optional status (e.g. sent, failed, pending). The SDK passes options: defaults page 1, limit 50.
const history = await przio.getEmailHistory({
page: 1,
limit: 50,
status: 'sent'
});
7. isConnected() / disconnect()
isConnected() returns the local flag set after a successful connect(). disconnect() clears local state; the session cookie may remain until it expires.
Same-origin, HTTPS, and third-party sites
Because authentication relies on a cookie, the page that runs PrzioSDK.Email should load sdk.js from the same PRZIO host you pass as baseUrl, and you should send email from that origin (or a subdomain configured with appropriate cookie SameSite / Secure rules). Embedding the key on arbitrary third-party domains is fragile; prefer a backend proxy that holds the key and calls send-bulk with a server-side JWT for production.
Summary: connect() → cookie session → sendEmail / getTemplates / getEmailHistory. That is how you trigger emails from the PRZIO SDK in the browser.
In-app integration tutorial
Screenshots and checklist inside the product.
Open /integration/email after sign-in for the full walkthrough (SMTP, API keys, copy-paste examples). This static page is the API reference; the in-app guide is the onboarding UI.
Tip: Keep baseUrl aligned with where sdk.js is hosted so connect() and subsequent API paths resolve correctly.
Schedules, audiences, and form auto-send
Configured in the UI—not the send-bulk JSON.
Scheduled emails let you pick a template, subject, SMTP, recipient folders (audience segments), and a future scheduledAt. A processor loads pending rows whose time has passed and sends through the same nodemailer pipeline as manual sends.
Auto-send email rules attach to a form: on submit, enabled rules enqueue a template to the visitor, fixed recipients, and/or addresses collected from selected folders—useful for instant confirmations without custom backend code.
The Campaign Composer Send email toolbar flow merges individually selected recipients plus everyone in chosen folders for an immediate send, with progress UI in the editor.
Operational note: Timed sends are processed when something calls POST /api/projects/{projectId}/scheduled-emails/process (pending rows with scheduledAt in the past). Wire your cron or worker to hit that endpoint on a short interval if you rely on schedules; see your deployment README for auth headers and allowed callers.
Common errors & HTTP codes
Quick triage for integrations.
| Code | Typical cause |
|---|---|
400 | Missing subject or recipients; neither html nor resolvable templateId; invalid SMTP selection. |
401 | No or invalid JWT / session. |
403 | Project id on the request does not match the API key’s project (when applicable). |
404 | Template or SMTP document not found for the user/project. |
429 | Rate limit exceeded—back off and retry. |
500 | Server or SMTP failure—inspect logs and SMTP credentials. |