# Compress PDF

Compression keeps the existing multipart upload contract while normalizing auth, idempotency, status polling, and downloads through the public DocuShell API host.

Source: https://docs.docushell.com/compress-pdf
Category: Reference
Read time: 5 min

## Related

- [Getting started](/getting-started.md): Shared headers, queued jobs, and request IDs.
- [Overview](/index.md): See the full endpoint inventory.

## What It Does

Upload one or more PDFs, choose a compression mode, and retrieve the optimized file through the shared jobs API once the queue completes.

## Endpoint Reference

- Method: `POST`
- Path: `/v1/pdf/compress`
- Auth: Bearer token required.
- Idempotency: Supports optional `Idempotency-Key` replay protection and file-hash-aware retries.
- Content type: `multipart/form-data`

Queue a PDF compression job using the existing multipart browser-lane contract behind the public API gateway.

### Headers

| Name | Type | Required | Location | Description |
| --- | --- | --- | --- | --- |
| Authorization | Bearer <API_KEY> | Yes | header | User-owned API key created in the DocuShell dashboard. |
| Idempotency-Key | string | No | header | Recommended for safely retrying submit requests without creating duplicate jobs. |
| X-File-Name | string | No | header | Optional file name hint used for idempotency hashing and job metadata. |
| X-File-Size | integer | No | header | Optional caller-declared byte size used for sizing and idempotency hashing. |
| X-File-SHA256 | string | No | header | Optional digest used to make retries safer when the same payload is sent again. |

### Request Fields

| Name | Type | Required | Location | Description |
| --- | --- | --- | --- | --- |
| files | file[] | Yes | multipart | One or more PDF uploads using the existing browser-lane form field. |
| mode | basic \| strong \| custom | No | multipart | Compression mode. |
| dpi | integer | No | multipart | Custom output DPI for `custom` mode. Supported range is 72 to 300. |
| quality | integer | No | multipart | Custom JPEG quality for `custom` mode. Supported range is 10 to 100. |
| grayscale | boolean | No | multipart | Produce grayscale output. |
| linearize | boolean | No | multipart | Optimize PDFs for fast web viewing when supported by the engine. |

### Sample Requests

#### Upload and compress

```bash
curl -X POST "https://api.docushell.com/api/v1/pdf/compress" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: compress-demo-001" \
  -H "X-File-Name: annual-report.pdf" \
  -F "files=@./annual-report.pdf;type=application/pdf" \
  -F "mode=strong" \
  -F "linearize=true"
```

### Queued Response

#### Queued response

```json
{
  "job_id": "job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT",
  "status": "queued",
  "cost": 1000,
  "service": "compress-pdf",
  "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E",
  "links": {
    "status": "/v1/jobs/job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT",
    "download": "/v1/jobs/job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT/download"
  }
}
```

### Status Response

#### Status response

```json
{
  "job_id": "job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT",
  "status": "done",
  "service": "compress-pdf",
  "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E",
  "result": {
    "filename": "quarterly-report.pdf",
    "sizeBytes": 184322,
    "download": "/v1/jobs/job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT/download"
  },
  "completed_at": "2026-04-24T10:12:56.145Z",
  "links": {
    "status": "/v1/jobs/job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT",
    "download": "/v1/jobs/job_01JX8Y5YJ2M2D8N1AQ5F7Q3KVT/download"
  }
}
```

Completed jobs return a public download link and keep the file streaming URL behind the gateway. Downloads use application/pdf.

### Poll And Download

- The public route preserves the existing multipart request shape and returns a queued `job_id` immediately.
- Poll the shared jobs endpoint until the compression job reports `done`, then stream the compressed PDF through `/v1/jobs/:jobId/download`.

### Failure Notes

- Uploads larger than 1 GB are rejected before the job is recorded.
- Invalid PDFs and encrypted PDFs are rejected by the compression service during validation.
- `backend_unavailable` covers temporary compression service outages before the queue handoff succeeds.

### Error Examples

#### Upload too large

- Status: `400`
- Code: `invalid_request`

The public route enforces a hard 1 GB ceiling on streamed uploads.

##### 400 error

```json
{
  "error": {
    "code": "invalid_request",
    "message": "Upload exceeds maximum allowed size (1 GB).",
    "type": "invalid_request_error",
    "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E"
  }
}
```

#### Authentication failure

- Status: `401`
- Code: `invalid_api_key`

Returned when the bearer token is missing, revoked, expired, or not allowed to use the API lane.

##### 401 error

```json
{
  "error": {
    "code": "invalid_api_key",
    "message": "Invalid API key.",
    "type": "auth_error",
    "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E"
  }
}
```

#### Idempotency conflict

- Status: `409`
- Code: `idempotency_key_reused`

Returned when the same Idempotency-Key is reused with a different payload than the original request.

##### 409 error

```json
{
  "error": {
    "code": "idempotency_key_reused",
    "message": "This Idempotency-Key was already used with a different request.",
    "type": "invalid_request_error",
    "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E"
  }
}
```

#### Webhook access disabled

- Status: `403`
- Code: `webhook_access_disabled`

Returned when a Starter API key submits webhook fields. Pro, Growth, and Scale include webhooks.

##### 403 error

```json
{
  "error": {
    "code": "webhook_access_disabled",
    "message": "Webhooks are available on Pro, Growth, and Scale. Starter includes API access without webhooks.",
    "type": "billing_error",
    "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E"
  }
}
```

#### Rate limit

- Status: `429`
- Code: `rate_limit_exceeded`

Returned when the API key or caller fingerprint exceeds the configured request rate.

##### 429 error

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded.",
    "type": "rate_limit_error",
    "request_id": "req_01JX8Y62XCDNZ2BM7TBM2M9Q8E"
  }
}
```
