START HERE
Your first integration
- Import the collection into Postman. Open its Variables tab and set
baseUrlto this service’s HTTPS address. - As admin, set
adminApiKeyand use Create a tenant. The response savestenantIdandtenantApiKeylocally. - Hand the tenant key to its owner securely. For tenant use, keep only the tenant key; never hand out a collection containing the admin key.
- Edit the collection SMTP variables and use Update your SMTP. Saving does not send.
- Preview a report, then explicitly execute a send request when ready.
Admin manages tenants and keys. Tenant configures SMTP and sends/previews reports. Public links opens documentation and health. Never share/export a collection containing real keys or passwords.
One header. Two privilege levels.
Every protected request uses the ApiKey header. Admin credentials work only on admin routes; tenant credentials work only on tenant, send and preview routes.
ApiKey: <admin-key> # Admin methods only
ApiKey: <tenant-key> # Tenant, send and preview methods onlyTenant keys contain at least 256 bits of random secret material. Only hashes are stored. The full key appears only in creation/regeneration responses; regenerating it immediately revokes the previous value. Disabling/deleting a tenant also blocks its key.
Tenant SMTP credentials are encrypted in PostgreSQL. Read operations return credential-presence information, never saved username/password. Use HTTPS and your automation’s secret store.
Errors, limits and delivery
| Status | Meaning | Action / detail |
|---|---|---|
| 400 | Bad request | Invalid input, destination or deletion confirmation. |
| 401 | Unauthorized | Missing, invalid, disabled or revoked key. |
| 403 | Forbidden | Valid key with the wrong privilege. |
| 404 | Not found | Admin target does not exist. |
| 409 | Setup required | Missing SMTP or undecryptable credentials. |
| 413 | Payload too large | Request body exceeds 1 MiB. |
| 429 | Too many requests | 120 requests/minute per tenant; admin has a separate quota. |
| 502 | SMTP failure | Delivery may be uncertain. |
| 504 | Timeout | SMTP exceeded a configured deadline; the response identifies the stage and log reference. |
| 503 | Unavailable | Service/database configuration requires operator attention. |
{
"error": "A valid ApiKey header is required."
}Messages allow 1–50 recipients. Structured reports allow 1–100 prospects. The service conceals recipient addresses from one another. Sender, recipients, subject, timestamps and final rendered HTML/plain-text bodies are retained in the tenant’s EmailLogs records. SMTP acceptance is recorded separately from uncertain or failed attempts; previews create no send log.
A successful response means SMTP accepted the message. A failure can occur after transmission starts. Check provider logs before retrying; the API has no automatic retries or deduplication.
Create a tenant and issue its first key
/api/admin/tenantsCreate tenant metadata and a unique API key atomically. SMTP can be configured afterward.
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| name | Required | 1–200 characters, no control characters. |
| contactEmail | Optional | Bare email address; omit/null to clear. |
| isActive | Optional | Defaults to true; false blocks the tenant key. |
JSON request
{
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true
}Example request
curl --fail-with-body -X POST "https://your-subdomain.example/api/admin/tenants" \
-H "ApiKey: <admin-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 201
| Field | Type | Meaning |
|---|---|---|
| tenant | object | Tenant metadata as described below. |
| apiKey | string | Full new key; returned once only. |
| note | string | Save and securely hand off the key. |
| tenant.id | UUID | Tenant identifier. |
| tenant.name | string | Tenant display name. |
| tenant.contactEmail | string/null | Optional contact address. |
| tenant.isActive | boolean | Whether the key is enabled. |
| tenant.createdAt | timestamp | Creation time (UTC). |
| tenant.smtpConfigured | boolean | SMTP settings have been saved; does not test delivery. |
| tenant.keyIdentifier | string | Masked identifier, not a usable key. |
| tenant.keyCreatedAt | timestamp | Current key creation/rotation time. |
{
"tenant": {
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true,
"createdAt": "2026-10-07T12:00:00Z",
"smtpConfigured": false,
"keyIdentifier": "pmt_12345678…",
"keyCreatedAt": "2026-10-07T12:00:00Z"
},
"apiKey": "pmt_<identifier>.<secret>",
"note": "Save this key now and hand it to the tenant securely. It cannot be retrieved later."
}The full key is returned once. Save it securely and hand it to the tenant manually. An inactive tenant receives a key that cannot authenticate until reactivated.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable.
List tenants with pagination
/api/admin/tenantsList tenant metadata, masked key identifiers and SMTP setup state. No secrets are included.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| page | Optional query integer | Default 1; range 1–1000000. |
| pageSize | Optional query integer | Default 50; range 1–100. |
Example request
curl --fail-with-body -X GET "https://your-subdomain.example/api/admin/tenants" \
-H "ApiKey: <admin-key>"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| items | array | Tenant metadata objects. |
| page | integer | Current page. |
| pageSize | integer | Current page size. |
| total | integer | Total tenants. |
| items[].id | UUID | Tenant identifier. |
| items[].name | string | Tenant display name. |
| items[].contactEmail | string/null | Optional contact address. |
| items[].isActive | boolean | Whether the key is enabled. |
| items[].createdAt | timestamp | Creation time (UTC). |
| items[].smtpConfigured | boolean | SMTP settings have been saved; does not test delivery. |
| items[].keyIdentifier | string | Masked identifier, not a usable key. |
| items[].keyCreatedAt | timestamp | Current key creation/rotation time. |
{
"items": [
{
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true,
"createdAt": "2026-10-07T12:00:00Z",
"smtpConfigured": false,
"keyIdentifier": "pmt_12345678…",
"keyCreatedAt": "2026-10-07T12:00:00Z"
}
],
"page": 1,
"pageSize": 50,
"total": 1
}400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable.
Read a tenant
/api/admin/tenants/{tenantId}Fetch metadata and setup state for one tenant.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| tenantId | Required path UUID | Target tenant created by the admin. |
Example request
curl --fail-with-body -X GET "https://your-subdomain.example/api/admin/tenants/<tenant-id>" \
-H "ApiKey: <admin-key>"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| id | UUID | Tenant identifier. |
| name | string | Tenant display name. |
| contactEmail | string/null | Optional contact address. |
| isActive | boolean | Whether the key is enabled. |
| createdAt | timestamp | Creation time (UTC). |
| smtpConfigured | boolean | SMTP settings have been saved; does not test delivery. |
| keyIdentifier | string | Masked identifier, not a usable key. |
| keyCreatedAt | timestamp | Current key creation/rotation time. |
{
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true,
"createdAt": "2026-10-07T12:00:00Z",
"smtpConfigured": false,
"keyIdentifier": "pmt_12345678…",
"keyCreatedAt": "2026-10-07T12:00:00Z"
}400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 404 unknown tenant.
Update tenant metadata or active status
/api/admin/tenants/{tenantId}Replace name, contact email and active status. SMTP settings and key are preserved.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| tenantId | Required path UUID | Target tenant created by the admin. |
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| name | Required | 1–200 characters, no control characters. |
| contactEmail | Optional | Bare email address; omit/null to clear. |
| isActive | Optional | Defaults to true; false blocks the tenant key. |
JSON request
{
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true
}Example request
curl --fail-with-body -X PUT "https://your-subdomain.example/api/admin/tenants/<tenant-id>" \
-H "ApiKey: <admin-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| id | UUID | Tenant identifier. |
| name | string | Tenant display name. |
| contactEmail | string/null | Optional contact address. |
| isActive | boolean | Whether the key is enabled. |
| createdAt | timestamp | Creation time (UTC). |
| smtpConfigured | boolean | SMTP settings have been saved; does not test delivery. |
| keyIdentifier | string | Masked identifier, not a usable key. |
| keyCreatedAt | timestamp | Current key creation/rotation time. |
{
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true,
"createdAt": "2026-10-07T12:00:00Z",
"smtpConfigured": false,
"keyIdentifier": "pmt_12345678…",
"keyCreatedAt": "2026-10-07T12:00:00Z"
}Omitting isActive defaults to true. Set false to immediately disable the tenant key without deleting stored configuration. Omit/null contactEmail to clear it.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 404 unknown tenant.
Regenerate a tenant API key
/api/admin/tenants/{tenantId}/api-key/regenerateAtomically replace the tenant key and return its full new value.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| tenantId | Required path UUID | Target tenant created by the admin. |
Example request
curl --fail-with-body -X POST "https://your-subdomain.example/api/admin/tenants/<tenant-id>/api-key/regenerate" \
-H "ApiKey: <admin-key>"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| tenant | object | Tenant metadata as described below. |
| apiKey | string | Full new key; returned once only. |
| note | string | Save and securely hand off the key. |
| tenant.id | UUID | Tenant identifier. |
| tenant.name | string | Tenant display name. |
| tenant.contactEmail | string/null | Optional contact address. |
| tenant.isActive | boolean | Whether the key is enabled. |
| tenant.createdAt | timestamp | Creation time (UTC). |
| tenant.smtpConfigured | boolean | SMTP settings have been saved; does not test delivery. |
| tenant.keyIdentifier | string | Masked identifier, not a usable key. |
| tenant.keyCreatedAt | timestamp | Current key creation/rotation time. |
{
"tenant": {
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true,
"createdAt": "2026-10-07T12:00:00Z",
"smtpConfigured": false,
"keyIdentifier": "pmt_12345678…",
"keyCreatedAt": "2026-10-07T12:00:00Z"
},
"apiKey": "pmt_<identifier>.<secret>",
"note": "Save this key now and hand it to the tenant securely. It cannot be retrieved later."
}The old key stops working immediately. No overlap or automatic handoff. Save the new key and update the tenant automation secret. SMTP and metadata are unchanged.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 404 unknown tenant.
Read tenant SMTP settings
/api/admin/tenants/{tenantId}/smtpReturns destination, sender and credential-presence information without revealing saved secrets.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| tenantId | Required path UUID | Target tenant created by the admin. |
Example request
curl --fail-with-body -X GET "https://your-subdomain.example/api/admin/tenants/<tenant-id>/smtp" \
-H "ApiKey: <admin-key>"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| host | string | Configured destination. |
| port | integer | SMTP port. |
| security | string | TLS mode. |
| fromEmail | string | Sender email. |
| fromName | string | Sender display name. |
| hasCredentials | boolean | Encrypted credentials exist; username/password/ciphertext are never returned. |
{
"host": "smtp.your-provider.example",
"port": 587,
"security": "StartTls",
"fromEmail": "reports@example.com",
"fromName": "Automation Reports",
"hasCredentials": true
}Neither username, password nor encrypted credentials are returned. HTTP 409 means SMTP has not been configured.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 404 unknown tenant. 409 missing/undecryptable SMTP configuration.
Read your SMTP settings
/api/tenant/smtpReturns destination, sender and credential-presence information without revealing saved secrets.
Example request
curl --fail-with-body -X GET "https://your-subdomain.example/api/tenant/smtp" \
-H "ApiKey: <tenant-key>"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| host | string | Configured destination. |
| port | integer | SMTP port. |
| security | string | TLS mode. |
| fromEmail | string | Sender email. |
| fromName | string | Sender display name. |
| hasCredentials | boolean | Encrypted credentials exist; username/password/ciphertext are never returned. |
{
"host": "smtp.your-provider.example",
"port": 587,
"security": "StartTls",
"fromEmail": "reports@example.com",
"fromName": "Automation Reports",
"hasCredentials": true
}Neither username, password nor encrypted credentials are returned. HTTP 409 means SMTP has not been configured.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 409 missing/undecryptable SMTP configuration.
Update tenant SMTP settings
/api/admin/tenants/{tenantId}/smtpSave SMTP destination, TLS mode, encrypted credentials and sender details. This operation sends no email.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| tenantId | Required path UUID | Target tenant created by the admin. |
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| host | Required | Public SMTP hostname/address, maximum 253 characters. |
| port | Optional | 1–65535; defaults to 587. |
| security | Optional | StartTls (default, usually port 587) or SslOnConnect (required for port 465). TLS is required in production. |
| username | Optional | Maximum 1000 characters. Stored encrypted and never returned. |
| password | Optional on edit | Maximum 1000 characters. Empty/omitted preserves saved password, including when username changes. |
| fromEmail | Required | Provider-authorized bare sender address. |
| fromName | Optional | Sender name, maximum 200 characters; defaults to ProspectMailer. |
| clearCredentials | Optional | Default false. True with empty username/password clears both for an authorized relay. |
JSON request
{
"host": "smtp.your-provider.example",
"port": 587,
"security": "StartTls",
"username": "your-smtp-user",
"password": "your-smtp-password",
"fromEmail": "reports@example.com",
"fromName": "Automation Reports",
"clearCredentials": false
}Example request
curl --fail-with-body -X PUT "https://your-subdomain.example/api/admin/tenants/<tenant-id>/smtp" \
-H "ApiKey: <admin-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| host | string | Configured destination. |
| port | integer | SMTP port. |
| security | string | TLS mode. |
| fromEmail | string | Sender email. |
| fromName | string | Sender display name. |
| hasCredentials | boolean | Encrypted credentials exist; username/password/ciphertext are never returned. |
{
"host": "smtp.your-provider.example",
"port": 587,
"security": "StartTls",
"fromEmail": "reports@example.com",
"fromName": "Automation Reports",
"hasCredentials": true
}Blank/omitted password preserves the old password, including when username changes. To clear credentials, set clearCredentials=true with empty username/password. Production permits only TLS and public destination addresses.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 404 unknown tenant. 409 missing/undecryptable SMTP configuration.
Update your SMTP settings
/api/tenant/smtpSave SMTP destination, TLS mode, encrypted credentials and sender details. This operation sends no email.
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| host | Required | Public SMTP hostname/address, maximum 253 characters. |
| port | Optional | 1–65535; defaults to 587. |
| security | Optional | StartTls (default, usually port 587) or SslOnConnect (required for port 465). TLS is required in production. |
| username | Optional | Maximum 1000 characters. Stored encrypted and never returned. |
| password | Optional on edit | Maximum 1000 characters. Empty/omitted preserves saved password, including when username changes. |
| fromEmail | Required | Provider-authorized bare sender address. |
| fromName | Optional | Sender name, maximum 200 characters; defaults to ProspectMailer. |
| clearCredentials | Optional | Default false. True with empty username/password clears both for an authorized relay. |
JSON request
{
"host": "smtp.your-provider.example",
"port": 587,
"security": "StartTls",
"username": "your-smtp-user",
"password": "your-smtp-password",
"fromEmail": "reports@example.com",
"fromName": "Automation Reports",
"clearCredentials": false
}Example request
curl --fail-with-body -X PUT "https://your-subdomain.example/api/tenant/smtp" \
-H "ApiKey: <tenant-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| host | string | Configured destination. |
| port | integer | SMTP port. |
| security | string | TLS mode. |
| fromEmail | string | Sender email. |
| fromName | string | Sender display name. |
| hasCredentials | boolean | Encrypted credentials exist; username/password/ciphertext are never returned. |
{
"host": "smtp.your-provider.example",
"port": 587,
"security": "StartTls",
"fromEmail": "reports@example.com",
"fromName": "Automation Reports",
"hasCredentials": true
}Blank/omitted password preserves the old password, including when username changes. To clear credentials, set clearCredentials=true with empty username/password. Production permits only TLS and public destination addresses.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 409 missing/undecryptable SMTP configuration.
Permanently delete a tenant
/api/admin/tenants/{tenantId}Delete the tenant and its SMTP/API-key records transactionally.
Path and query parameters
| Field | Requirement / type | Description |
|---|---|---|
| tenantId | Required path UUID | Target tenant created by the admin. |
| confirmTenantId | Required query UUID | Must equal tenantId; confirms permanent deletion. |
Example request
curl --fail-with-body -X DELETE "https://your-subdomain.example/api/admin/tenants/<tenant-id>?confirmTenantId=<tenant-id>" \
-H "ApiKey: <admin-key>"Response · HTTP 204
No response body.
Destructive. Existing tenant keys stop working. Accepted/delivered messages cannot be recalled, and backups follow operator retention. No request body.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 404 unknown tenant.
Read your tenant
/api/tenantReturn metadata and SMTP setup state for the tenant identified by your key. No target ID is accepted.
Example request
curl --fail-with-body -X GET "https://your-subdomain.example/api/tenant" \
-H "ApiKey: <tenant-key>"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| id | UUID | Tenant identifier. |
| name | string | Tenant display name. |
| contactEmail | string/null | Optional contact address. |
| isActive | boolean | Whether the key is enabled. |
| createdAt | timestamp | Creation time (UTC). |
| smtpConfigured | boolean | SMTP settings have been saved; does not test delivery. |
| keyIdentifier | string | Masked identifier, not a usable key. |
| keyCreatedAt | timestamp | Current key creation/rotation time. |
{
"id": "11111111-1111-4111-8111-111111111111",
"name": "Example automation",
"contactEmail": "owner@example.com",
"isActive": true,
"createdAt": "2026-10-07T12:00:00Z",
"smtpConfigured": false,
"keyIdentifier": "pmt_12345678…",
"keyCreatedAt": "2026-10-07T12:00:00Z"
}400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable.
Send an HTML email
/api/emails/sendWrap AI-supplied HTML in the navy-header email design and send through your tenant SMTP with a plain-text alternative.
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| to | Required | 1–50 bare recipient email addresses. |
| subject | Required | 1–200 characters; no control characters. |
| htmlBody | Required | 1–500000 characters of AI HTML content. Wrapped in the navy-header design with inline styling; subject supplies the header title. Full HTML documents use their body content. |
| textBody | Optional | Maximum 500000 characters; absent/blank uses generic HTML-view instruction. |
JSON request
{
"to": [
"recipient@example.com"
],
"subject": "Your automation report",
"htmlBody": "<h1>Automation report</h1><p>Your results are ready.</p>",
"textBody": "Your results are ready."
}Example request
curl --fail-with-body -X POST "https://your-subdomain.example/api/emails/send" \
-H "ApiKey: <tenant-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| status | string | accepted means SMTP accepted the DATA transaction. |
| messageId | string | Identifier for provider-log correlation. |
| note | string | Acceptance is not confirmed inbox delivery. |
{
"status": "accepted",
"messageId": "example-message-id@example.com",
"note": "SMTP accepted the message; inbox delivery is not confirmed."
}Sends real email. Recipients are concealed from one another. The subject and body come from your AI workflow; the service supplies layout and default styling, not predefined report content. HTML is trusted caller content. Final bodies are stored in EmailLogs. Inspect provider logs before retrying an uncertain failure. SMTP must be configured first.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 409 missing/undecryptable SMTP configuration. 502 SMTP failure; 504 timeout. Delivery may be uncertain; inspect provider logs before retrying.
Render and send a prospect report
/api/prospects/sendRender a navy/teal HTML digest and complete plain-text alternative from structured prospects, then send through your tenant SMTP.
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| to | Required | 1–50 bare recipient email addresses. |
| subject | Required | 1–200 characters; no control characters. |
| title | Optional | Maximum 200 characters. |
| summary | Optional | Maximum 5000 characters. |
| reportDate | Optional | YYYY-MM-DD; defaults to current UTC date. |
| prospects | Required | 1–100 objects; companyName required; every field maximum 5000 characters. |
Prospect fields
Each field allows at most 5000 characters. Text is escaped and links must use HTTP/HTTPS.
| Field | Requirement / type | Description |
|---|---|---|
| companyName | Required | Company name. |
| industry | Optional | Business industry. |
| location | Optional | Business location. |
| websiteUrl | Optional | HTTP/HTTPS company website. |
| ceoName | Optional | CEO/owner name. |
| ceoTitle | Optional | Actual leadership title. |
| ceoInfo | Optional | Professional background. |
| ceoEmail | Optional | Published executive business email; never guessed. |
| ceoSourceUrl | Optional | HTTP/HTTPS leadership source. |
| generalEmail | Optional | General business email. |
| phone | Optional | Business phone. |
| contactUrl | Optional | HTTP/HTTPS contact page. |
| needEvidence | Optional | Evidence of software need. |
| evidenceType | Optional | Caller-provided confirmed/inferred classification. |
| evidenceUrl | Optional | HTTP/HTTPS evidence source. |
| signalDate | Optional | Caller-provided signal date text. |
| opportunity | Optional | Proposed solution. |
| budget | Optional | Published budget or explicitly missing. |
| priority | Optional | Caller-assigned priority. |
JSON request
{
"to": [
"recipient@example.com"
],
"subject": "Business software opportunities",
"title": "Your opportunity digest",
"summary": "Example data supplied by your automation.",
"reportDate": "2026-10-07",
"prospects": [
{
"companyName": "Example Company (fictional)",
"industry": "Wholesale",
"websiteUrl": "https://example.com",
"ceoName": "Example Owner",
"ceoTitle": "Owner",
"ceoInfo": "Example professional background.",
"ceoEmail": "owner@example.com",
"ceoSourceUrl": "https://example.com/team",
"generalEmail": "hello@example.com",
"phone": "+1 555 0100",
"contactUrl": "https://example.com/contact",
"needEvidence": "Example request for inventory integration.",
"evidenceType": "Inferred",
"evidenceUrl": "https://example.com/news",
"signalDate": "2026-10-07",
"opportunity": "Inventory portal",
"budget": "Not published",
"priority": "Medium",
"location": "Example location"
}
]
}Example request
curl --fail-with-body -X POST "https://your-subdomain.example/api/prospects/send" \
-H "ApiKey: <tenant-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| status | string | accepted means SMTP accepted the DATA transaction. |
| messageId | string | Identifier for provider-log correlation. |
| note | string | Acceptance is not confirmed inbox delivery. |
{
"status": "accepted",
"messageId": "example-message-id@example.com",
"note": "SMTP accepted the message; inbox delivery is not confirmed."
}Sends real email. Text is HTML-encoded and only HTTP/HTTPS links are clickable. Missing information is labeled; executive emails are never guessed. The caller verifies supplied facts. SMTP must be configured first.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable. 409 missing/undecryptable SMTP configuration. 502 SMTP failure; 504 timeout. Delivery may be uncertain; inspect provider logs before retrying.
Preview a report without sending
/api/prospects/previewRender the same HTML digest returned by structured sending, without contacting SMTP.
Request fields
| Field | Requirement / type | Description |
|---|---|---|
| to | Required | 1–50 bare recipient email addresses. |
| subject | Required | 1–200 characters; no control characters. |
| title | Optional | Maximum 200 characters. |
| summary | Optional | Maximum 5000 characters. |
| reportDate | Optional | YYYY-MM-DD; defaults to current UTC date. |
| prospects | Required | 1–100 objects; companyName required; every field maximum 5000 characters. |
Prospect fields
Each field allows at most 5000 characters. Text is escaped and links must use HTTP/HTTPS.
| Field | Requirement / type | Description |
|---|---|---|
| companyName | Required | Company name. |
| industry | Optional | Business industry. |
| location | Optional | Business location. |
| websiteUrl | Optional | HTTP/HTTPS company website. |
| ceoName | Optional | CEO/owner name. |
| ceoTitle | Optional | Actual leadership title. |
| ceoInfo | Optional | Professional background. |
| ceoEmail | Optional | Published executive business email; never guessed. |
| ceoSourceUrl | Optional | HTTP/HTTPS leadership source. |
| generalEmail | Optional | General business email. |
| phone | Optional | Business phone. |
| contactUrl | Optional | HTTP/HTTPS contact page. |
| needEvidence | Optional | Evidence of software need. |
| evidenceType | Optional | Caller-provided confirmed/inferred classification. |
| evidenceUrl | Optional | HTTP/HTTPS evidence source. |
| signalDate | Optional | Caller-provided signal date text. |
| opportunity | Optional | Proposed solution. |
| budget | Optional | Published budget or explicitly missing. |
| priority | Optional | Caller-assigned priority. |
JSON request
{
"to": [
"recipient@example.com"
],
"subject": "Business software opportunities",
"title": "Your opportunity digest",
"summary": "Example data supplied by your automation.",
"reportDate": "2026-10-07",
"prospects": [
{
"companyName": "Example Company (fictional)",
"industry": "Wholesale",
"websiteUrl": "https://example.com",
"ceoName": "Example Owner",
"ceoTitle": "Owner",
"ceoInfo": "Example professional background.",
"ceoEmail": "owner@example.com",
"ceoSourceUrl": "https://example.com/team",
"generalEmail": "hello@example.com",
"phone": "+1 555 0100",
"contactUrl": "https://example.com/contact",
"needEvidence": "Example request for inventory integration.",
"evidenceType": "Inferred",
"evidenceUrl": "https://example.com/news",
"signalDate": "2026-10-07",
"opportunity": "Inventory portal",
"budget": "Not published",
"priority": "Medium",
"location": "Example location"
}
]
}Example request
curl --fail-with-body -X POST "https://your-subdomain.example/api/prospects/preview" \
-H "ApiKey: <tenant-key>" \
-H "Content-Type: application/json" \
--data-binary @request.jsonResponse · HTTP 200
<!doctype html><html><body>Formatted prospect report...</body></html>Safe to preview. No email is sent and no SMTP configuration is required. Recipients and subject must still satisfy the sending validation. Response content type is text/html.
400 invalid input; 401 invalid/revoked key; 403 wrong credential privilege; 413 body over 1 MiB; 429 quota exceeded; 503 service/database unavailable.
Check process liveness
/healthConfirm that the API process is responding.
Example request
curl --fail-with-body -X GET "https://your-subdomain.example/health"Response · HTTP 200
| Field | Type | Meaning |
|---|---|---|
| status | string | ok |
| check | string | liveness only |
{
"status": "ok",
"check": "liveness only"
}No authentication. This does not test PostgreSQL, SMTP or inbox delivery.
This is liveness only; it does not verify PostgreSQL or SMTP.