General integration guide
This guide describes the request-flow shape Priority.vote expects from an external script. The patterns here apply regardless of whether you are syncing from Jira, Linear, a custom CSV pipeline, or anything else.
Authentication
Send every request with a Bearer token:
Authorization: Bearer pv_pat_<your-secret>
If the token is unknown, revoked, or expired you get 401 invalid_token. If the token is valid but does not have the required scope or the path is outside the token's backlog allow-list, you get 403.
Polling cadence
The API is pull-based. A typical adapter polls a backlog once every few minutes and reacts to changes. There are no webhooks.
If your adapter polls at >1 request per second per token you may hit the per-token rate limit. The API returns 429 too_many_requests with a Retry-After header in seconds. Honour that header — retrying earlier will not help.
Avoiding bandwidth waste with ETag
GET /api/v1/backlogs/{id}/initiatives returns an ETag header on every 200. Save it, and pass it back on the next request as If-None-Match:
GET /api/v1/backlogs/{id}/initiatives HTTP/1.1
Authorization: Bearer pv_pat_...
If-None-Match: "abc123…"
If nothing changed the API returns 304 Not Modified with no body. Treat that as "no work to do this tick".
Idempotency on writes
POST and PATCH accept an optional Idempotency-Key header (16–255 ASCII characters). The first successful request under a key is cached for 24 hours; identical retries replay the same response without creating duplicates. If you reuse the same key with a different body the API returns 422 idempotency_key_conflict.
Use this whenever your adapter retries after a network failure — you cannot be certain whether the original request landed.
Error matrix
| Status | Code | When | What your script should do |
|---|---|---|---|
| 400 | invalid_idempotency_key |
Idempotency-Key malformed | Regenerate the key |
| 401 | invalid_token |
Token missing, unknown, revoked, or expired | Reissue and rotate; do not retry |
| 403 | pat_scope_required / pat_scope_insufficient |
Endpoint not reachable with current scopes | Reissue with the right scopes |
| 403 | backlog_out_of_scope |
Token restricted to other backlogs | Reissue with the right backlog allow-list |
| 404 | (various) | Resource does not exist | Create it, or fail — depends on your sync logic |
| 409 | external_ref_conflict |
This external_source/external_ref already exists |
PATCH the existing initiative instead |
| 409 | limit_reached |
Per-user PAT limit | Revoke an unused token |
| 422 | idempotency_key_conflict |
Reused Idempotency-Key with a different body | Pick a fresh key for this body |
| 422 | validation_error |
Field-level validation failed | Read errors in the response, fix, retry |
| 429 | too_many_requests |
Rate-limit budget exhausted | Sleep Retry-After seconds, retry |
| 5xx | — | Server error | Exponential back-off, retry |
What not to do
- Do not poll faster than once per second per token.
- Do not store the raw token in source control. Use a secret manager.
- Do not bypass the
external_source/external_reflookup pattern — re-enumerating the backlog on every sync is wasteful and racy.