Inbox management
Register an inbox address to start receiving email at that address. You can list and remove inboxes via the API.
GET /v1/inboxes
Returns all inboxes registered to your account.
curl "https://api2.freecustom.email/v1/inboxes" \
-H "Authorization: Bearer fce_your_api_key"Responses
200Success
{
"success": true,
"data": {
"inboxes": ["test@freecustom.email", "staging@acme.com"],
"count": 2
}
}200Empty
{
"success": true,
"data": { "inboxes": [], "count": 0 }
}401Missing or invalid API key
{
"success": false,
"error": "unauthorized",
"message": "Missing or invalid API key. Pass your key in the Authorization header: Bearer fce_..."
}POST /v1/inboxes
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
| inbox | string | Yes | Full email address (e.g. test@freecustom.email) |
| isTesting | boolean | No | Flag this inbox for testing purposes to enable zero-latency event timelines in the Auth Flow Debugger. |
curl -X POST https://api2.freecustom.email/v1/inboxes \
-H "Authorization: Bearer fce_your_api_key" \
-H "Content-Type: application/json" \
-d '{"inbox":"mytest@ditapi.info", "isTesting": true}'Responses
201Inbox registered
{
"success": true,
"data": {
"inbox": "mytest@ditapi.info",
"registered_at": "2026-03-04T10:00:00.000Z"
}
}400Missing inbox
{
"success": false,
"error": "missing_field",
"message": "inbox is required."
}400Invalid email format
{
"success": false,
"error": "invalid_inbox",
"message": "\"not-an-email\" is not a valid email address."
}403Custom domain requires upgrade
{
"success": false,
"error": "plan_restriction",
"message": "Custom domain inboxes require the Startup plan or higher.",
"upgrade_url": "https://freecustom.email/api/pricing"
}409Already registered
{
"success": false,
"error": "already_registered",
"message": "mytest@ditapi.info is already registered to this account."
}POST /v1/inboxes/{inbox}/tests
Marks the start of a testing boundary for this inbox. Useful in test suites (Playwright, Cypress, Selenium) to group timeline events together under a single test run ID. Logs a test_started event in the Timeline.
| Field | Type | Required | Description |
|---|---|---|---|
| test_id | string | No | Optional custom test ID. If omitted, one will be generated automatically. |
curl -X POST https://api2.freecustom.email/v1/inboxes/mytest@ditapi.info/tests \
-H "Authorization: Bearer fce_your_api_key" \
-H "Content-Type: application/json" \
-d '{"test_id":"e2e-signup-1"}'Responses
200Test started
{
"success": true,
"data": {
"test_id": "e2e-signup-1",
"inbox": "mytest@ditapi.info",
"started_at": "2026-03-04T10:05:00.000Z"
}
}GET /v1/inboxes/{inbox}/timeline
Returns the timeline history for a specific inbox. This shows the test run history and event sequence for debugging failed tests. If the inbox was registered with isTesting: true, zero-latency early timeline events like smtp_rcpt_received will be tracked. Cost: 2 requests.
| Field | Type | Required | Description |
|---|---|---|---|
| test_id | string | No | Optional test ID to filter the timeline events by a specific test run. |
curl "https://api2.freecustom.email/v1/inboxes/mytest@ditapi.info/timeline?test_id=e2e-signup-1" \
-H "Authorization: Bearer fce_your_api_key"Responses
200Success
{
"success": true,
"data": {
"inbox": "mytest@ditapi.info",
"events": [
{ "id": "evt_1", "type": "test_started", "timestamp": 1714152000000, "test_run_id": "e2e-signup-1" },
{ "id": "evt_2", "type": "smtp_rcpt_received", "timestamp": 1714152000500, "latency_ms": 500, "test_run_id": "e2e-signup-1" },
{ "id": "evt_3", "type": "email_received", "timestamp": 1714152001000, "latency_ms": 1000, "test_run_id": "e2e-signup-1", "metadata": { "subject": "Verify your email" } },
{ "id": "evt_4", "type": "otp_extracted", "timestamp": 1714152001200, "latency_ms": 200, "test_run_id": "e2e-signup-1", "metadata": { "otp": "123456", "score": 0.99 } }
],
"duration_hours": 24,
"event_count": 4
}
}GET /v1/inboxes/{inbox}/insights
Returns automated failure insights for a specific inbox. This analyzes the inbox activity and detects common issues with test flows. Cost: 3 requests.
curl "https://api2.freecustom.email/v1/inboxes/mytest@ditapi.info/insights" \
-H "Authorization: Bearer fce_your_api_key"Responses
200Success
{
"success": true,
"data": {
"inbox": "mytest@ditapi.info",
"insights": [
{ "type": "slow_delivery", "message": "Email took >3s" },
{ "type": "multiple_detected", "message": "Multiple emails detected" }
],
"analyzed_at": "2026-03-04T10:05:00.000Z"
}
}Inbox Generator — Bulk generation
The Inbox Generator lets you create hundreds of disposable inboxes in a single API call, each pre-wired with a long-lived public OTP polling URL. It is designed for high-volume bot workflows, multi-account testing, CI/CD pipelines, and any automation that needs to create inboxes at scale without exposing your main API key.
Gen API key
The generator uses a scoped Gen API key (fcegen_…) that is separate from your main developer key. It can only call POST /v1/inboxes/generate and GET /v1/otp/public — safe to embed in scripts, CI jobs, or Playwright tests without exposing your full-access key. Create and manage it from the Dashboard → Inbox Generator tab.
POST /v1/inboxes/generate
Requires Developer plan or above. Authenticate with your fcegen_ Gen API key.
| Field | Type | Default | Description |
|---|---|---|---|
| count | integer | 1 | Number of inboxes to generate. |
| username_style | string | random_chars | random_chars, digits_only, letters_only, name, noun_digits, firstname.surname |
| domain_mode | string | any | any, free_only, pro_only, custom_only, specific |
| output_format | string | {email}----{otp_url} | Template for each output line. Variables: {email}, {username}, {domain}, {otp_url}, {token} |
| since | integer | — | Unix ms timestamp embedded as ?since= in every OTP URL. Prevents stale codes from previous sessions. |
| parseCode | boolean | true | Embeds ?parseCode=true in OTP URLs, enabling on-demand extraction at poll time. Required for API inboxes (see below). |
curl -X POST https://api2.freecustom.email/v1/inboxes/generate \
-H "Authorization: Bearer fcegen_your_gen_key" \
-H "Content-Type: application/json" \
-d '{
"count": 5,
"username_style": "firstname.surname",
"domain_mode": "any",
"since": 1716900000000,
"parseCode": true
}'Response
200Generated
{
"success": true,
"count": 5,
"daily_used": 5,
"daily_limit": 500,
"daily_remaining": 495,
"inboxes": [
{
"email": "jade.quasar21@addmy.space",
"username": "jade.quasar21",
"domain": "addmy.space",
"token": "fceotp_24f1add500d18150a02c62e40b395828226a79ab",
"otp_url": "https://api2.freecustom.email/v1/otp/public?token=fceotp_…&since=1716900000000&parseCode=true",
"formatted": "jade.quasar21@addmy.space----https://api2.freecustom.email/v1/otp/public?token=fceotp_…"
}
]
}GET /v1/otp/public — keyless OTP polling
Each generated inbox includes an otp_url that you can poll directly — no API key needed. Tokens are valid for 365 days. Use ?since= to avoid getting codes from a previous session, and ?parseCode=true to trigger on-demand extraction (required for API inboxes).
# Poll for OTP — no API key required
curl "https://api2.freecustom.email/v1/otp/public?token=fceotp_24f1add500d18150a02c62e40b395828226a79ab&since=1716900000000&parseCode=true"200OTP found
{
"success": true,
"otp": "340108",
"code": "340108",
"inbox": "jade.quasar21@addmy.space",
"score": 0.8,
"email_id": "zUllTeLcT4",
"from": "\"Apple\" <appleid@id.apple.com>",
"subject": "Verify your Apple Account email address.",
"timestamp": 1716900060000,
"verification_link": null
}200No OTP yet
{
"success": true,
"otp": null,
"code": null,
"inbox": "jade.quasar21@addmy.space",
"message": "No OTP found in messages received after 2026-05-29T18:00:00.000Z."
}Fast-save mode & on-demand extraction
API-generated inboxes (isApiInbox) skip OTP extraction at SMTP delivery time to maximise throughput. The email is saved to Redis immediately with otp: null. When you poll with ?parseCode=true, the API fetches the stored subject and body, runs the multilingual regex extractor (<1 ms, supports 20+ languages including Chinese, Japanese, Korean, Arabic), and returns the live OTP — all in the same HTTP response. No re-parsing, no extra latency.
If you do not pass ?parseCode=true, the endpoint returns otp: null for API inboxes. The Inbox Generator UI and the generated OTP URLs both include parseCode=true by default.
Full bot workflow example
import time, requests
GEN_KEY = "fcegen_your_gen_key"
API_BASE = "https://api2.freecustom.email/v1"
# 1. Generate an inbox
since = int(time.time() * 1000)
r = requests.post(f"{API_BASE}/inboxes/generate",
headers={"Authorization": f"Bearer {GEN_KEY}"},
json={"count": 1, "since": since, "parseCode": True})
inbox = r.json()["inboxes"][0]
email, otp_url = inbox["email"], inbox["otp_url"]
# 2. Use email on the target site (e.g. Apple ID sign-up)
# ... trigger_signup(email) ...
# 3. Poll until OTP arrives (up to 60 s)
for _ in range(20):
time.sleep(3)
resp = requests.get(otp_url).json()
if resp.get("otp"):
print("OTP:", resp["otp"])
breakDELETE /v1/inboxes/{inbox}
Unregisters the inbox. Path inbox must be URL-encoded (e.g. test%40freecustom.email).
curl -X DELETE "https://api2.freecustom.email/v1/inboxes/mytest%40ditapi.info" \
-H "Authorization: Bearer fce_your_api_key"Responses
200Unregistered
{
"success": true,
"message": "mytest@ditapi.info has been unregistered."
}404Not registered
{
"success": false,
"error": "not_found",
"message": "mytest@ditapi.info is not registered on this account."
}