# Errors, limits and retries

Every error is an RFC 9457 problem with a code, whether to retry, and one sentence telling the assistant what to do next.

## Problem codes

Errors are returned as application/problem+json. Read fix and tell the homeowner what it says. Retry only when retryable is true, and only with the same idempotency key unless the fix says to use a new one.

| Code | Status | Retryable | Fix |
| --- | --- | --- | --- |
| invalid_request | 400 | no | Fix the fields in invalid_fields and call again with a NEW idempotency key. |
| contact_required | 400 | no | Ask the homeowner for their full name, service address, mobile phone and email - PolyJacks prices only with all four. |
| idempotency_key_required | 400 | no | Send Idempotency-Key (REST) or idempotency_key (MCP): 8-255 letters, digits, _ or -; a UUID v4 is ideal. |
| idempotency_mismatch | 409 | no | This key was used for a different request. Use a new key for a new request. |
| request_in_progress | 409 | yes | The first call with this key is still running. Retry with the same key in 2 seconds. |
| not_found | 404 | no | Check the ref (quotes start q_, bookings b_). Expired refs cannot be revived - start again with get_quote. |
| quote_expired | 410 | no | This price held until valid_until. Call get_quote again for a fresh one. |
| doors_closed | 503 | no | PolyJacks is not taking online requests right now. Give the homeowner the phone number in summary_for_user. |
| scheduling_by_phone | 409 | no | Online booking is paused for this area. PolyJacks will call the homeowner; tell them to expect the call. |
| window_unavailable | 409 | yes | That time was just taken or has passed. Call list_windows again. |
| pending_exists | 409 | no | A request is already waiting for this homeowner's OK. Ask them to check their texts and email, or wait 30 minutes. |
| day_cap | 409 | yes | That day has too many unconfirmed requests. Offer another day. |
| confirmation_channel_offline | 503 | no | PolyJacks cannot reach the homeowner to confirm right now. Give them handoff_url to book it themselves. |
| confirm_later | 409 | yes | PolyJacks texts homeowners only from 8 AM to 8 PM Central. Try after 8 AM, or give them handoff_url. |
| not_signed | 409 | no | Install days are offered only after the homeowner signs their own agreement. |
| otp_invalid | 400 | yes | The code did not match or has expired. Ask the homeowner to read it again, or call find_my_booking for a new code. |
| permission_required | 403 | no | This needs the homeowner's code (find_my_booking) or their standing permission. |
| human_needed | 409 | no | This needs a person. Give the homeowner the phone number in summary_for_user. |
| rate_limited | 429 | yes | Too many calls. Wait retry_after_s seconds. |
| lookup_cap | 429 | no | This network has used its price lookups. Give the homeowner the phone number in summary_for_user. |
| busy_retry | 503 | yes | PolyJacks is busy. Retry with the same idempotency key after Retry-After. |
| internal | 500 | yes | Something went wrong on our side. Retry once with the same key; if it repeats, give the homeowner the phone number. |

## Limits

Calls are rate-limited per network. Strict limits return 429 with Retry-After. The phone, email and address limits are soft on the homeowner web doors (they only flag us) but strict for assistants - the rows below show them as strict (agents).

| Bucket | Window | Limit | Type |
| --- | --- | --- | --- |
| ip_read | 600 s | 120 | strict |
| ip_write | 3600 s | 40 | strict |
| ipnet_write | 3600 s | 600 | strict |
| ipnet_read | 600 s | 2000 | strict |
| ip_upload | 3600 s | 40 | strict |
| ip_geo | 60 s | 60 | strict |
| ip_area | 60 s | 20 | strict |
| ip_preview | 600 s | 120 | strict |
| ip_hold | 1800 s | 2 | strict |
| ipnet_hold | 1800 s | 50 | strict |
| ip_web_hold | 3600 s | 4 | strict |
| phone_ip_quote | 86400 s | 10 | strict |
| phone_quote | 86400 s | 5 | strict (agents) |
| email_quote | 86400 s | 5 | strict (agents) |
| addr_quote | 86400 s | 5 | strict (agents) |
| phone_ip_otp | 3600 s | 5 | strict |
| all_intake | 3600 s | 60 | ceiling |
| all_web_hold | 3600 s | 20 | ceiling |
| all_self_book | 86400 s | 50 | ceiling |
| agent_quote | 3600 s | 20 | ceiling |
| agent_hold | 3600 s | 6 | ceiling |
| ip_lookup_life | 1576800000 s | 4 | strict |

## Idempotency

Every mutating call takes an idempotency key: 8-255 letters, digits, underscore or hyphen (a UUID v4 is ideal). Send it as the Idempotency-Key header (REST) or the idempotency_key argument (MCP). After a network error, retry with the SAME key and you get the same result back - nothing is done twice. A key is honoured for 24 hours.

_Last updated 2026-10-17 - PolyJacks_
