# Resume a bulk job that ran out of credits

`POST /api/v1/email/bulk/{jobId}/resume`

- Authentication: Secret API key as a bearer token
- Billing: Free to call. The resumed run bills the rows it reaches exactly as the first one did, and a row answered in the last seven days is a free repeat.
- Group: Bulk

Runs a job that stopped when the credit balance ran out again, from the top of the list it was given, instead of asking you to upload it a second time. Rows verified in the last seven days come back as free repeats, so only the rows the stopped run never reached are charged.

The job keeps its id, its webhook and its cumulative `credits_used`, which is the real spend on the account. `processed` and the verdict counts restart at zero: the part files they were counted from are deleted when a run settles, so the resumed run rebuilds them, and the result file the stopped run left is replaced as the rows come back.

Only a run whose `stopped_reason` is `insufficient_credits` and whose `status` has settled can be resumed; anything else answers `409 JOB_NOT_RESUMABLE`, and so does a second resume of a run that is already going again — claiming the run is one conditional write, so two calls can never queue it twice. A run whose list has passed out of the retention window answers `409 JOB_INPUT_EXPIRED`. An empty balance answers `402 INSUFFICIENT_CREDITS` rather than queueing a run that would stop again on the first row it never reached.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `jobId` | path | integer | yes |  |

## Example request

```bash
curl -X POST https://spaw.co/api/v1/email/bulk/{jobId}/resume \
  -H "Authorization: Bearer sk_live_…"
```

## Responses

### 202 — The list is queued again.

```json
{
    "success": true,
    "data": {
        "job": {
            "id": 512,
            "status": "queued",
            "total": 2000,
            "duplicate_count": 12,
            "processed": 0,
            "deliverable": 0,
            "risky": 0,
            "undeliverable": 0,
            "credits_used": 750,
            "stopped_reason": null,
            "cancel_requested": false,
            "webhook_status": null,
            "created_at": "2026-09-03T10:12:44+00:00",
            "finished_at": null
        }
    }
}
```

### 401 — The key is missing, malformed, or revoked.

```json
{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 402 — The balance is empty. The lookup did not run.

```json
{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your credit balance is empty.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 404 — No such record on this account.

```json
{
    "success": false,
    "error": {
        "code": "NOT_FOUND",
        "message": "No record with that id on this account.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 409 — The run is not in a state a resume can recover (`JOB_NOT_RESUMABLE`), or its list is no longer stored (`JOB_INPUT_EXPIRED`).

```json
{
    "success": false,
    "error": {
        "code": "JOB_NOT_RESUMABLE",
        "message": "Only a run that stopped because the credit balance ran out can be resumed, and only once it has finished settling.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

### 429 — Over 5 requests per second for the key. Retry after the limit resets.

```json
{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}
```

## Error codes

- `UNAUTHENTICATED` — https://spaw.co/docs/errors/UNAUTHENTICATED
- `NOT_FOUND` — https://spaw.co/docs/errors/NOT_FOUND
- `JOB_NOT_RESUMABLE` — https://spaw.co/docs/errors/JOB_NOT_RESUMABLE
- `JOB_INPUT_EXPIRED` — https://spaw.co/docs/errors/JOB_INPUT_EXPIRED
- `INSUFFICIENT_CREDITS` — https://spaw.co/docs/errors/INSUFFICIENT_CREDITS
- `RATE_LIMITED` — https://spaw.co/docs/errors/RATE_LIMITED

---

Canonical page: https://spaw.co/docs/api/resume-bulk-job · OpenAPI document: https://spaw.co/openapi.json · All endpoints: https://spaw.co/docs/api
