Polling is the default way to retrieve analysis results from the Resistant Documents API. After you create a submission and upload the file, your system repeatedly calls the relevant result endpoint(s) until processing completes.
When to use polling
Polling is recommended when you want:
- the simplest implementation (no additional infrastructure)
- predictable integration behavior
- full control over retry and timeout logic
If you want an event-driven integration, see:
- Amazon SQS event notifications (optional)
- Webhooks via Svix (optional)
What endpoints are polled
Poll the endpoint(s) that correspond to the pipeline features you use:
- Fraud:
GET /v2/submission/{submission_id}/fraud
- Quality:
GET /v2/submission/{submission_id}/quality
- Classification:
GET /v2/submission/{submission_id}/classification
- Adaptive Decision:
GET /v2/submission/{submission_id}/decision
- Report:
GET /v2/submission/{submission_id}/report
Your polling should be scoped to the endpoints you actually consume. Don’t poll endpoints you don’t need.
Recommended polling strategy
Exponential backoff (required)
Use exponential backoff to avoid unnecessary load on the API.
Recommended behavior:
- start with a short delay
- increase delay exponentially
- add jitter to prevent synchronized client bursts
- cap the delay at 45 seconds
import time, random
def poll_fraud_result(submission_id, token, max_retries=20):
base_delay = 1 # seconds
max_delay = 900 # 15 minutes hard cap
for attempt in range(max_retries):
response = requests.get(
f"https://api.documents.resistant.ai/v2/submission/{submission_id}/fraud",
headers={"Authorization": f"Bearer {token}"}
)
if response.status_code == 200:
return response.json()
elif response.status_code == 404:
# Not ready yet
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
time.sleep(delay)
else:
response.raise_for_status()
raise TimeoutError("Max polling retries exceeded")
Recommended Polling Intervals
| Document volume | Initial delay | Max delay |
|---|
| Low (<10/min) | 3–5 seconds | 30 seconds |
| Medium (10–100/min) | 2–3 seconds | 20 seconds |
| High (>100/min) | Switch to SQS or Webhooks | — |
Hard analysis timeout (15 minutes)
Stop polling after 15 minutes. Treat this as a hard upper bound for analysis completion and fail gracefully (log and surface an actionable error).
How to detect “completion”
Result endpoints return a response with a status field. Your integration should treat these as terminal states:
SUCCESS → results available
FAILED → processing failed
INVALID_INPUT → input could not be processed
SKIPPED → processing step did not run (e.g., not enabled)
For each endpoint, handle terminal states consistently and avoid infinite loops.
Handling errors and retries
429 Too Many Requests
If you receive 429, you are being throttled. Recommended behavior:
- increase delay (apply backoff)
- add jitter
- avoid parallel polling bursts across many submissions
5xx server errors
If you receive transient 5xx errors:
- retry with backoff
- log request/response metadata (submission_id, timestamp, endpoint, status code)
4xx client errors
Most 4xx errors are not retriable (except 429). Treat them as failures and fix the request.