Transactional Email
Use the transactional endpoint for messages caused by a specific application action, such as a verification code, password reset, receipt or security notification.
Endpoint
Section titled “Endpoint”POST https://app.forgecloud.cc/api/v1/email/sendAuthorization: Bearer ef_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxContent-Type: application/jsonIdempotency-Key: 550e8400-e29b-41d4-a716-446655440000Idempotency-Key is required. Generate one UUID for each logical email and reuse it only when retrying that same request. Reusing a key with different request data is rejected.
Request
Section titled “Request”{ "from": "noreply@example.com", "to": ["user@example.net"], "subject": "Your verification code", "text_body": "Your verification code is 482193.", "html_body": "<p>Your verification code is <strong>482193</strong>.</p>", "purpose": "transactional"}| Field | Required | Description |
|---|---|---|
from |
Sometimes | Required for a project key when the project has multiple verified senders. It must match a verified sender in that project. |
to |
Yes | Recipient addresses. The current per-request maximum is 50. |
subject |
Yes | Subject line, up to 300 characters. |
text_body |
Yes | Plain-text body. |
html_body |
No | Optional HTML alternative. |
purpose |
No | When present, must be transactional. |
A sender-scoped key always uses its selected identity. If from is present, it must match that identity.
Successful Submission
Section titled “Successful Submission”A request can contain more than one recipient, so the response reports each delivery separately:
{ "status": "queued", "traffic_class": "tenant_transactional", "accepted": 1, "sent": 1, "failed": 0, "deliveries": [ { "id": "send_a1b2c3d4e5f6", "to": "user@example.net", "status": "queued", "smtp_message_id": "<forge-send_a1b2c3d4e5f6@example.com>", "error": null, "duration_ms": 342 } ]}The top-level status can be queued, partial, suppressed or failed. A 201 response means at least one delivery was accepted for submission. It does not prove inbox placement.
Example
Section titled “Example”const response = await fetch("https://app.forgecloud.cc/api/v1/email/send", { method: "POST", headers: { Authorization: `Bearer ${process.env.PROJECT_EMAIL_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), }, body: JSON.stringify({ from: "noreply@example.com", to: ["user@example.net"], subject: "Welcome", text_body: "Thanks for signing up.", html_body: "<p>Thanks for signing up.</p>", purpose: "transactional", }),});
const result = await response.json();if (!response.ok) throw new Error(result.error ?? "Email request failed");Use your own service variable name rather than committing the API key. The example variable name is not required by Forge.
Errors And Retries
Section titled “Errors And Retries”400: malformed or unsupported request data.401: invalid, revoked or insufficient API key.409: recipient/provider suppression, unverified identity or conflicting idempotency use.429: request or quota limit. RespectRetry-Afterwhen present.502: no recipient could be submitted to the configured delivery route.
Retry network errors and retryable server responses with the same idempotency key. Do not generate a new key for the same logical email because that can create a duplicate delivery.
Delivery History
Section titled “Delivery History”Open Email → Send History to review each recipient. queued is submission acceptance; later delivery evidence may advance the record to delivered, deferred or bounced. A recipient can also be suppressed after a permanent failure, complaint or active provider incident.
For higher-volume or marketing email, use a provider and workflow designed for consent, unsubscribe processing, complaint handling and separate reputation. Forge’s current public API is transactional-only.