Why Pi uses async
Operations like brand extraction, image generation, and campaign rendering are compute-heavy and can take seconds to minutes. Rather than holding a connection open, Pi returns immediately with202 Accepted and a job_id. Your code then polls for the result — or uses long-polling to let the server wait on your behalf.
This pattern lets you:
- Run many jobs in parallel without blocking threads
- Integrate into queues, serverless functions, and automation platforms
- Retry failed jobs without re-triggering the original POST
Job lifecycle
Every job moves through these states in order:| State | Meaning |
|---|---|
queued | Job accepted and waiting for a worker |
processing | Worker is actively executing the job |
completed | Job finished successfully; result is available in job_result |
failed | Job encountered an unrecoverable error; details are in error_log |
Polling: GET /api/v1/jobs/:id
Retrieve a job’s current state at any time:
Query parameters
When
true, the server holds the connection open and returns only when the job reaches a terminal state (completed or failed). Use this instead of a manual polling loop.Maximum seconds to wait when
wait_for_completion=true. If the job is still running when the timeout expires, the server returns the current (non-terminal) state so you can re-poll.Pass
expand=brand to include the resolved brand object inline in data.expanded.brand when the job result references a brand in your organization. Reduces the need for a follow-up GET.Long-polling
Long-polling is the recommended pattern for server-side integrations. Passwait_for_completion=true and a generous timeout_seconds, then re-poll if the response comes back without a terminal status:
Full example: extract and poll
Error handling
When a job reachesfailed, inspect error_log in the response for a description of what went wrong:
failed job by polling — create a new job.
Shopify app backends should prefer
wait_for_completion=true on server-side workers, then persist brand_id in your shop config. ManyChat or Zapier-style connectors should poll with short timeouts and emit brand_id as the stable downstream key.