# Get bulk import job status and results

`GET /v1/contacts/bulk/{job_id}`

- Authentication: required (Bearer token)
- Required scope: `api.contacts.manage`

Returns the status and per-contact outcomes of a bulk import job
created by `POST /v1/contacts/bulk`.  Poll until `status` is
`completed` or `failed`.

Per-contact outcomes are keyset-paginated by row index via the
`cursor` query param.  Use the `next_cursor` from `results` to fetch
the next page; when `next_cursor` is `null` there are no more items.
Items are available from the time the job enters `running` status.

## Path parameters

- `job_id` (string<uuid>, required) — Job ID returned by `POST /v1/contacts/bulk`.

## Query parameters

- `cursor` (string, optional) — Opaque cursor returned from the previous page.

## Example request

```bash
curl 'https://api.sendops.dev/v1/contacts/bulk/00000000-0000-0000-0000-000000000000' \
  -H "Authorization: Bearer $SENDOPS_API_KEY"
```

## Responses

### 200 — Job status and per-contact result page

Content type: `application/json`

```json
{
  "job_id": "00000000-0000-0000-0000-000000000000",
  "status": "string",
  "total": 0,
  "processed": 0,
  "succeeded": 0,
  "failed": 0,
  "results": {
    "data": [
      {
        "index": 0,
        "email": "user@example.com",
        "outcome": "created",
        "reason": "string"
      }
    ],
    "next_cursor": "string"
  }
}
```

### 401 — Missing, malformed, or unknown API key

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 403 — Key lacks the required scope or plan limit violated

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 404 — Resource not found

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 429 — Per-org rate limit exceeded

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```

### 500 — Unexpected server-side failure. The `code` is `internal_error`. The
`request_id` field can be quoted to SendOps support to investigate.

Content type: `application/problem+json`

```json
{
  "type": "https://example.com",
  "title": "string",
  "status": 0,
  "detail": "string",
  "code": "invalid_key",
  "request_id": "string",
  "retry_after": 0,
  "retention_days": 0,
  "scope": "string",
  "resource": "string",
  "errors": [
    {
      "field": "string",
      "reason": "string"
    }
  ]
}
```
