Receivers
Ephemeral email, webhook, SMS, and OAuth receivers for CI and AI agents.
Testing real-world flows in CI is hard because your test suite needs to actually receive messages from external systems: a verification email from your auth provider, a webhook callback from a payment processor, an SMS code from a phone verification service, or an OAuth redirect from a third-party login. You can't mock these interactions without losing confidence that the real flow works, but the existing options are painful: shared test inboxes create race conditions between parallel runs, local SMTP catchers can't receive real email from production providers like Auth0 or Clerk, and polling loops with retries are slow and flaky.
Receivers solve this. Each receiver is an ephemeral endpoint that gives your test run its own unique email address, webhook URL, phone number, or OAuth callback URL. You send to it, call the wait endpoint which blocks until a message arrives (no polling, no retries, no sleep loops), assert on the content, and clean up. Receivers auto-expire after a configurable TTL, so forgotten resources don't accumulate and you don't need to worry about cleanup failures in CI.
Channels
| Channel | What you get | Use case |
|---|---|---|
email | HMAC-signed email address on a managed domain | Verification emails, OTPs, password resets |
webhook | HMAC-signed HTTPS URL (accepts all HTTP methods) | Provider callbacks, payment notifications, form submissions |
sms | Real phone number from a managed pool | SMS verification codes |
oauth_callback | Stable OAuth redirect URL (no expiry) | OAuth flow testing with automatic token exchange |
Create a receiver
curl -X POST https://api.bouncehouse.cloud/api/accounts/me/receivers \
-H "Authorization: Bearer bh_your_key" \
-H "Content-Type: application/json" \
-d '{"channel": "email", "label": "signup-test", "ttl_seconds": 3600}'Returns {id, label, channel, address_or_url, expires_at, created_at} with status 201.
Parameters:
channel—email,webhook,sms, oroauth_callbacklabel— identifier for this receiver (must be unique per account; 409 if duplicate)ttl_seconds— time to live in seconds. Omit (or passnull) for a persistent receiver (the default).
Automatic content extraction
Every message that arrives at a receiver is automatically processed through an extraction pipeline before it's stored. You don't need to parse HTML or write regex to pull out verification codes and links.
What gets extracted:
- OTP codes — 4-8 digit codes that appear near keywords like "code," "verify," or "confirm," or standalone codes on their own line
- Verification links — URLs containing paths like
/verify,/confirm,/activate,/reset, or query parameters like?token=or?code= - Auth provider links — Links from known auth providers (Auth0, Clerk, Supabase, Firebase, Cognito, Neon Auth, WorkOS, Stytch) are identified by provider and classified by purpose:
verification,password_reset,magic_link,invitation, orcallback. Your tests can match on provider and purpose instead of brittle URL patterns that break when the provider changes their URLs. - OAuth parameters — Authorization codes, state parameters, access tokens, and error responses extracted from query parameters, JSON bodies, and URLs in email
- Unsubscribe links — RFC 2369 List-Unsubscribe headers, RFC 8058 one-click unsubscribe support, and unsubscribe URLs in the email body
All extraction results are available in the message's extracted field:
{
"otp_codes": ["123456"],
"verification_links": ["https://example.com/verify?token=abc"],
"provider_links": [{ "provider": "clerk", "purpose": "verification", "url": "https://..." }],
"oauth": { "code": "auth_code_here", "state": "csrf_token" },
"unsubscribe": {
"header_urls": ["https://example.com/unsub"],
"one_click": true
}
}If an individual extractor fails, the error is captured in extracted._errors without breaking the rest of the pipeline.
Wait for a message
Long-poll until a message arrives:
curl "https://api.bouncehouse.cloud/api/accounts/me/receivers/{id}/wait?timeout=30" \
-H "Authorization: Bearer bh_your_key"Returns the message immediately when it arrives, or 204 No Content if the timeout expires.
Parameters:
timeout— seconds to wait (1-120, default 30)since— ISO timestamp; only return messages after this time (useful for waiting for a second message after you've already consumed the first)
The wait endpoint uses async notification internally, with Redis pub/sub for cross-instance delivery. A message arriving on any server instance immediately wakes your waiting client, regardless of which instance it's connected to.
List messages
curl https://api.bouncehouse.cloud/api/accounts/me/receivers/{id}/messages \
-H "Authorization: Bearer bh_your_key"Returns [{id, sender, subject, extracted, created_at, latency_ms}, ...]
The latency_ms field measures the actual time between when an auth provider sent a verification email and when it arrived at the receiver. This is calculated by correlating the email's arrival time with auth provider events within a 10-minute window, giving you real delivery speed data for your email service provider.
OAuth receivers
OAuth receivers are designed for testing OAuth login flows. Unlike other receivers, they don't expire (OAuth providers need a stable redirect URL in their configuration).
If you provide client credentials when creating the receiver, Bounce House will automatically exchange the authorization code for tokens when the OAuth redirect arrives:
curl -X POST https://api.bouncehouse.cloud/api/accounts/me/receivers \
-H "Authorization: Bearer bh_your_key" \
-H "Content-Type: application/json" \
-d '{
"channel": "oauth_callback",
"label": "github-login-test",
"oauth_client_id": "your_client_id",
"oauth_client_secret": "<your-client-secret>",
"oauth_token_url": "https://github.com/login/oauth/access_token"
}'When the provider redirects to your receiver URL with an authorization code, the extraction pipeline captures the code, and the token exchange happens automatically. The resulting access token, refresh token, and expiration are stored in extracted.oauth.token_exchange. Client secrets are encrypted at rest.
SMS receivers
SMS receivers allocate a real phone number from a managed pool. Numbers have account affinity: the system prefers numbers previously used by your account to reduce carrier-side association churn. When a receiver is deleted, the number enters a cooldown period (default 15 minutes) before being released back to the pool, so late-arriving messages still route correctly.
curl -X POST https://api.bouncehouse.cloud/api/accounts/me/receivers \
-H "Authorization: Bearer bh_your_key" \
-H "Content-Type: application/json" \
-d '{"channel": "sms", "label": "phone-verify", "ttl_seconds": 3600}'Returns 503 if no numbers are available in the pool.
Webhook receivers
Webhook receivers accept all HTTP methods (GET, POST, PUT, PATCH, DELETE) at their unique URL. The full request is captured: method, headers, body, query parameters, content type, and source IP.
The inbound URL is HMAC-signed, so the URL itself is the credential. No authentication header is needed on the inbound side. The URL format is:
https://api.bouncehouse.cloud/webhooks/ingest/{receiver_id}/{signature}Receiver metadata
curl https://api.bouncehouse.cloud/api/accounts/me/receivers/{id}/metadata \
-H "Authorization: Bearer bh_your_key"Returns {id, label, channel, address_or_url, expires_at, created_at, message_count}.
Update a receiver
Rename or extend the TTL:
curl -X PATCH https://api.bouncehouse.cloud/api/accounts/me/receivers/{id} \
-H "Authorization: Bearer bh_your_key" \
-H "Content-Type: application/json" \
-d '{"ttl_seconds": 14400}'Cannot set TTL on persistent receivers (OAuth callbacks).
List receivers
curl "https://api.bouncehouse.cloud/api/accounts/me/receivers?channel=email&status=active" \
-H "Authorization: Bearer bh_your_key"Filter by channel, label (substring match), and status (active or expired).
Delete a receiver
Persistent receivers stay until you delete them. Ephemeral receivers (those created with a ttl_seconds) auto-expire when their expires_at elapses. To destroy one immediately:
curl -X DELETE https://api.bouncehouse.cloud/api/accounts/me/receivers/{id} \
-H "Authorization: Bearer bh_your_key"Returns 204. Attempting to use an expired receiver returns 410 Gone.
Domains
DMARC monitoring, DNS health auditing, and one-click DNS fixes.
Messages
Query, inspect, and manage inbound messages across all channels.
Was this page helpful?