# Uploading certificates

This guide covers how to upload Certificates of Insurance via the API, including file requirements, contractor association, and handling multiple uploads.

## Basic upload

Submit a COI PDF associated with a contractor:

```bash
curl https://api.1099policy.com/api/v1/files/certificates \
  -u YOUR_SECRET_KEY: \
  -F "contractor=cn_abc123" \
  -F "certificate=@/path/to/certificate.pdf"
```

Response:

```json
{
  "id": "ci_YnsHeB9PTo",
  "contractor": "cn_abc123",
  "status": "pending",
  "created": 1760509809,
  "filename": "certificate.pdf",
  "review_results": null
}
```

The certificate is queued for processing. You'll receive a [webhook](/content/docs/uploading-certificates#/index.html) when evaluation completes.

## File requirements

| Requirement | Details |
| --- | --- |
| Format | PDF only |
| Maximum size | 15 MB |
| Pages analyzed | First 2 pages only |

### Format validation

The system validates PDF files at three levels:

- File extension must be `.pdf`
- MIME type must be `application/pdf`
- File must begin with valid PDF magic bytes (`%PDF`)

Other formats (images, Word documents, scanned TIFFs) are rejected.

### Page limit

Only the first 2 pages of each PDF are sent to the AI for analysis. Ensure all critical coverage information—limits, expiration dates, certificate holder, additional insureds—appears on these pages.

Multi-page certificates

Most standard ACORD forms include all relevant information on the first page. Multi-page certificates with coverage details on page 3+ may result in missing data and failed rules. If you need to relax this requirement for your tenant, contact your account rep at support@1099policy.com.

## Contractor association

Every certificate must be associated with a contractor. The contractor record must exist before uploading:

```bash
# Create contractor first
curl https://api.1099policy.com/api/v1/contractors \
  -u YOUR_SECRET_KEY: \
  -d email="jane@example.com" \
  -d first_name="Jane" \
  -d last_name="Smith"

# Then upload their certificate
curl https://api.1099policy.com/api/v1/files/certificates \
  -u YOUR_SECRET_KEY: \
  -F "contractor=cn_abc123" \
  -F "certificate=@/path/to/certificate.pdf"
```

The contractor association determines:

- Which insurance requirement is used (based on the contractor's entity, if applicable)
- Where the certificate appears in your Dashboard
- How insured name validation works (contractor's name or company must match)

## Multiple certificates per contractor

Contractors can have multiple certificates. Each upload creates an independent record with its own evaluation results.

Common scenarios:

| Scenario | Behavior |
| --- | --- |
| Contractor uploads updated certificate | Both old and new certificates exist independently. Determine which to use based on `created` timestamp or status. |
| Certificate uploaded while another is processing | Both process independently. No locking or deduplication. |
| Different coverage types on separate certificates | Each certificate is evaluated against the full requirement. Consider whether your requirement expects all coverages on one certificate. |

## Finding the latest approved certificate

```python
import requests

response = requests.get(
    'https://api.1099policy.com/api/v1/files/certificates',
    auth=('YOUR_SECRET_KEY', ''),
    params={'contractor': 'cn_abc123'}
)
certificates = response.json()['data']

# Filter to approved certificates
approved = [c for c in certificates if c['status'] == 'approved']

# Get most recent
if approved:
    latest = max(approved, key=lambda x: x['created'])
```

## Re-uploading after errors

If a certificate ends up in `error` status, you can upload a new one. Common reasons to re-upload:

| Issue | Solution |
| --- | --- |
| Corrupted or blank PDF | Obtain a valid PDF from the contractor |
| Poor scan quality | Request a clearer scan or digital copy |
| Critical info on page 3+ | Ask contractor for a certificate with coverage details on pages 1-2 |
| Unsupported date format | Request certificate with dates in MM/DD/YYYY, MM/DD/YY, or YYYY-MM-DD format |

There's no "retry" endpoint—simply upload the corrected PDF as a new certificate:

```bash
curl https://api.1099policy.com/api/v1/files/certificates \
  -u YOUR_SECRET_KEY: \
  -F "contractor=cn_abc123" \
  -F "certificate=@/path/to/corrected-certificate.pdf"
```

The original errored certificate remains in your records for reference.

## What happens after upload

1. **Immediate response** — You receive the certificate object with `status: "pending"`
2. **Processing begins** — AI parses the PDF and extracts coverage data (typically 1-2 minutes)
3. **Evaluation runs** — Extracted data is checked against the applicable insurance requirement
4. **Webhook sent** — You receive `certificate.approved`, `certificate.flagged`, or `certificate.denied`
5. **Results available** — Fetch detailed results using the `expand` parameter

See [Working with Review Results](/content/docs/uploading-certificates#/index.html) for how to interpret the evaluation output.

## Deleting certificates

To remove a certificate:

```bash
curl -X DELETE https://api.1099policy.com/api/v1/files/certificates/ci_YnsHeB9PTo \
  -u YOUR_SECRET_KEY:
```

Soft deletes

Deletes are soft deletes. The certificate is hidden from normal queries but retained for audit purposes.

**Next:** Learn how to [work with review results](/content/docs/uploading-certificates#/index.html) to understand evaluation outcomes.
