emcognito
Back to Blog

Your Alias API Hit a 429. Here's Which Limit You Hit and What to Do

September 29, 2026

Updated

email alias APIrate limitingHTTP 429Retry-Afterprogrammatic alias creationdeveloper APIEmcognito

Keep your real inbox private.

Unlimited aliases, free. No credit card, passwordless sign-in.

Create a free alias →

Proper email alias API rate limit handling starts with checking a single response header before changing any client code. When an automated script receives an HTTP 429 Too Many Requests response from the Emcognito API, the request was halted by one of two distinct boundaries: a 60-call-per-minute per-key burst limiter or the daily alias-creation cap. Identifying which restriction triggered the response dictates whether your background worker should pause for several seconds or suspend creation jobs until 00:00 UTC.

The 60-Second Answer: Which 429 Did You Get?

Determining why an API call failed does not require trial-and-error debugging. Inspect the HTTP response headers directly:

  • If the response includes a Retry-After header: The request encountered the burst limit of 60 requests per minute per API key. The edge rate limiter rejected the call. As specified in RFC 9110 Section 10.2.7, the header value conveys the duration to wait in seconds. Pause for that duration, add a fractional jitter value, and retry the request.
  • If the response has no Retry-After header: The account exhausted its daily creation cap for the current tier. This restriction is enforced inside application code rather than at the network edge, so no retry header is returned. The daily allocation refreshes at 00:00 UTC. Retrying immediately or within the hour will return another 429.

POST /v1/aliases returns HTTP 200 with the new alias under "alias". The burst limit is 60 requests a minute per key; its 429 carries a Retry-After header giving the seconds until the window resets. The daily alias-creation cap (50 on Plus, 200 on Pro) resets at 00:00 UTC and its 429 carries no Retry-After. Emcognito sends no X-RateLimit-* headers. Because successful responses omit remaining quota counts, client applications must track their own provisioning consumption.

Here is the initial branching logic to incorporate into your HTTP dispatch worker:

def handle_alias_response(response):
    if response.status_code == 200:
        return response.json()["alias"]

if response.status_code == 429:
    retry_after = response.headers.get("Retry-After")
    if retry_after is not None:
        # Burst limit reached: sleep whole seconds and retry
        wait_seconds = int(retry_after)
        return {"action": "retry", "wait_seconds": wait_seconds}
    else:
        # Daily creation cap exhausted: hold until 00:00 UTC
        return {"action": "stop_until_reset", "reset_at": "00:00 UTC"}

response.raise_for_status()

What the Emcognito API Returns on a 429

Building predictable automation against the developer alias API requires understanding the HTTP contract. Emcognito exposes its v1 REST interface at https://api.emcognito.com/v1 without an /api/v1 route prefix. Authentication relies on a standard bearer token inside the HTTP Authorization header:

Authorization: Bearer emk_your_key_here_43_characters_placeholder_xxxx

API keys begin with the literal emk_ prefix followed by 43 URL-safe characters. There is no distinction between live and test keys. Every valid token executes against production records, requiring comprehensive local validation before running continuous tasks.

Successful alias creation requests to POST /v1/aliases yield an HTTP 200 response rather than 201 Created. The payload places the created record under an alias key containing explicit metadata attributes: id, address, status, created_at, forward_count, label, note, source, category, single_use, and expires_at. The created_at value is an integer Unix epoch timestamp rather than an ISO-8601 string, and empty text attributes return as empty strings ("") rather than null.

According to the standard defined in RFC 6585 Section 4, the 429 Too Many Requests status code indicates that the client has sent too many requests in a given amount of time. Under the Emcognito API specification, HTTP 200 responses send no rate-limiting headers, and a 429 generated by the daily creation cap carries no Retry-After header. The Retry-After response header appears under two precise conditions:

  1. On an HTTP 429 generated by the 60-call-per-minute per-key burst limiter.
  2. On an HTTP 503 generated when internal rate-limiting subsystems register upstream backpressure.

In both scenarios, the response body contains a bare JSON error message structured as {"message": "..."}.

Reading Retry-After Without Retrying Early

When the 60-call-per-minute burst ceiling is reached, the Retry-After value reflects the entire window duration in whole seconds rather than an incremental millisecond calculation. Live testing conducted on September 20, 2026, on /v1/aliases confirmed that exceeding the burst ceiling returns an HTTP 429 containing retry-after: 60.

This implementation governs how integration workers must handle backoff intervals:

  • Window duration vs. remaining offset: A header of retry-after: 60 instructs the client to suspend calls for that complete interval. Attempting to subtract local network round-trip time risks dispatching a retry before the server-side window has refreshed.
  • Window-aligned clearance: Because the server reports the complete window duration, a client waiting for the specified seconds avoids resuming before the rate window expires, helping avoid immediate repeat errors. While this approach may hold a task idle slightly longer than the minimum millisecond threshold, it ensures subsequent attempts land after the burst window resets.
  • Uniform handling for 503 backpressure: If an automated routine receives a 503 status code accompanied by a Retry-After header, the worker should treat it as a rate-limiting pause rather than an unrecoverable failure. Route the request through the identical backoff routine used for burst 429 errors.

In distributed systems where multiple background workers share a single API token, waking all waiting processes simultaneously causes secondary collisions. According to the AWS Architecture Blog analysis on exponential backoff and jitter, adding randomized wait times breaks synchronized retry cycles across concurrent clients. Incorporating decorrelated or uniform jitter prevents synchronized bursts from repeatedly triggering the 60-call ceiling:

import random
import time

def calculate_backoff(retry_after_header): base_wait = int(retry_after_header) # Add between 0.5 and 2.5 seconds of random jitter jitter = random.uniform(0.5, 2.5) return base_wait + jitter

The Daily Creation Cap Has No Retry-After Header

The daily volume constraint applies strictly to automated alias generation. It does not restrict read operations. Issuing GET /v1/aliases to inspect existing addresses or parse paginated results does not consume daily creation quota.

According to the published Emcognito pricing schedule, creation limits differ by account tier: Source: Emcognito source.

  • Emcognito Plus: $20 per year (or $2 per month), which includes 50 API alias creations per day and 2,500 monthly forwarded messages.
  • Emcognito Pro: $36 per year (or $4 per month), offering 200 API alias creations per day and 15,000 monthly forwarded messages. Yearly Pro includes three months free and represents the standard operational term for production workloads.

Manual alias generation performed directly inside the web dashboard permits up to 200 aliases per day on all tiers, including Free accounts. Programmatic provisioning through POST /v1/aliases, however, enforces 50 creations per day on Plus and 200 creations per day on Pro.

When this ceiling is reached, internal application code returns an HTTP 429 containing no Retry-After header. The creation counter resets daily at 00:00 UTC. Polling the endpoint every 60 seconds after reaching this threshold serves no operational purpose and consumes burst request allowances. Integration logic must log the event and hold creation jobs until the UTC day rolls over.

Pipelines requiring more than 200 programmatic aliases within 24 hours cannot bypass this limit through retries. Such environments must stage records upstream or distribute provisioning batches across consecutive UTC days.

A Complete Python Wrapper for Both Limits

The following client illustrates resilient email alias API rate limit handling. It differentiates between transient burst pauses and daily quota exhaustion, handles upstream 503 responses, and verifies the returned data object:

import datetime
import random
import time
import requests

class EmcognitoClient: def init(self, api_key): self.base_url = "https://api.emcognito.com/v1" self.session = requests.Session() self.session.headers.update({ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }) self.daily_cap_exhausted_date = None

def _is_daily_cap_active(self):
    if self.daily_cap_exhausted_date is None:
        return False
    # Daily limit resets at 00:00 UTC
    today_utc = datetime.datetime.now(datetime.timezone.utc).date()
    return self.daily_cap_exhausted_date == today_utc

def create_alias(self, label="", note="", max_burst_retries=3):
    if self._is_daily_cap_active():
        raise RuntimeError("Daily alias creation quota is exhausted. Halting until 00:00 UTC.")

    url = f"{self.base_url}/aliases"
    payload = {"label": label, "note": note}
    retries = 0

    while retries <= max_burst_retries:
        response = self.session.post(url, json=payload)

        # Success condition: API responds with 200
        if response.status_code == 200:
            data = response.json()
            return data["alias"]

        # Handle rate limiting (429) and gateway backpressure (503)
        if response.status_code in (429, 503):
            retry_after = response.headers.get("Retry-After")
            
            if retry_after is not None:
                # Case 1: Burst limiter tripped (or temporary 503 backpressure)
                wait_time = int(retry_after) + random.uniform(0.5, 2.0)
                retries += 1
                if retries > max_burst_retries:
                    raise RuntimeError(f"Exceeded maximum burst retries ({max_burst_retries}).")
                time.sleep(wait_time)
                continue
            else:
                # Case 2: Daily creation limit hit (no Retry-After header present)
                self.daily_cap_exhausted_date = datetime.datetime.now(datetime.timezone.utc).date()
                raise RuntimeError("Hit daily creation cap. Reset occurs at 00:00 UTC.")

        # Raise on unexpected HTTP errors (401, 500, etc.)
        response.raise_for_status()

Pacing Requests to Avoid Rate Limits

Production engineering should prevent the 429 execution path whenever possible. Forcing background workers to pause repeatedly wastes computing resources and increases queue latency. Implementing client-side pacing keeps outbound traffic well within the 60-call envelope:

1. Centralize Token Buckets Across Distributed Workers

The 60 requests-per-minute ceiling applies across the entire API key. When running multiple ingestion containers or asynchronous tasks, individual workers must not assume they have dedicated 60-call budgets. Implement a shared token-bucket mechanism in an external cache such as Redis, calibrating the global rate to 50 requests per minute. This leaves an operational buffer for manual administrative queries or diagnostic requests.

2. Consolidate Read Queries with Pagination

When inspecting alias records or auditing forwarding counts, avoid querying individual items in serial requests. GET /v1/aliases supports cursor-based pagination using the next_cursor query parameter and last_key response field. Retrieving records in paginated batches minimizes round trips and leaves burst capacity available for real-time creation calls.

3. Manage Lifecycle Transitions Through the Dashboard

v1 of the Emcognito API creates and lists aliases (GET and POST /v1/aliases). Suspending, resuming and deleting an alias are one-click dashboard actions today; there is no PATCH or DELETE endpoint yet. Scripts must not attempt unlisted HTTP methods or poll state-transition routes. Keeping workers focused strictly on the supported GET and POST contracts prevents wasted quota.

Edge Cases in Automated Environments

Several subtle timing factors can cause standard retry logic to fail during production execution.

UTC Midnight Timing

When application servers operate in local timezones such as US Eastern or Pacific time, anchoring daily reset timers to local midnight causes worker queues to remain paused hours after the API has refreshed. Emcognito clears daily limits strictly at 00:00 UTC. Date calculations must parse timestamps using coordinated universal time.

Intra-Task Limit Exhaustion

A continuous queue running near 23:55 UTC might trigger the daily creation cap just prior to midnight. If the worker sets a rigid 24-hour sleep timer, the job will remain idle long after the 00:00 UTC reset opens a fresh quota. Check the current UTC date on every dispatch cycle rather than relying on an indefinite sleep duration.

Account Tier Capabilities During Trials

Engineers testing integrations often work within the 7-day free trial on paid subscriptions. While unrelated to API rate limiting, unexpected integration errors during trial setups often stem from features that activate only after billing completion.

Architecture Fit and High-Volume Provisioning

The Emcognito API provides just-in-time identity creation, minting durable forwarding addresses on demand during account signups, newsletter subscriptions, or contact form submissions. Generating distinct addresses per counterparty segments inbound traffic and isolates data disclosures.

The FTC guidance on how websites and apps collect and use information illustrates how online tracking correlates activity across entities when persistent identifiers are shared. Minting distinct aliases per service limits that cross-context linkage. Similarly, FTC phishing guidance highlights verifying sender identity; routing traffic through dedicated per-site aliases makes unexpected incoming messages an immediate signal of an address leak.

However, an API capped at 50 to 200 creations per day is not intended for mass database migrations. Projects requiring tens of thousands of addresses provisioned overnight will exceed the daily creation cap by design.

Evaluate your infrastructure requirements against operational limits:

  • Self-Hosting Requirements: Emcognito is closed source and runs only as a hosted service; if open source or self-hosting is a requirement, addy.io is the better fit.
  • Domain Options: Emcognito aliases use the shared emcognito.com domain. Custom subdomain support is planned, but custom domains are not available today.
  • Creation Scale: If your automation provisions up to 50 addresses per day, Emcognito Plus ($20/year) covers that volume. For workloads requiring up to 200 addresses per day, Emcognito Pro ($36/year, which includes three months free on the annual plan) provides the higher 200-creation daily cap.

Frequently Asked Questions

Does the API send rate-limit headers?

POST /v1/aliases returns HTTP 200 with the new alias under "alias". The burst limit is 60 requests a minute per key; its 429 carries a Retry-After header giving the seconds until the window resets. The daily alias-creation cap (50 on Plus, 200 on Pro) resets at 00:00 UTC and its 429 carries no Retry-After. Emcognito sends no X-RateLimit-* headers.

Why did my 429 response have no Retry-After header?

An HTTP 429 response without a Retry-After header indicates the account reached its daily alias-creation cap (50 per day on Plus, 200 per day on Pro). Because this threshold is checked in application logic rather than at the network rate-limiting tier, no retry duration is returned. The counter refreshes at 00:00 UTC.

How long should my client wait after a burst 429?

Inspect the integer value returned in the Retry-After header, which reports the full length of the rate-limiting window (60 seconds). Sleep for that duration plus an additional 0.5 to 2.0 seconds of randomized jitter to ensure the server-side window has closed.

Does the API support alias suspension or deletion?

v1 of the Emcognito API creates and lists aliases (GET and POST /v1/aliases). Suspending, resuming and deleting an alias are one-click dashboard actions today; there is no PATCH or DELETE endpoint yet.

What does POST /v1/aliases return on success?

The endpoint returns an HTTP 200 status code with a JSON payload wrapping an alias object. Attributes include id, address, status, and created_at (as an integer epoch timestamp). Unassigned string fields return as empty strings rather than null.

Next Step

Review the exact request schemas, field definitions, and bearer authentication specifications directly in the developer alias API documentation before deploying your ingestion pipeline.

Sources and further reading

Create aliases from your own code.

Two endpoints, Bearer auth, 50 aliases a day on Plus and 200 on Pro. No PATCH or DELETE yet.

Read the API docs →