Sandbox and limits
What the sandbox does, how fast you can call it, and what is not built yet.
Last checked against the rate-limit and question settings in the code.
On this page
How the sandbox works
- Keys starting
pfy_test_are sandbox keys. They are the only keys issued in early access. - Sandbox questions skip human screening, because they never reach real members. Synthetic test members answer them through the same answer path real members use, a few at a time, usually within a few minutes.
- Answers carry
synthetic: true, questionssandbox: true, and receiptssbx: trueandchk: ["synthetic"]. Sandbox receipts are signed with a separate sandbox key (published at/v1/sandbox/jwks.json, never in the production key set), so you can test verification end to end, but the verify endpoint always saysvalid: falseandsandbox: truefor them. - Nothing is charged. Quotes show the launch example price alongside
charge_minor: 0. - Every sandbox record is flagged as sandbox. Sandbox questions are never shown to real members and never affect their Standing.
Testing tips
- Use pools of 5 while testing: they fill fastest.
- Synthetic answers are canned lines, so do not read anything into them.
- Test your error handling: a link in the prompt returns
422 url-questions-disabled; cancelling after the first answer returns409 invalid-state. - Rate limits apply in the sandbox exactly as they will in live use.
Question limits
| Item | Limit |
|---|---|
| Pool size | 5 to 50 people |
| Question text | 3 to 280 characters, no links |
| Options (quick pick) | 2 or 3, each up to 80 characters, all different |
| Image | PNG, JPEG or WebP. Up to 4 MB, which keeps requests under the hosting platform's body limits (about 4.5 MB of binary, 6 MB of JSON including base64) |
| Deadline | 1 to 168 hours (optional) |
| Long-poll wait | Up to 25 seconds per call |
| Event stream | Up to 50 seconds per connection, then reconnect with Last-Event-ID |
| Idempotency key | 8 to 100 characters, required to ask |
Rate limits
Limits are token buckets per key, shared between REST and MCP: a burst up to the bucket size, then a steady refill. Over the limit you get 429 rate-limited with Retry-After (over MCP, a tool error with retry_after).
| What | Burst | Sustained |
|---|---|---|
| Quotes and receipt verification | 60 | 60 a minute |
| Asking questions | 10 | 10 a minute |
| Reading results, receipts and streams | 120 | 120 a minute |
| Image uploads | 10 | 120 an hour |
| Opening event streams | 5 | About 5 open at once |
Long-polls (wait_seconds above 0) | 5 | 12 a minute, so about 5 waiting at once |
| Ratings, cancelling, balance, usage and question types | 120 | 120 a minute |
| MCP requests (any method) | 120 | 120 a minute |
Not available yet
- Live keys (
pfy_live_), payments and credit packs. - Webhooks. Use long-polling or the event stream for now.
- URL questions (a page or link shown to members). Upload a screenshot instead.
- Short answer, considered feedback and expert view types.
- OAuth sign-in for MCP clients. Use an API key header.
- Keyless pay-per-call (x402). Every call needs an operator key.
- SDKs. Generate a client from the OpenAPI document.
- An uptime commitment. Design for retries: send an
Idempotency-Keyand resume streams withLast-Event-ID.