Testing
Use sandbox keys and prefix-based fixtures to test your ShieldSignup integration end-to-end.
ShieldSignup ships a sandbox mode driven by your API key prefix and the local-part of the email you send. Sandbox calls never deduct from your monthly quota and never call upstream signal sources, so you can run your test suite as often as you like.
Use a sandbox key
Create a key prefixed sk_test_ from
Dashboard → API Keys. With a sandbox key, the API
short-circuits to a deterministic fixture:
- It does not call the disposable-domain blocklist.
- It does not call IP intelligence sources.
- It does not record the assessment against your monthly quota.
- It still validates input (
emailis required;ipis optional). - It still returns the same response shape as a live request — fields, types, and rate-limit headers are identical.
Fixture matrix
The fixture matches on the local-part prefix of the email you send,
plus a special case for the mailinator.com domain. When a usable public
IP is included, challenge@* returns velocity_ip; without IP it returns
velocity_domain instead.
| Email pattern | Verdict | Score | Notes |
|---|---|---|---|
block@* | block | 92 | Returns one email_disposable reason. Works with or without ip. |
*@mailinator.com | block | 92 | Same fixture as block@*. |
challenge@* (with usable IP) | challenge | 45 | Returns velocity_ip. |
challenge@* (no / ignored IP) | challenge | 45 | Returns velocity_domain. |
allow@* | allow | 5 | Returns an empty reasons array. |
| anything else | allow | 5 | Returns an empty reasons array. |
The domain after @ is yours to choose for the prefix patterns —
block@example.com and block@your-team.test produce identical
responses.
curl https://api.shieldsignup.com/v1/assess \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"challenge@example.com","ip":"203.0.113.42"}'What to test
A complete integration test covers each branch of your signup flow at least once. Recommended checklist:
-
allowresponse → user is created and you persistrequest_id. -
challengeresponse → your verification flow (email or CAPTCHA) is triggered and you persistrequest_idon the pending record. -
blockresponse → user sees the generic error, no row is written. -
400 invalid_email→ your client-side validation is engaged before hitting the API (saves a round-trip). -
400 invalid_ip→ only for malformed strings (not for127.0.0.1— that returns200withip_status: ignored_loopback). - Email-only request (no
ip) →ip_provided: false, nosignals.ip. - Usable public IP →
ip_provided: true,signals.ippresent. -
401 unauthorized→ the error is caught and surfaces to alerting, not swallowed silently. -
429(eitherquota_exceededorrate_limit) → your retry/backoff logic kicks in. - Request timeout / network error → your fail-open or fail-closed policy executes correctly.
Simulating downtime
There is no built-in 503 fixture today. To test your fail-open or
fail-closed path, point the API base URL at a mock server that returns
the error you want:
const baseUrl =
process.env.SHIELDSIGNUP_BASE_URL ??
"https://api.shieldsignup.com/v1";
const res = await fetch(`${baseUrl}/assess`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SHIELDSIGNUP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email, ip }),
signal: AbortSignal.timeout(3000),
});In tests, set SHIELDSIGNUP_BASE_URL to a local mock that responds with
500, hangs for longer than the timeout, or returns malformed JSON. Then
assert your fallback path produces the right effect.
What sandbox does not mock
- Quota and rate-limit headers are still set, but they are based on the sandbox-key's own usage, not your live key's.
- The dashboard assessments log shows sandbox calls separately. Use the filter on API Key to focus on production traffic.