Authentication

API Documentation

Authentication

Bearer tokens, scoped API keys, SMTP credentials, key rotation, error responses, and security recommendations. Two integration surfaces (REST and SMTP) use distinct credential types — this page covers both.

Bearer token format

The REST API uses Bearer token authentication over HTTPS. Every request to https://api.cloudserverforemail.com/v1/* must include an Authorization header containing a valid API key. Requests over plain HTTP are rejected at the load balancer; the API does not negotiate a downgrade.

# Standard Bearer header format used by every endpoint Authorization: Bearer cse_live_a4f9c2e1b8d6...

Keys are prefixed for environment safety. Production keys begin with cse_live_; staging keys with cse_test_. The prefix is the first thing scanners (GitHub secret scanning, gitleaks, internal CI checks) match against, so accidental commits trigger immediate revocation alerts. The same prefix is used in the dashboard audit log to make per-key activity traceable.

API version pinning. The base path /v1/ is the stable API surface. Future major versions (v2, v3) will be additive paths; v1 endpoints are not deprecated when v2 launches. If you need to lock a specific minor version for reproducibility, send an X-API-Version: 2026-05 header — the response includes X-API-Version-Used with the version that processed the request.

API key scopes

Keys are scoped at creation time. The four scope levels follow the principle of least privilege — create a key with the smallest scope your application actually needs. A separate read-only reporting key for an analytics dashboard limits the blast radius if the dashboard credentials leak; a single root-scoped key for everything is an anti-pattern that we document explicitly because it remains a common one.

ScopeEndpointsTypical use
sendPOST /v1/messages, SMTP relayApplication backend that only sends email; cannot read suppressions or admin endpoints
suppressionsGET/POST/DELETE /v1/suppressions/*Bounce processor, unsubscribe handler, list-cleaning batch jobs
reportingGET /v1/events, GET /v1/statsBI dashboard, deliverability monitoring tool, finance attribution
adminAll of the above + IP pool, webhook configOperations team for infrastructure changes; rarely needed by application code

Scopes are enforced at the request authorisation layer, not at the application layer. A send-scoped key calling GET /v1/suppressions receives a 403 Forbidden with error.code = "scope_insufficient" — the request never reaches the suppressions service. Scope mismatch is logged as a security event in the audit log; legitimate scope errors during development are common, but a sudden burst of scope-mismatched requests in production is a signal worth investigating.

Plan for credential separation early. Most integrations begin with one admin key. By the time the first incident occurs (a credential leak, a third-party tool needing limited access, an audit requiring proof of scoped access), retrofitting scope separation across an existing codebase is painful. Generate scoped keys from the start — one per logical caller.

Code examples

The same authenticated request, expressed in four common environments. The pattern is identical: read the API key from a secrets manager or environment variable, never from a string literal in source code, and pass it in the Authorization header.

cURL

# Always use HTTPS. The endpoint rejects HTTP requests at the LB. curl https://api.cloudserverforemail.com/v1/messages \ -H "Authorization: Bearer $CSE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "alerts@yourdomain.com", "to": "user@example.com", "subject": "Welcome", "html": "<p>Hello</p>" }'

Python (requests)

import os import requests API_KEY = os.environ["CSE_API_KEY"] # raises KeyError if unset response = requests.post( "https://api.cloudserverforemail.com/v1/messages", headers={"Authorization": f"Bearer {API_KEY}"}, json={ "from": "alerts@yourdomain.com", "to": "user@example.com", "subject": "Welcome", "html": "<p>Hello</p>", }, timeout=10, # always set; default is no timeout ) response.raise_for_status() message_id = response.json()["id"]

Node.js (fetch)

const response = await fetch( "https://api.cloudserverforemail.com/v1/messages", { method: "POST", headers: { "Authorization": `Bearer ${process.env.CSE_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: "alerts@yourdomain.com", to: "user@example.com", subject: "Welcome", html: "<p>Hello</p>", }), // always handle non-2xx responses; fetch does not throw on them } ); if (!response.ok) throw new Error(`HTTP ${response.status}`); const { id } = await response.json();

PHP (cURL extension)

<?php $apiKey = getenv('CSE_API_KEY'); $ch = curl_init('https://api.cloudserverforemail.com/v1/messages'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $apiKey", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ 'from' => 'alerts@yourdomain.com', 'to' => 'user@example.com', 'subject' => 'Welcome', 'html' => '<p>Hello</p>', ]), CURLOPT_TIMEOUT => 10, ]); $response = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);

SMTP credentials

The SMTP relay surface uses a separate credential type from the REST API. SMTP credentials authenticate using SASL AUTH PLAIN or AUTH LOGIN mechanisms over TLS. The REST API key cannot be used as an SMTP password and vice versa — they are distinct credentials with distinct scopes, generated separately in the dashboard.

# SMTP relay configuration Host: smtp.cloudserverforemail.com Port (STARTTLS): 587 # negotiated upgrade, recommended Port (SMTPS): 465 # implicit TLS, also supported Port: 2525 # fallback if 587/465 are blocked by network Username: smtp_YOUR_ACCOUNT_ID Password: # generated in dashboard → SMTP Credentials Mechanism: AUTH PLAIN # or AUTH LOGIN

Why two credential systems? The SMTP relay path was designed for legacy applications and infrastructure (Postfix forwarding, transactional flows from CRMs that only speak SMTP, mail-merge tools, monitoring agents) where rotating an SMTP password is expensive but rotating an API key is cheap. Keeping them separate means you can rotate API keys aggressively without breaking SMTP integrations — and rotate SMTP credentials on a longer cadence without affecting the REST API.

Port 25 is intentionally not supported for relay. Most consumer ISPs block outbound port 25; even where it works, it lacks the explicit STARTTLS or SMTPS layer that authenticated relay requires. If your application can only speak port 25, route it through a local Postfix instance configured to relay over 587 to smtp.cloudserverforemail.com.

Error responses

Authentication failures return one of three HTTP status codes, each with a distinct meaning. The combination of HTTP status and the structured error.code in the response body lets your application discriminate between "the key is wrong" and "the key is right but cannot do this thing."

401 UnauthorizedNo valid API key was presented. The header is missing, malformed, or contains a key that does not exist or has been revoked.
HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="api.cloudserverforemail.com" Content-Type: application/json { "error": { "code": "invalid_api_key", "message": "Authentication credentials were not valid.", "request_id": "req_01HV8K2P9F3MZQX" } }
403 ForbiddenThe key is valid but does not have the required scope for the requested operation, or it has been disabled administratively.
HTTP/1.1 403 Forbidden Content-Type: application/json { "error": { "code": "scope_insufficient", "message": "This key has scope 'send' but 'suppressions' is required.", "required_scope": "suppressions", "request_id": "req_01HV8K2P9F3MZQY" } }
429 Too Many RequestsThe key is valid but has exceeded the per-key or per-account rate limit. The response includes a Retry-After header.
HTTP/1.1 429 Too Many Requests Retry-After: 12 X-RateLimit-Limit: 200 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1714912860 Content-Type: application/json { "error": { "code": "rate_limit_exceeded", "message": "Per-key rate limit of 200 requests per second exceeded.", "retry_after_seconds": 12, "request_id": "req_01HV8K2P9F3MZQZ" } }
Repeated 401 responses trigger temporary lockout. After roughly 50 consecutive failed authentication attempts in a short window, the source IP is rate-limited at the edge for 5 minutes — even with a valid key. This protects against credential brute-forcing. Applications that loop on a 401 without backoff will trigger this and then receive 403 responses for valid requests until the lockout clears.

Key lifecycle

Treat API keys the way you treat database passwords: generated, stored in a secrets manager, rotated on a schedule, revoked when team members leave, audited for usage. The dashboard supports the full lifecycle; nothing in this section requires a support ticket.

Generation

Keys are generated server-side using cryptographically secure random bytes, prefixed with the environment indicator, and shown to you exactly once at creation time. The key value is never stored in plaintext on our side — only a hash is retained for verification. If you lose the key, generate a new one; we cannot recover the original.

Storage

The right place for a production API key is a secrets manager (AWS Secrets Manager, HashiCorp Vault, Doppler, 1Password Secrets Automation, GCP Secret Manager). Environment variables are acceptable for development but become problematic in production at scale — rotation requires redeploying every service that reads the variable. Secrets managers solve that by letting the key be fetched at runtime and rotated without redeployment.

Rotation

Generate a new key, deploy applications to use it, then revoke the old one — in that order. Both keys are valid simultaneously during the transition window, which can last as long as your slowest deployment cycle. Rotating quarterly is a defensible default for most senders. Rotating monthly is better. Rotating after every employee departure or vendor relationship change is non-negotiable, and the dashboard's audit log makes the rotation event visible to compliance teams who care about that level of control.

Revocation

Revocation is immediate and cannot be undone. The key returns 401 on the next request, regardless of any in-flight requests — those will complete or fail based on their own state, but no new request authenticated with that key will succeed. The audit log retains the revocation event with timestamp and the operator who performed it.

Security recommendations

The recommendations below are not unique to this API — they apply to any credential-based authentication system. They appear here because senders integrating an email API are often application engineers rather than security engineers, and the threat model for email infrastructure deserves explicit framing.

  • Never commit API keys to version control. Even private repositories. The first thing an attacker who gains repository access does is search the history for credential-shaped strings. The cse_live_ prefix exists specifically so that GitHub secret scanning and similar tools can match keys without false positives.
  • Use environment variables or secrets managers, never config files. Config files end up in CI artefacts, container images, log captures during debugging, and third-party tool integrations. None of those are intended credential storage locations, but all of them have caused credential leaks in published incidents.
  • Generate scoped keys for each application. One send-scoped key for the marketing platform, one suppressions-scoped key for the bounce processor, one reporting-scoped key for the analytics dashboard. The blast radius of a compromise is bounded by the scope of the leaked key, not by the breadth of your account.
  • Pin TLS versions to 1.2 or higher in your HTTP client. The endpoint enforces TLS 1.2 minimum; older versions are rejected at the handshake. Older clients (curl on legacy systems, OpenSSL 1.0.x) may need explicit configuration. PCI DSS 4.0 mandates this regardless of email; the endpoint is aligned with the standard.
  • Set request timeouts in your HTTP client. Most language defaults are "never time out," which is wrong for production. 10 to 30 seconds is the right range for most application calls. A hung request that never times out is a slot in your connection pool that another request cannot use.
  • Monitor key usage in the audit log. A sudden spike in requests from a key that normally sends 100 messages per day is a signal worth investigating — either a campaign launched without coordination, or a credential leak. Either way, the operations team wants to know.
  • Restrict by source IP where possible. Each key can be configured with an IP allowlist in the dashboard. Server-to-server integrations almost always have stable source IPs; locking the key to those IPs means a leaked credential is useless from anywhere else.

If a key is compromised

Time matters. The window between credential disclosure and exploitation is measured in minutes, not hours — automated scrapers harvest GitHub commits, leaked logs, and exposed buckets continuously. The remediation sequence is short and should be familiar to anyone with on-call experience:

  1. Revoke immediately. Dashboard → API Keys → revoke. The key returns 401 from the next request onwards.
  2. Generate a replacement with the same scope — or a tighter scope if the audit reveals the original was over-permissioned.
  3. Update the application with the new key from your secrets manager. Roll the deployment.
  4. Audit log review. Filter by the revoked key. Look for unusual patterns: requests from unexpected IPs, requests outside normal business hours, suppression list deletions, configuration changes.
  5. If exploitation is confirmed (audit log shows requests you did not make), assume related credentials may also be compromised. Rotate adjacent keys and SMTP passwords. Notify your security team and whoever owns compliance reporting.
Do not delete the audit log entries for the compromised key. Forensic analysis often depends on those entries; security and compliance teams need them. The audit log retains revoked-key activity for the configured retention period (default 90 days, extendable on request).

The single thing that helps most in a credential-leak incident is having rotated keys recently. If your last rotation was three years ago, the audit window is longer than the compromise window. If your last rotation was four weeks ago, you know the universe of activity that needs review. Aggressive rotation is uncomfortable; the alternative is worse.