---
title: "Poll an async job"
method: GET
path: "/api/v1/jobs/{id}"
tags: ["Jobs"]
---

# Poll an async job

`GET /api/v1/jobs/{id}`

## Request

- Base URL: `https://api.agendaforge.app`
- URL: `https://api.agendaforge.app/api/v1/jobs/{id}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`
  - HTTP bearer
  - API key in header `X-API-Key`

Returns the current status and result counters of a job created by POST /api/v1/imports/contacts or POST /api/v1/imports/tickets. A contacts_import job needs a key with public_api; a tickets_import job needs a key with tickets:import. Jobs are retained for 7 days; unknown, expired, and cross-organization ids all answer 404. Poll with backoff (a 1,000-item import typically completes within a minute).

## Path parameters

- `id` string, required

## Response `200`

The job with live progress counters. The shape depends on the job type.

- union
  - Job
    - `jobId` string, required
    - `type` 'contacts_import', required
    - `status` 'pending' | 'processing' | 'completed' | 'failed', required: Terminal states are completed and failed; keep polling until one is reached.
    - `createdAt` string, required: ISO-8601 UTC timestamp.
    - `completedAt` string, nullable, required: ISO-8601 UTC timestamp; null until the job reaches a terminal state.
    - `result` object, required
      - `total` integer, required
      - `processed` integer, required: Items handled so far; equals total when done.
      - `created` integer, required
      - `failed` integer, required
      - `errors` object[], required: Per-item failures (first 50), each with the failing input index.
        - `index` integer, required
        - `code` string, required
        - `message` string, required
  - TicketsImportJob: Returned by POST /api/v1/imports/tickets and by GET /api/v1/jobs/{id} for a tickets_import job.
    - `jobId` string, required: Opaque job id.
    - `type` 'tickets_import', required
    - `status` 'pending' | 'processing' | 'completed' | 'failed', required: completed in a 200 response; pending in a 202 response. Terminal states are completed and failed; keep polling until one is reached.
    - `total` integer, required: Tickets in the request.
    - `statusUrl` string, uri, required: Poll this URL (GET, a key with tickets:import) for progress.
    - `result` object, required
      - `total` integer, required
      - `processed` integer, required: Rows handled so far, failed rows included; equals total when done.
      - `created` integer, required: New tickets.
      - `updated` integer, required: Existing tickets that changed.
      - `unchanged` integer, required: Existing tickets with nothing to change.
      - `cancelled` integer, required: Tickets cancelled or refunded.
      - `restored` integer, required: Cancelled or refunded tickets made valid again.
      - `failed` integer, required: Rows not applied.
      - `errors` object[], required: Row failures (first 50). code is one of missing_reference, reference_too_long, reference_mangled, reference_reserved, duplicate_reference, missing_name, invalid_email, missing_ticket_type, unknown_status, scan_key_reserved, scan_key_length, scan_key_taken, invalid_date, field_too_long, missing_fields, checked_in, event_full, type_catalogue_full. A job that stops early reports one CONFLICT entry and status failed.
        - `index` integer, required: Zero-based position in the tickets array.
        - `reference` string, nullable, required: The row's reference, or null when it is withheld.
        - `code` string, required
        - `message` string, required

## Other responses

- `400`: A required field is missing or invalid, an unknown event was supplied, or a referenced record is not owned by the key's organization.
- `401`: The API key is missing, malformed, invalid, expired, or revoked.
- `403`: The API key is valid but does not include the public_api scope. Create a key with the public_api scope in Settings > API Tokens.
- `404`: No such endpoint under /api/v1. The message lists the valid endpoints.
- `429`: The fixed window for this API key (120 requests per minute) or IP (30 per minute, unauthenticated) is exhausted. Wait Retry-After seconds and retry.
- `500`: An unexpected server failure. The body still follows the JSON error contract; retry with exponential backoff.
- `default`: Any other failure, including 404 NOT_FOUND for an unknown path and transient 5xx errors. Always the same JSON error contract.

---

[API](https://skmtc.dev/agendaforge/apis/agendaforge-public-rest-api.md) · [All operations](https://skmtc.dev/agendaforge/apis/agendaforge-public-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/agendaforge/apis/agendaforge-public-rest-api/revisions/b8956ce1e5f3?raw)
