Authentication
Secure your API requests with Bearer token authentication.
Creating API Keys
You can create API keys in two ways:
- From the API Keys dashboard
- Programmatically via
POST /v1/api-keys
Keys are shown once at creation. Store them securely. If you lose a key, revoke it and create a new one.
Bearer Token Format
Include your API key in the Authorization header of every request:
Authorization: Bearer sf_live_your_api_key
All keys start with sf_live_ for production or sf_test_ for test mode.
Example Request
curl https://smtpfa.st/api/v1/emails \
-H "Authorization: Bearer sf_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"from":"[email protected]","to":["[email protected]"],"subject":"Test","html":"<p>Hello</p>"}'API Key Scopes
Scopes control what each key can access. When creating a key, select only the permissions you need.
| Parameter | Type | Required | Description |
|---|---|---|---|
| email:send | scope | No | Emails: POST /v1/emails and batch sends |
| email:read | scope | No | Emails: Look up sent emails and analytics |
| domain:read | scope | No | Domains: List domains and verification status |
| domain:write | scope | No | Domains: Add, verify and delete domains |
| contact:read | scope | No | Contacts: List and export contacts |
| contact:write | scope | No | Contacts: Create, update, import, suppress |
| form:read | scope | No | Signup forms: List forms and pending signups |
| form:write | scope | No | Signup forms: Create and edit forms |
| webhook:read | scope | No | Webhooks: List webhooks |
| webhook:write | scope | No | Webhooks: Create, edit, test and delete webhooks |
| logs:read | scope | No | Logs: GET /v1/logs with filters by type, time, recipient, domain and tag |
| inbound:read | scope | No | Inbound email: List messages, download raw mail and attachments; in inboxes, mark read, label, archive and write drafts (sending them needs email:send) |
| inbound:delete | scope | No | Inbound email: Delete received messages and their files, and move inbox threads to trash |
| team:read | scope | No | Team: List members, and pending invitations for owners and admins |
| team:manage | scope | No | Team: Invite people, revoke invitations, change roles, remove members |
| apikey:manage | scope | No | API keys: List, create and revoke API keys |
A key with no scopes chosen gets a default set, whether it is created in the dashboard or through the API. Pass scopes to narrow it.
Rate Limit Headers
Every response includes rate limit headers so you can track your usage:
X-RateLimit-Limit: 100 X-RateLimit-Remaining: 97 X-RateLimit-Reset: 1712345678
See the Rate Limits page for details on limits per tier and how to handle 429 responses.
Authentication Errors
| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 403 | Key does not have the required scope |
Check what a key can do
Before this endpoint the only way to discover a key's scopes was to call each one and see which returned 403. This returns them directly, along with the team it belongs to and where it stands against the rate limit. It needs no scope of its own, so any valid key can call it.
/v1/meThe scopes, team, account tier and rate limit position of the key making the request, and the user who created it. user_id matches user_id on GET /v1/team/members, so you can tell which member the key acts as.
Response
{
"api_key_id": "key_01j9x3p2q7",
"user_id": "user_01j9x3m4k2",
"scopes": ["email:send", "email:read", "domain:read"],
"team_id": "team_01j9x3n8r1",
"team_sending_status": "active",
"account": { "tier": "pro", "status": "active" },
"send_checks": { "display_name_enforced": false, "link_scan_enforced": false },
"rate_limit": { "per_second": 10, "remaining": 9, "reset": 1758374400000 }
}Check usage against your plan
Emails in the last 24 hours and this month against your limit, prepaid credits, and contacts, segments, broadcasts and domains against their limits. Check it before a large send or an import instead of finding out from a refusal. The response has the same shape as Resend's GET /usage, so the Resend SDKs' usage call works against SMTPfast. A null limit means no cap. Emails count recipients, the unit the quota charges in, and received mail does not count against the limit. AI credits and automation runs are not offered: they are in the response only to match Resend's shape, and their limit is 0. On a team, the email quota and broadcast cap follow the team owner's plan and the domain limit the team's plan. Like /v1/me, it needs no scope.
/v1/usageUsage and limits for the account the key belongs to.
Response
{
"object": "usage",
"emails": {
"daily": { "used": 37, "limit": null, "sent": 37, "received": 3, "resets_at": null },
"monthly": { "used": 1200, "limit": 50000, "sent": 1200, "received": 40, "resets_at": "2026-11-01T00:00:00.000Z" },
"credits": { "balance": 500 },
"effective_remaining": 49300
},
"contacts": { "used": 205, "limit": 1000 },
"segments": { "used": 1, "limit": 50 },
"broadcasts": { "used": 4, "limit": 50 },
"ai_credits": { "used": 0, "limit": 0, "next_increase_at": null },
"automation_runs": { "used": 0, "limit": 0, "resets_at": "2026-11-01T00:00:00.000Z" },
"domains": { "used": 2, "limit": null },
"rate_limit": { "limit": 10, "duration": "1000ms" }
}