API Keys & SMTP Credentials
PostMTA exposes two credential systems: a REST API accessed via bearer tokens, and an SMTP endpoint accessed via SMTP AUTH PLAIN. Both credential types share the same RBAC role model and workspace membership.
API Key Lifecycle
Create a Key
POST to /v1/keys with a JSON body specifying the key name, scopes, and optional expiry. The response includes the full key value — shown only once — and a truncated preview for future reference.
curl -X POST https://api.postmta.com/v1/keys \
-H "Authorization: Bearer pmta_live_admin_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "production-send-key",
"scopes": ["messages:send", "messages:read"],
"workspace_id": "ws_01HXABC123DEF456",
"expires_at": "2027-07-18T00:00:00Z",
"description": "Used by the order confirmation service"
}'Response — the key field appears only here:
{
"id": "key_01HXKEY001",
"name": "production-send-key",
"key": "pmta_live_sk_01HXabcdef123456789abcdef123456789abcdef12",
"key_preview": "pmta_live_sk_01HXab...ef12",
"scopes": ["messages:send", "messages:read"],
"workspace_id": "ws_01HXABC123DEF456",
"created_at": "2026-07-18T09:00:00Z",
"expires_at": "2027-07-18T00:00:00Z",
"last_used_at": null,
"status": "active"
}Revoke a Key
Revocation is immediate and permanent. Any in-flight request using the revoked key receives 401 Unauthorized.
curl -X DELETE https://api.postmta.com/v1/keys/key_01HXKEY001 \
-H "Authorization: Bearer pmta_live_admin_xxxxxxxxxxxx"Response:
{
"id": "key_01HXKEY001",
"status": "revoked",
"revoked_at": "2026-07-18T14:30:00Z"
}List Keys
curl https://api.postmta.com/v1/keys \
-H "Authorization: Bearer pmta_live_admin_xxxxxxxxxxxx"Returns all keys for the workspace. The full key field is never returned for existing keys — only the key_preview.
SMTP AUTH PLAIN
For integrations that prefer SMTP submission, PostMTA exposes an SMTP submission endpoint. SMTP credentials are separate from API keys and have their own creation and revocation flow.
SMTP Ports
| Port | Encryption | Use | Notes |
|---|---|---|---|
2525 | STARTTLS | Lab / development | Unencrypted until STARTTLS upgrade |
587 | STARTTLS (required) | Production | Connection dropped if TLS not established |
465 | Implicit TLS | Production (legacy) | Deprecated but still supported |
AUTH PLAIN Command
After connecting and completing STARTTLS, issue AUTH PLAIN. The credential format is:
auth_plain_id\0username\0passwordWhere username is the SMTP username and password is the SMTP password. Both are ASCII. The entire string is Base64-encoded before sending.
S: 220 mail.postmta.com ESMTP PostMTA
C: EHLO client.example.com
S: 250-mail.postmta.com
S: 250-STARTTLS
S: 250 AUTH PLAIN
C: AUTH PLAIN
S: 334
C: AG1haWwuZXhhbXBsZS5jb20AYWRtaW5f c3BfdGtleV9wYXNzXzE5MjM0NTY3OA==
S: 235 2.7.0 Authentication successfulDecoded auth string for the example above:
mail.example.com <- username (SMTP credential name)
admin_smtp_pass_192345678 <- passwordSMTP Send Example
After authentication, send a message using standard SMTP envelope commands:
C: MAIL FROM:<hello@mail.example.com> SIZE=2048
S: 250 2.1.0 OK
C: RCPT TO:<alice@example.com>
S: 250 2.1.5 OK
C: DATA
S: 354 Start mail input; end with <CRLF>.<CRLF>
C: From: Hello <hello@mail.example.com>
C: To: alice@example.com
C: Subject: Order Confirmation
C:
C: Hello Alice,
C: Your order #12345 has shipped.
C: .
S: 250 2.0.0 OK: queued as msg_01HX5K9P7N3M4Q6R8T2V4W6Y8Role-Based Access Control
Every principal (API key or SMTP credential) is assigned a role at the workspace level. Roles are hierarchical — each role includes all permissions of the roles below it.
Role Permissions
| Permission | Viewer | Editor | Operator | Owner |
|---|---|---|---|---|
| Read analytics and delivery stats | + | + | + | + |
| Read sending domains and IP pools | + | + | + | + |
| Send email (messages:send) | - | + | + | + |
| Manage suppression lists | - | + | + | + |
| Manage webhooks | - | + | + | + |
| Create and revoke API keys | - | - | + | + |
| Manage IP pools and warmup | - | - | + | + |
| Apply shaping policy | - | - | + | + |
| Manage workspace members and roles | - | - | - | + |
| Billing and credit purchase | - | - | - | + |
| Air-gap admin grants | - | - | - | + |
| Delete workspace | - | - | - | + |
+ = has permission - = no permission
Safe Credential View (No Hash Columns)
API keys and SMTP credentials are stored with their password hashes using Argon2id. When listing credentials via the API, hashes are never returned. If you need to query credentials directly from the database (strongly discouraged), use the safe read view that projects only non-sensitive columns:
SELECT
id,
name,
key_preview,
scopes,
workspace_id,
created_at,
expires_at,
last_used_at,
status
FROM postmta.credential_safe_view
WHERE workspace_id = 'ws_01HXABC123DEF456';credential_safe_view is the only approved read path for credential metadata. The underlying credentials table is off-limits except to the PostMTA internal agent running under a separate security context.Workspace Membership and RLS
PostMTA uses Row-Level Security (RLS) on all credential and workspace tables. Every API request is scoped to the workspace(s) the calling key has access to. Cross-workspace access requires explicit membership in each workspace.
To grant a key access to an additional workspace:
curl -X POST https://api.postmta.com/v1/workspaces/ws_01HXABC123DEF456/members \
-H "Authorization: Bearer pmta_live_admin_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"key_id": "key_01HXKEY001",
"role": "editor"
}'A key may have different roles in different workspaces. The role is evaluated at request time based on the workspace_id in the request path or payload.
SMTP Credential Creation
Create SMTP credentials separately from API keys. SMTP credentials use a username/password model and are used only for SMTP submission.
curl -X POST https://api.postmta.com/v1/smtp/credentials \
-H "Authorization: Bearer pmta_live_admin_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"username": "mail.example.com",
"description": "Production SMTP submission for example.com",
"workspace_id": "ws_01HXABC123DEF456",
"allowed_sending_domain": "mail.example.com",
"expires_at": "2027-07-18T00:00:00Z"
}'Response — the password field is shown only once:
{
"id": "smtp_cred_01HXSMTCP001",
"username": "mail.example.com",
"password": "smtp_pass_19234567890abcdef",
"password_preview": "smtp_pa...bcdef",
"workspace_id": "ws_01HXABC123DEF456",
"allowed_sending_domain": "mail.example.com",
"created_at": "2026-07-18T09:00:00Z",
"expires_at": "2027-07-18T00:00:00Z",
"status": "active"
}Credential Auditing
All credential lifecycle events are written to the immutable audit log:
- Key and SMTP credential creation (with key/password preview)
- Key and SMTP credential revocation
- Role changes
- Workspace membership changes
- Failed authentication attempts (timestamp, IP, credential preview)
View audit entries:
curl "https://api.postmta.com/v1/audit?resource_type=credential&limit=50" \
-H "Authorization: Bearer pmta_live_admin_xxxxxxxxxxxx"