# Transaction enrollment

> Ask a payer to send a provider’s files through Payerworks, and follow the request to the end. The one part of the API that keeps what you send.

Page: https://payerworks.com/docs/enrollment · Markdown: https://payerworks.com/docs/enrollment.md

> Payerworks writes and explains files; it sends nothing to a payer. Every file a route writes says `transmitted: false`, and is yours to send on your own connection. A test key is for invented data only, never a real patient.

A payer sends a provider’s eligibility answers, claim status answers, claims or remittances through a clearinghouse only after it is asked to: that is transaction enrollment. Create the provider once (its name, NPI and tax id), then request enrollment per payer and transaction, answer the tasks it raises, and follow it to the end.

Payerworks is registered with no payer yet, so a live request waits with Payerworks. Only the sandbox payer `PWSANDBOX` runs the whole path, and every sandbox status word starts with “Sandbox:”.

New here? Start with [The enrollment sandbox](https://payerworks.com/docs/quickstart-enrollment).

## Routes

- [POST /v1/providers](#post-v1-providers): Create a provider
- [GET /v1/providers](#get-v1-providers): List your providers
- [GET /v1/providers/{id}](#get-v1-providers-id): One provider
- [POST /v1/providers/{id}](#post-v1-providers-id): Change a provider
- [DELETE /v1/providers/{id}](#delete-v1-providers-id): Delete a provider
- [POST /v1/enrollments](#post-v1-enrollments): Request an enrollment
- [GET /v1/enrollments](#get-v1-enrollments): List your enrollments
- [GET /v1/enrollments/{id}](#get-v1-enrollments-id): One enrollment
- [POST /v1/enrollments/{id}](#post-v1-enrollments-id): Change an enrollment
- [DELETE /v1/enrollments/{id}](#delete-v1-enrollments-id): Delete an enrollment
- [POST /v1/enrollments/{id}/submit](#post-v1-enrollments-id-submit): Submit a draft
- [POST /v1/enrollments/{id}/cancel](#post-v1-enrollments-id-cancel): Cancel an enrollment
- [POST /v1/tasks/{id}](#post-v1-tasks-id): Answer a task
- [POST /v1/enrollments/{id}/documents](#post-v1-enrollments-id-documents): Upload a PDF for a task
- [POST /v1/documents/{id}/confirm](#post-v1-documents-id-confirm): Confirm an upload
- [GET /v1/documents/{id}](#get-v1-documents-id): Download a document
- [DELETE /v1/documents/{id}](#delete-v1-documents-id): Delete a document
- [GET /v1/enrollment-requirements](#get-v1-enrollment-requirements): Payers with published steps
- [GET /v1/enrollment-requirements/{payer_id}](#get-v1-enrollment-requirements-payer-id): What a payer asks
- [POST /v1/sandbox/enrollments/{id}/advance](#post-v1-sandbox-enrollments-id-advance): Advance a sandbox enrollment
- [POST /v1/enrollments/import/check](#post-v1-enrollments-import-check): Check an enrollment import
- [POST /v1/enrollments/import](#post-v1-enrollments-import): Import enrollment requests
- [GET /v1/enrollments/export](#get-v1-enrollments-export): Export your enrollments
- [GET /v1/enrollments/durations](#get-v1-enrollments-durations): How long your requests took

Each route shows its call with curl and with the two clients, then its real answer, shortened, and the fields it holds. The client calls assume one client made once, `const pw = new Payerworks()` in JavaScript or `pw = payerworks.Payerworks()` in Python, each reading PAYERWORKS_API_KEY and PAYERWORKS_BASE_URL, and `body` is the request.json shown.

### POST /v1/providers

**Create a provider.** A provider record: its name, billing NPI, tax id (an EIN, never a Social Security number) and contacts. One per NPI and tax id pair: a second is refused, naming the first. With a live key the answer also says what the NPI registry holds for the NPI: whether it is there, Type 1 or 2, and whether the provider’s name matches (its own name only, never a contact’s; a warning, never a refusal; a lookup that fails says so, and is never read as not found).

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/providers" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postProviders(body);
```

With the Python client

```python
answer = pw.post_providers(body)
```

request.json

```json
{
  "name": "Sample Family Clinic TASKS",
  "npi": "1234567893",
  "tax_id": "12-3456789",
  "tax_id_type": "ein",
  "contacts": [
    {
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "enrollment@sampleclinic.example",
      "phone": "8015550100"
    }
  ]
}
```

The answer (201)

```json
{
  "object": "provider",
  "id": "prv_01a154ad358043763d71b95c",
  "mode": "test",
  "name": "Sample Family Clinic TASKS",
  "npi": "1234567893",
  "tax_id": "123456789",
  "tax_id_type": "ein",
  "contacts": [
    {
      "organization_name": null,
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "enrollment@sampleclinic.example",
      "phone": "8015550100",
      "phone_extension": null,
      "address": null
    }
  ],
  "identifiers_locked": false,
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "provider" |  |
| `id` | string | prv_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `name` | string |  |
| `npi` | string |  |
| `tax_id` | string |  |
| `tax_id_type` | one of "ein" |  |
| `contacts` | list of Contact |  |
| `identifiers_locked` | boolean | True once a request for this provider has gone to a payer: the NPI and tax id no longer change. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `npi_registry` | object | A live key’s new provider (wave 4): what the NPI registry holds for the NPI, found, holding no active record, or not asked (with why). Never stored. |
| `warnings` | list of FieldProblem | A live key’s new provider: what the NPI registry answer warns of. Never a refusal. |

### GET /v1/providers

**List your providers.** Newest first. Page with limit (up to 100) and starting_after, and filter with npi, tax_id or q (part of the name).

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/providers" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getProviders();
```

With the Python client

```python
answer = pw.get_providers()
```

The answer (200)

```json
{
  "data": [
    {
      "object": "provider",
      "id": "prv_01a154ad358043763d71b95c",
      "mode": "test",
      "name": "Sample Family Clinic TASKS",
      "npi": "1234567893",
      "tax_id": "123456789",
      "tax_id_type": "ein",
      "contacts": [
        {
          "organization_name": null,
          "first_name": "Jane",
          "last_name": "Doe",
          "email": "enrollment@sampleclinic.example",
          "phone": "8015550100",
          "phone_extension": null,
          "address": null
        }
      ],
      "identifiers_locked": false,
      "created_at": "2026-10-19T15:00:00.000Z",
      "updated_at": "2026-10-19T15:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "list" |  |
| `data` | list of Provider | Newest first. |
| `has_more` | boolean |  |
| `next_cursor` | string or null | Pass as starting_after. |

### GET /v1/providers/{id}

**One provider.** The provider, and whether its NPI and tax id are locked because a request for it has gone to a payer.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/providers/prv_01a154ad358043763d71b95c" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getProvidersById("prv_01a154ad358043763d71b95c");
```

With the Python client

```python
answer = pw.get_providers_by_id("prv_01a154ad358043763d71b95c")
```

The answer (200)

```json
{
  "object": "provider",
  "id": "prv_01a154ad358043763d71b95c",
  "mode": "test",
  "name": "Sample Family Clinic TASKS",
  "npi": "1234567893",
  "tax_id": "123456789",
  "tax_id_type": "ein",
  "contacts": [
    {
      "organization_name": null,
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "enrollment@sampleclinic.example",
      "phone": "8015550100",
      "phone_extension": null,
      "address": null
    }
  ],
  "identifiers_locked": false,
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "provider" |  |
| `id` | string | prv_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `name` | string |  |
| `npi` | string |  |
| `tax_id` | string |  |
| `tax_id_type` | one of "ein" |  |
| `contacts` | list of Contact |  |
| `identifiers_locked` | boolean | True once a request for this provider has gone to a payer: the NPI and tax id no longer change. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `npi_registry` | object | A live key’s new provider (wave 4): what the NPI registry holds for the NPI, found, holding no active record, or not asked (with why). Never stored. |
| `warnings` | list of FieldProblem | A live key’s new provider: what the NPI registry answer warns of. Never a refusal. |

### POST /v1/providers/{id}

**Change a provider.** Only the fields you send change. The NPI and tax id can be corrected until a request for the provider has gone to a payer.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/providers/prv_01a154ad358043763d71b95c" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postProvidersById("prv_01a154ad358043763d71b95c", body);
```

With the Python client

```python
answer = pw.post_providers_by_id("prv_01a154ad358043763d71b95c", body)
```

request.json

```json
{
  "name": "Sample Family Clinic TASKS"
}
```

The answer (200)

```json
{
  "object": "provider",
  "id": "prv_01a154ad358043763d71b95c",
  "mode": "test",
  "name": "Sample Family Clinic TASKS",
  "npi": "1234567893",
  "tax_id": "123456789",
  "tax_id_type": "ein",
  "contacts": [
    {
      "organization_name": null,
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "enrollment@sampleclinic.example",
      "phone": "8015550100",
      "phone_extension": null,
      "address": null
    }
  ],
  "identifiers_locked": false,
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "provider" |  |
| `id` | string | prv_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `name` | string |  |
| `npi` | string |  |
| `tax_id` | string |  |
| `tax_id_type` | one of "ein" |  |
| `contacts` | list of Contact |  |
| `identifiers_locked` | boolean | True once a request for this provider has gone to a payer: the NPI and tax id no longer change. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `npi_registry` | object | A live key’s new provider (wave 4): what the NPI registry holds for the NPI, found, holding no active record, or not asked (with why). Never stored. |
| `warnings` | list of FieldProblem | A live key’s new provider: what the NPI registry answer warns of. Never a refusal. |

### DELETE /v1/providers/{id}

**Delete a provider.** Its drafts go with it. A provider with a request that is open or live is kept, and the refusal names those requests. Deleting again answers the same.

Request

```bash
curl -sS -X DELETE "$PAYERWORKS_BASE_URL/v1/providers/prv_01a154ad358043763d71b95c" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.deleteProvidersById("prv_01a154ad358043763d71b95c");
```

With the Python client

```python
answer = pw.delete_providers_by_id("prv_01a154ad358043763d71b95c")
```

The answer (200)

```json
{
  "deleted": true,
  "id": "prv_01a154ad358043763d71b95c"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `deleted` | the value true |  |
| `id` | string |  |

### POST /v1/enrollments

**Request an enrollment.** One request per provider, payer and transaction: eligibility, claim_status, professional_claims or remittances. Kept as a draft, or handed to Payerworks with submit: true. Payerworks is not yet registered with any payer, so a live request waits with Payerworks, the answer carries a route_not_open warning, and nothing is sent.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postEnrollments(body);
```

With the Python client

```python
answer = pw.post_enrollments(body)
```

request.json

```json
{
  "provider_id": "prv_01a154ad358043763d71b95c",
  "payer": {
    "id": "PWSANDBOX"
  },
  "transaction": "remittances",
  "primary_contact": {
    "organization_name": "Sample Family Clinic LLC",
    "email": "enrollment@sampleclinic.example",
    "phone": "8015550100",
    "address": {
      "line1": "100 Main St",
      "city": "Salt Lake City",
      "state": "UT",
      "zip": "84101"
    }
  },
  "notify_email": "dev@sampleclinic.example",
  "submit": true
}
```

The answer (201)

```json
{
  "object": "enrollment",
  "id": "enr_01a154ad35808fafb0295307",
  "mode": "test",
  "provider": {
    "id": "prv_01a154ad358043763d71b95c",
    "name": "Sample Family Clinic TASKS",
    "npi": "1234567893",
    "tax_id_last_four": "6789"
  },
  "payer": {
    "id": "PWSANDBOX",
    "name": "PAYERWORKS SANDBOX PAYER",
    "sandbox": true
  },
  "transaction": "remittances",
  "x12": "835",
  "status": "provider_action_required",
  "status_words": "Waiting on the provider: 2 steps below need the provider. Finish them in order.",
  "waiting_on": "provider",
  "reason_code": null,
  "route": {
    "open": true,
    "sandbox": true,
    "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
  },
  "primary_contact": {
    "organization_name": "Sample Family Clinic LLC",
    "first_name": null,
    "last_name": null,
    "email": "enrollment@sampleclinic.example",
    "phone": "8015550100",
    "phone_extension": null,
    "address": {
      "line1": "100 Main St",
      "line2": null,
      "city": "Salt Lake City",
      "state": "UT",
      "zip": "84101"
    }
  },
  "notify_email": "dev@sampleclinic.example",
  "requested_effective_date": null,
  "era_aggregation": null,
  "ptan": null,
  "note": "",
  "tasks": [
    {
      "id": "tsk_01a154ad35808fafb0295307_01",
      "rank": 0,
      "responsible": "provider",
      "title": "Give the sandbox payer’s packet number",
      "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
      "fields": [
        {
          "key": "packet_id",
          "label": "Packet number",
          "type": "text",
          "format": "identifier",
          "required": true,
          "description": ""
        }
      ],
      "links": [],
      "template_document_id": null,
      "values": [],
      "complete": false,
      "completed_at": null,
      "created_at": "2026-10-19T15:00:00.000Z"
    },
    {
      "id": "tsk_01a154ad35808fafb0295307_02",
      "rank": 1,
      "responsible": "provider",
      "title": "Finish the sandbox payer’s steps",
      "instructions": "Sandbox: these steps happen on the payer’s own site. Mark this task complete, with no values, once they are done.",
      "fields": [],
      "links": [],
      "template_document_id": null,
      "values": [],
      "complete": false,
      "completed_at": null,
      "created_at": "2026-10-19T15:00:00.000Z"
    }
  ],
  "documents": [],
  "notes": [],
  "rejection": null,
  "payer_reference": null,
  "history": [
    {
      "sequence": 1,
      "at": "2026-10-19T15:00:00.000Z",
      "from": null,
      "to": "payerworks_action_required",
      "by": "you",
      "reason_code": "preparing"
    },
    {
      "sequence": 3,
      "at": "2026-10-19T15:00:00.000Z",
      "from": "payerworks_action_required",
      "to": "provider_action_required",
      "by": "sandbox",
      "reason_code": null
    }
  ],
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z",
  "submitted_at": "2026-10-19T15:00:00.000Z",
  "status_changed_at": "2026-10-19T15:00:00.000Z",
  "sent_to_payer_at": null,
  "live_at": null,
  "ended_at": null,
  "cancel_requested_at": null,
  "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances",
  "warnings": []
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment" |  |
| `id` | string | enr_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `provider` | object |  |
| `payer` | object |  |
| `transaction` | one of "eligibility", "claim_status", "professional_claims", "remittances" |  |
| `x12` | string |  |
| `status` | one of "draft", "payerworks_action_required", "provider_action_required", "with_payer", "live", "rejected", "canceled", "ended" |  |
| `status_words` | string |  |
| `waiting_on` | string or null | Whose turn it is; null when nobody’s. |
| `reason_code` | string or null | Why it is Payerworks’ turn, at payerworks_action_required. |
| `route` | object |  |
| `notify_email` | string or null |  |
| `requested_effective_date` | string or null |  |
| `era_aggregation` | string or null |  |
| `ptan` | string or null |  |
| `note` | string |  |
| `tasks` | list of Task | In rank order. |
| `documents` | list of Document |  |
| `rejection` | Rejection or null |  |
| `payer_reference` | string or null | What the payer’s confirmation said. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `submitted_at` | string or null |  |
| `status_changed_at` | string or null |  |
| `sent_to_payer_at` | string or null |  |
| `live_at` | string or null |  |
| `ended_at` | string or null |  |
| `cancel_requested_at` | string or null |  |
| `requirements_url` | string | The payer’s published steps for this transaction. |
| `open_tasks` | integer | List items only: tasks not yet finished. |
| `primary_contact` | Contact or null |  |
| `notes` | list of object | From Payerworks. |
| `history` | list of object | Every status change, oldest first. |
| `history_truncated` | boolean |  |
| `warnings` | list of object | On a create or submit: route_not_open while Payerworks’ route is closed. |

### GET /v1/enrollments

**List your enrollments.** Newest first, each with its status, whose turn it is and its open tasks. Filter with status, transaction, payer_id, provider_id, npi, waiting_on and the created and updated dates. A page may hold fewer than limit, so keep paging while has_more is true.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/enrollments" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getEnrollments();
```

With the Python client

```python
answer = pw.get_enrollments()
```

The answer (200)

```json
{
  "data": [
    {
      "object": "enrollment",
      "id": "enr_01a154ad35808fafb0295307",
      "mode": "test",
      "provider": {
        "id": "prv_01a154ad358043763d71b95c",
        "name": "Sample Family Clinic TASKS",
        "npi": "1234567893",
        "tax_id_last_four": "6789"
      },
      "payer": {
        "id": "PWSANDBOX",
        "name": "PAYERWORKS SANDBOX PAYER",
        "sandbox": true
      },
      "transaction": "remittances",
      "x12": "835",
      "status": "provider_action_required",
      "status_words": "Waiting on the provider: 2 steps below need the provider. Finish them in order.",
      "waiting_on": "provider",
      "reason_code": null,
      "route": {
        "open": true,
        "sandbox": true,
        "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
      },
      "notify_email": "dev@sampleclinic.example",
      "requested_effective_date": null,
      "era_aggregation": null,
      "ptan": null,
      "note": "",
      "tasks": [
        {
          "id": "tsk_01a154ad35808fafb0295307_01",
          "rank": 0,
          "responsible": "provider",
          "title": "Give the sandbox payer’s packet number",
          "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
          "fields": [
            {
              "key": "packet_id",
              "label": "Packet number",
              "type": "text",
              "format": "identifier",
              "required": true,
              "description": ""
            }
          ],
          "links": [],
          "template_document_id": null,
          "values": [],
          "complete": false,
          "completed_at": null,
          "created_at": "2026-10-19T15:00:00.000Z"
        },
        {
          "id": "tsk_01a154ad35808fafb0295307_02",
          "rank": 1,
          "responsible": "provider",
          "title": "Finish the sandbox payer’s steps",
          "instructions": "Sandbox: these steps happen on the payer’s own site. Mark this task complete, with no values, once they are done.",
          "fields": [],
          "links": [],
          "template_document_id": null,
          "values": [],
          "complete": false,
          "completed_at": null,
          "created_at": "2026-10-19T15:00:00.000Z"
        }
      ],
      "documents": [],
      "rejection": null,
      "payer_reference": null,
      "created_at": "2026-10-19T15:00:00.000Z",
      "updated_at": "2026-10-19T15:00:00.000Z",
      "submitted_at": "2026-10-19T15:00:00.000Z",
      "status_changed_at": "2026-10-19T15:00:00.000Z",
      "sent_to_payer_at": null,
      "live_at": null,
      "ended_at": null,
      "cancel_requested_at": null,
      "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances",
      "open_tasks": 2
    },
    {
      "object": "enrollment",
      "id": "enr_01a154ad35802c85a436872c",
      "mode": "test",
      "provider": {
        "id": "prv_01a154ad35807d5d51823b6e",
        "name": "Sample Family Clinic SLOW",
        "npi": "1234567893",
        "tax_id_last_four": "6789"
      },
      "payer": {
        "id": "PWSANDBOX",
        "name": "PAYERWORKS SANDBOX PAYER",
        "sandbox": true
      },
      "transaction": "remittances",
      "x12": "835",
      "status": "with_payer",
      "status_words": "Sandbox: waiting on the sandbox payer. Nothing was sent anywhere; advance moves it on.",
      "waiting_on": "payer",
      "reason_code": null,
      "route": {
        "open": true,
        "sandbox": true,
        "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
      },
      "notify_email": "dev@sampleclinic.example",
      "requested_effective_date": null,
      "era_aggregation": null,
      "ptan": null,
      "note": "",
      "tasks": [],
      "documents": [],
      "rejection": null,
      "payer_reference": null,
      "created_at": "2026-10-19T15:00:00.000Z",
      "updated_at": "2026-10-19T15:00:00.000Z",
      "submitted_at": "2026-10-19T15:00:00.000Z",
      "status_changed_at": "2026-10-19T15:00:00.000Z",
      "sent_to_payer_at": "2026-10-19T15:00:00.000Z",
      "live_at": null,
      "ended_at": null,
      "cancel_requested_at": null,
      "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances",
      "open_tasks": 0
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "list" |  |
| `data` | list of EnrollmentSummary | Newest first. |
| `has_more` | boolean | A page may hold fewer than limit: keep paging while has_more is true. |
| `next_cursor` | string or null |  |

### GET /v1/enrollments/{id}

**One enrollment.** Its status and whose turn it is, in words; its tasks in rank order, its documents, notes from Payerworks, a rejection with its remedy, and the history of every status change.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/enrollments/enr_01a154ad35808fafb0295307" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getEnrollmentsById("enr_01a154ad35808fafb0295307");
```

With the Python client

```python
answer = pw.get_enrollments_by_id("enr_01a154ad35808fafb0295307")
```

The answer (200)

```json
{
  "object": "enrollment",
  "id": "enr_01a154ad35808fafb0295307",
  "mode": "test",
  "provider": {
    "id": "prv_01a154ad358043763d71b95c",
    "name": "Sample Family Clinic TASKS",
    "npi": "1234567893",
    "tax_id_last_four": "6789"
  },
  "payer": {
    "id": "PWSANDBOX",
    "name": "PAYERWORKS SANDBOX PAYER",
    "sandbox": true
  },
  "transaction": "remittances",
  "x12": "835",
  "status": "provider_action_required",
  "status_words": "Waiting on the provider: 1 step below needs the provider. Finish it, in rank order after any step before it.",
  "waiting_on": "provider",
  "reason_code": null,
  "route": {
    "open": true,
    "sandbox": true,
    "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
  },
  "primary_contact": {
    "organization_name": "Sample Family Clinic LLC",
    "first_name": null,
    "last_name": null,
    "email": "enrollment@sampleclinic.example",
    "phone": "8015550100",
    "phone_extension": null,
    "address": {
      "line1": "100 Main St",
      "line2": null,
      "city": "Salt Lake City",
      "state": "UT",
      "zip": "84101"
    }
  },
  "notify_email": "dev@sampleclinic.example",
  "requested_effective_date": null,
  "era_aggregation": null,
  "ptan": null,
  "note": "",
  "tasks": [
    {
      "id": "tsk_01a154ad35808fafb0295307_01",
      "rank": 0,
      "responsible": "provider",
      "title": "Give the sandbox payer’s packet number",
      "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
      "fields": [
        {
          "key": "packet_id",
          "label": "Packet number",
          "type": "text",
          "format": "identifier",
          "required": true,
          "description": ""
        }
      ],
      "links": [],
      "template_document_id": null,
      "values": [
        {
          "key": "packet_id",
          "text": "PKT-0001"
        }
      ],
      "complete": true,
      "completed_at": "2026-10-19T15:00:00.000Z",
      "created_at": "2026-10-19T15:00:00.000Z"
    },
    {
      "id": "tsk_01a154ad35808fafb0295307_02",
      "rank": 1,
      "responsible": "provider",
      "title": "Finish the sandbox payer’s steps",
      "instructions": "Sandbox: these steps happen on the payer’s own site. Mark this task complete, with no values, once they are done.",
      "fields": [],
      "links": [],
      "template_document_id": null,
      "values": [],
      "complete": false,
      "completed_at": null,
      "created_at": "2026-10-19T15:00:00.000Z"
    }
  ],
  "documents": [],
  "notes": [],
  "rejection": null,
  "payer_reference": null,
  "history": [
    {
      "sequence": 1,
      "at": "2026-10-19T15:00:00.000Z",
      "from": null,
      "to": "payerworks_action_required",
      "by": "you",
      "reason_code": "preparing"
    },
    {
      "sequence": 3,
      "at": "2026-10-19T15:00:00.000Z",
      "from": "payerworks_action_required",
      "to": "provider_action_required",
      "by": "sandbox",
      "reason_code": null
    }
  ],
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z",
  "submitted_at": "2026-10-19T15:00:00.000Z",
  "status_changed_at": "2026-10-19T15:00:00.000Z",
  "sent_to_payer_at": null,
  "live_at": null,
  "ended_at": null,
  "cancel_requested_at": null,
  "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment" |  |
| `id` | string | enr_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `provider` | object |  |
| `payer` | object |  |
| `transaction` | one of "eligibility", "claim_status", "professional_claims", "remittances" |  |
| `x12` | string |  |
| `status` | one of "draft", "payerworks_action_required", "provider_action_required", "with_payer", "live", "rejected", "canceled", "ended" |  |
| `status_words` | string |  |
| `waiting_on` | string or null | Whose turn it is; null when nobody’s. |
| `reason_code` | string or null | Why it is Payerworks’ turn, at payerworks_action_required. |
| `route` | object |  |
| `notify_email` | string or null |  |
| `requested_effective_date` | string or null |  |
| `era_aggregation` | string or null |  |
| `ptan` | string or null |  |
| `note` | string |  |
| `tasks` | list of Task | In rank order. |
| `documents` | list of Document |  |
| `rejection` | Rejection or null |  |
| `payer_reference` | string or null | What the payer’s confirmation said. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `submitted_at` | string or null |  |
| `status_changed_at` | string or null |  |
| `sent_to_payer_at` | string or null |  |
| `live_at` | string or null |  |
| `ended_at` | string or null |  |
| `cancel_requested_at` | string or null |  |
| `requirements_url` | string | The payer’s published steps for this transaction. |
| `open_tasks` | integer | List items only: tasks not yet finished. |
| `primary_contact` | Contact or null |  |
| `notes` | list of object | From Payerworks. |
| `history` | list of object | Every status change, oldest first. |
| `history_truncated` | boolean |  |
| `warnings` | list of object | On a create or submit: route_not_open while Payerworks’ route is closed. |

### POST /v1/enrollments/{id}

**Change an enrollment.** The contact, the notice email, the effective date, the remittance grouping, the PTAN or your note, until the request is sent to a payer; while it is a draft, the payer and the transaction too.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments/enr_01a154ad35808fafb0295307" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postEnrollmentsById("enr_01a154ad35808fafb0295307", body);
```

With the Python client

```python
answer = pw.post_enrollments_by_id("enr_01a154ad35808fafb0295307", body)
```

request.json

```json
{
  "note": "Our remittances go to the billing office."
}
```

The answer (200)

```json
{
  "object": "enrollment",
  "id": "enr_01a154ad35808fafb0295307",
  "mode": "test",
  "provider": {
    "id": "prv_01a154ad358043763d71b95c",
    "name": "Sample Family Clinic TASKS",
    "npi": "1234567893",
    "tax_id_last_four": "6789"
  },
  "payer": {
    "id": "PWSANDBOX",
    "name": "PAYERWORKS SANDBOX PAYER",
    "sandbox": true
  },
  "transaction": "remittances",
  "x12": "835",
  "status": "provider_action_required",
  "status_words": "Waiting on the provider: 1 step below needs the provider. Finish it, in rank order after any step before it.",
  "waiting_on": "provider",
  "reason_code": null,
  "route": {
    "open": true,
    "sandbox": true,
    "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
  },
  "primary_contact": {
    "organization_name": "Sample Family Clinic LLC",
    "first_name": null,
    "last_name": null,
    "email": "enrollment@sampleclinic.example",
    "phone": "8015550100",
    "phone_extension": null,
    "address": {
      "line1": "100 Main St",
      "line2": null,
      "city": "Salt Lake City",
      "state": "UT",
      "zip": "84101"
    }
  },
  "notify_email": "dev@sampleclinic.example",
  "requested_effective_date": null,
  "era_aggregation": null,
  "ptan": null,
  "note": "",
  "tasks": [
    {
      "id": "tsk_01a154ad35808fafb0295307_01",
      "rank": 0,
      "responsible": "provider",
      "title": "Give the sandbox payer’s packet number",
      "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
      "fields": [
        {
          "key": "packet_id",
          "label": "Packet number",
          "type": "text",
          "format": "identifier",
          "required": true,
          "description": ""
        }
      ],
      "links": [],
      "template_document_id": null,
      "values": [
        {
          "key": "packet_id",
          "text": "PKT-0001"
        }
      ],
      "complete": true,
      "completed_at": "2026-10-19T15:00:00.000Z",
      "created_at": "2026-10-19T15:00:00.000Z"
    },
    {
      "id": "tsk_01a154ad35808fafb0295307_02",
      "rank": 1,
      "responsible": "provider",
      "title": "Finish the sandbox payer’s steps",
      "instructions": "Sandbox: these steps happen on the payer’s own site. Mark this task complete, with no values, once they are done.",
      "fields": [],
      "links": [],
      "template_document_id": null,
      "values": [],
      "complete": false,
      "completed_at": null,
      "created_at": "2026-10-19T15:00:00.000Z"
    }
  ],
  "documents": [],
  "notes": [],
  "rejection": null,
  "payer_reference": null,
  "history": [
    {
      "sequence": 1,
      "at": "2026-10-19T15:00:00.000Z",
      "from": null,
      "to": "payerworks_action_required",
      "by": "you",
      "reason_code": "preparing"
    },
    {
      "sequence": 3,
      "at": "2026-10-19T15:00:00.000Z",
      "from": "payerworks_action_required",
      "to": "provider_action_required",
      "by": "sandbox",
      "reason_code": null
    }
  ],
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z",
  "submitted_at": "2026-10-19T15:00:00.000Z",
  "status_changed_at": "2026-10-19T15:00:00.000Z",
  "sent_to_payer_at": null,
  "live_at": null,
  "ended_at": null,
  "cancel_requested_at": null,
  "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment" |  |
| `id` | string | enr_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `provider` | object |  |
| `payer` | object |  |
| `transaction` | one of "eligibility", "claim_status", "professional_claims", "remittances" |  |
| `x12` | string |  |
| `status` | one of "draft", "payerworks_action_required", "provider_action_required", "with_payer", "live", "rejected", "canceled", "ended" |  |
| `status_words` | string |  |
| `waiting_on` | string or null | Whose turn it is; null when nobody’s. |
| `reason_code` | string or null | Why it is Payerworks’ turn, at payerworks_action_required. |
| `route` | object |  |
| `notify_email` | string or null |  |
| `requested_effective_date` | string or null |  |
| `era_aggregation` | string or null |  |
| `ptan` | string or null |  |
| `note` | string |  |
| `tasks` | list of Task | In rank order. |
| `documents` | list of Document |  |
| `rejection` | Rejection or null |  |
| `payer_reference` | string or null | What the payer’s confirmation said. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `submitted_at` | string or null |  |
| `status_changed_at` | string or null |  |
| `sent_to_payer_at` | string or null |  |
| `live_at` | string or null |  |
| `ended_at` | string or null |  |
| `cancel_requested_at` | string or null |  |
| `requirements_url` | string | The payer’s published steps for this transaction. |
| `open_tasks` | integer | List items only: tasks not yet finished. |
| `primary_contact` | Contact or null |  |
| `notes` | list of object | From Payerworks. |
| `history` | list of object | Every status change, oldest first. |
| `history_truncated` | boolean |  |
| `warnings` | list of object | On a create or submit: route_not_open while Payerworks’ route is closed. |

### DELETE /v1/enrollments/{id}

**Delete an enrollment.** A draft, a canceled or a rejected request. Deleting again answers the same.

Request

```bash
curl -sS -X DELETE "$PAYERWORKS_BASE_URL/v1/enrollments/enr_01a154ad35808fafb0295307" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.deleteEnrollmentsById("enr_01a154ad35808fafb0295307");
```

With the Python client

```python
answer = pw.delete_enrollments_by_id("enr_01a154ad35808fafb0295307")
```

The answer (200)

```json
{
  "deleted": true,
  "id": "enr_01a154ad35808fafb0295307"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `deleted` | the value true |  |
| `id` | string |  |

### POST /v1/enrollments/{id}/submit

**Submit a draft.** The draft is checked again and handed to Payerworks.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments/enr_01a154ad3580afd6446277eb/submit" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.postEnrollmentsByIdSubmit("enr_01a154ad3580afd6446277eb");
```

With the Python client

```python
answer = pw.post_enrollments_by_id_submit("enr_01a154ad3580afd6446277eb")
```

The answer (200)

```json
{
  "object": "enrollment",
  "id": "enr_01a154ad3580afd6446277eb",
  "mode": "test",
  "provider": {
    "id": "prv_01a154ad35802482aa01ccf0",
    "name": "Sample Family Clinic WAITS",
    "npi": "1234567893",
    "tax_id_last_four": "6789"
  },
  "payer": {
    "id": "PWSANDBOX",
    "name": "PAYERWORKS SANDBOX PAYER",
    "sandbox": true
  },
  "transaction": "remittances",
  "x12": "835",
  "status": "payerworks_action_required",
  "status_words": "Waiting on Payerworks. Payerworks is not yet registered to exchange 835 files with PAYERWORKS SANDBOX PAYER, so nothing has been sent to the payer. Your request waits here, and you can change or cancel it until it is sent.",
  "waiting_on": "payerworks",
  "reason_code": "route_not_open",
  "route": {
    "open": true,
    "sandbox": true,
    "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
  },
  "primary_contact": {
    "organization_name": "Sample Family Clinic LLC",
    "first_name": null,
    "last_name": null,
    "email": "enrollment@sampleclinic.example",
    "phone": "8015550100",
    "phone_extension": null,
    "address": {
      "line1": "100 Main St",
      "line2": null,
      "city": "Salt Lake City",
      "state": "UT",
      "zip": "84101"
    }
  },
  "notify_email": "dev@sampleclinic.example",
  "requested_effective_date": null,
  "era_aggregation": null,
  "ptan": null,
  "note": "",
  "tasks": [],
  "documents": [],
  "notes": [],
  "rejection": null,
  "payer_reference": null,
  "history": [
    {
      "sequence": 1,
      "at": "2026-10-19T15:00:00.000Z",
      "from": null,
      "to": "draft",
      "by": "you",
      "reason_code": null
    },
    {
      "sequence": 2,
      "at": "2026-10-19T15:00:00.000Z",
      "from": "draft",
      "to": "payerworks_action_required",
      "by": "you",
      "reason_code": "route_not_open"
    }
  ],
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z",
  "submitted_at": "2026-10-19T15:00:00.000Z",
  "status_changed_at": "2026-10-19T15:00:00.000Z",
  "sent_to_payer_at": null,
  "live_at": null,
  "ended_at": null,
  "cancel_requested_at": null,
  "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances",
  "warnings": []
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment" |  |
| `id` | string | enr_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `provider` | object |  |
| `payer` | object |  |
| `transaction` | one of "eligibility", "claim_status", "professional_claims", "remittances" |  |
| `x12` | string |  |
| `status` | one of "draft", "payerworks_action_required", "provider_action_required", "with_payer", "live", "rejected", "canceled", "ended" |  |
| `status_words` | string |  |
| `waiting_on` | string or null | Whose turn it is; null when nobody’s. |
| `reason_code` | string or null | Why it is Payerworks’ turn, at payerworks_action_required. |
| `route` | object |  |
| `notify_email` | string or null |  |
| `requested_effective_date` | string or null |  |
| `era_aggregation` | string or null |  |
| `ptan` | string or null |  |
| `note` | string |  |
| `tasks` | list of Task | In rank order. |
| `documents` | list of Document |  |
| `rejection` | Rejection or null |  |
| `payer_reference` | string or null | What the payer’s confirmation said. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `submitted_at` | string or null |  |
| `status_changed_at` | string or null |  |
| `sent_to_payer_at` | string or null |  |
| `live_at` | string or null |  |
| `ended_at` | string or null |  |
| `cancel_requested_at` | string or null |  |
| `requirements_url` | string | The payer’s published steps for this transaction. |
| `open_tasks` | integer | List items only: tasks not yet finished. |
| `primary_contact` | Contact or null |  |
| `notes` | list of object | From Payerworks. |
| `history` | list of object | Every status change, oldest first. |
| `history_truncated` | boolean |  |
| `warnings` | list of object | On a create or submit: route_not_open while Payerworks’ route is closed. |

### POST /v1/enrollments/{id}/cancel

**Cancel an enrollment.** In any open status. Before it is sent to a payer it is canceled at once; once it is with a payer, or live, the answer is 202 and Payerworks withdraws it.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments/enr_01a154ad35808fafb0295307/cancel" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postEnrollmentsByIdCancel("enr_01a154ad35808fafb0295307", body);
```

With the Python client

```python
answer = pw.post_enrollments_by_id_cancel("enr_01a154ad35808fafb0295307", body)
```

request.json

```json
{
  "reason": "Filed by mistake."
}
```

The answer (200)

```json
{
  "object": "enrollment",
  "id": "enr_01a154ad35808fafb0295307",
  "mode": "test",
  "provider": {
    "id": "prv_01a154ad358043763d71b95c",
    "name": "Sample Family Clinic TASKS",
    "npi": "1234567893",
    "tax_id_last_four": "6789"
  },
  "payer": {
    "id": "PWSANDBOX",
    "name": "PAYERWORKS SANDBOX PAYER",
    "sandbox": true
  },
  "transaction": "remittances",
  "x12": "835",
  "status": "canceled",
  "status_words": "Canceled. Nothing more happens to this request.",
  "waiting_on": null,
  "reason_code": null,
  "route": {
    "open": true,
    "sandbox": true,
    "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
  },
  "primary_contact": {
    "organization_name": "Sample Family Clinic LLC",
    "first_name": null,
    "last_name": null,
    "email": "enrollment@sampleclinic.example",
    "phone": "8015550100",
    "phone_extension": null,
    "address": {
      "line1": "100 Main St",
      "line2": null,
      "city": "Salt Lake City",
      "state": "UT",
      "zip": "84101"
    }
  },
  "notify_email": "dev@sampleclinic.example",
  "requested_effective_date": null,
  "era_aggregation": null,
  "ptan": null,
  "note": "",
  "tasks": [
    {
      "id": "tsk_01a154ad35808fafb0295307_01",
      "rank": 0,
      "responsible": "provider",
      "title": "Give the sandbox payer’s packet number",
      "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
      "fields": [
        {
          "key": "packet_id",
          "label": "Packet number",
          "type": "text",
          "format": "identifier",
          "required": true,
          "description": ""
        }
      ],
      "links": [],
      "template_document_id": null,
      "values": [],
      "complete": false,
      "completed_at": null,
      "created_at": "2026-10-19T15:00:00.000Z"
    },
    {
      "id": "tsk_01a154ad35808fafb0295307_02",
      "rank": 1,
      "responsible": "provider",
      "title": "Finish the sandbox payer’s steps",
      "instructions": "Sandbox: these steps happen on the payer’s own site. Mark this task complete, with no values, once they are done.",
      "fields": [],
      "links": [],
      "template_document_id": null,
      "values": [],
      "complete": false,
      "completed_at": null,
      "created_at": "2026-10-19T15:00:00.000Z"
    }
  ],
  "documents": [],
  "notes": [],
  "rejection": null,
  "payer_reference": null,
  "history": [
    {
      "sequence": 1,
      "at": "2026-10-19T15:00:00.000Z",
      "from": null,
      "to": "payerworks_action_required",
      "by": "you",
      "reason_code": "preparing"
    },
    {
      "sequence": 3,
      "at": "2026-10-19T15:00:00.000Z",
      "from": "payerworks_action_required",
      "to": "provider_action_required",
      "by": "sandbox",
      "reason_code": null
    }
  ],
  "created_at": "2026-10-19T15:00:00.000Z",
  "updated_at": "2026-10-19T15:00:00.000Z",
  "submitted_at": "2026-10-19T15:00:00.000Z",
  "status_changed_at": "2026-10-19T15:00:00.000Z",
  "sent_to_payer_at": null,
  "live_at": null,
  "ended_at": "2026-10-19T15:00:00.000Z",
  "cancel_requested_at": null,
  "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances"
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment" |  |
| `id` | string | enr_ and 24 hexadecimal characters. |
| `mode` | one of "test", "live" |  |
| `provider` | object |  |
| `payer` | object |  |
| `transaction` | one of "eligibility", "claim_status", "professional_claims", "remittances" |  |
| `x12` | string |  |
| `status` | one of "draft", "payerworks_action_required", "provider_action_required", "with_payer", "live", "rejected", "canceled", "ended" |  |
| `status_words` | string |  |
| `waiting_on` | string or null | Whose turn it is; null when nobody’s. |
| `reason_code` | string or null | Why it is Payerworks’ turn, at payerworks_action_required. |
| `route` | object |  |
| `notify_email` | string or null |  |
| `requested_effective_date` | string or null |  |
| `era_aggregation` | string or null |  |
| `ptan` | string or null |  |
| `note` | string |  |
| `tasks` | list of Task | In rank order. |
| `documents` | list of Document |  |
| `rejection` | Rejection or null |  |
| `payer_reference` | string or null | What the payer’s confirmation said. |
| `created_at` | string |  |
| `updated_at` | string |  |
| `submitted_at` | string or null |  |
| `status_changed_at` | string or null |  |
| `sent_to_payer_at` | string or null |  |
| `live_at` | string or null |  |
| `ended_at` | string or null |  |
| `cancel_requested_at` | string or null |  |
| `requirements_url` | string | The payer’s published steps for this transaction. |
| `open_tasks` | integer | List items only: tasks not yet finished. |
| `primary_contact` | Contact or null |  |
| `notes` | list of object | From Payerworks. |
| `history` | list of object | Every status change, oldest first. |
| `history_truncated` | boolean |  |
| `warnings` | list of object | On a create or submit: route_not_open while Payerworks’ route is closed. |

### POST /v1/tasks/{id}

**Answer a task.** Save a task’s values, text or an uploaded document, and finish it with complete: true, in rank order. A task held up by an earlier one is refused naming that task, its rank and who holds it, Payerworks included. complete: false reopens a task finished by mistake while nothing has gone to a payer.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/tasks/tsk_01a154ad35808fafb0295307_01" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postTasksById("tsk_01a154ad35808fafb0295307_01", body);
```

With the Python client

```python
answer = pw.post_tasks_by_id("tsk_01a154ad35808fafb0295307_01", body)
```

request.json

```json
{
  "values": [
    {
      "key": "packet_id",
      "text": "PKT-0001"
    }
  ],
  "complete": true
}
```

The answer (200)

```json
{
  "task": {
    "id": "tsk_01a154ad35808fafb0295307_01",
    "rank": 0,
    "responsible": "provider",
    "title": "Give the sandbox payer’s packet number",
    "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
    "fields": [
      {
        "key": "packet_id",
        "label": "Packet number",
        "type": "text",
        "format": "identifier",
        "required": true,
        "description": ""
      }
    ],
    "links": [],
    "template_document_id": null,
    "values": [
      {
        "key": "packet_id",
        "text": "PKT-0001"
      }
    ],
    "complete": true,
    "completed_at": "2026-10-19T15:00:00.000Z",
    "created_at": "2026-10-19T15:00:00.000Z"
  },
  "enrollment": {
    "object": "enrollment",
    "id": "enr_01a154ad35808fafb0295307",
    "mode": "test",
    "provider": {
      "id": "prv_01a154ad358043763d71b95c",
      "name": "Sample Family Clinic TASKS",
      "npi": "1234567893",
      "tax_id_last_four": "6789"
    },
    "payer": {
      "id": "PWSANDBOX",
      "name": "PAYERWORKS SANDBOX PAYER",
      "sandbox": true
    },
    "transaction": "remittances",
    "x12": "835",
    "status": "provider_action_required",
    "status_words": "Waiting on the provider: 1 step below needs the provider. Finish it, in rank order after any step before it.",
    "waiting_on": "provider",
    "reason_code": null,
    "route": {
      "open": true,
      "sandbox": true,
      "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
    },
    "primary_contact": {
      "organization_name": "Sample Family Clinic LLC",
      "first_name": null,
      "last_name": null,
      "email": "enrollment@sampleclinic.example",
      "phone": "8015550100",
      "phone_extension": null,
      "address": {
        "line1": "100 Main St",
        "line2": null,
        "city": "Salt Lake City",
        "state": "UT",
        "zip": "84101"
      }
    },
    "notify_email": "dev@sampleclinic.example",
    "requested_effective_date": null,
    "era_aggregation": null,
    "ptan": null,
    "note": "",
    "tasks": [
      {
        "id": "tsk_01a154ad35808fafb0295307_01",
        "rank": 0,
        "responsible": "provider",
        "title": "Give the sandbox payer’s packet number",
        "instructions": "Sandbox: the payer emailed a packet number when the provider finished its form. Enter it here.",
        "fields": [
          {
            "key": "packet_id",
            "label": "Packet number",
            "type": "text",
            "format": "identifier",
            "required": true,
            "description": ""
          }
        ],
        "links": [],
        "template_document_id": null,
        "values": [
          {
            "key": "packet_id",
            "text": "PKT-0001"
          }
        ],
        "complete": true,
        "completed_at": "2026-10-19T15:00:00.000Z",
        "created_at": "2026-10-19T15:00:00.000Z"
      },
      {
        "id": "tsk_01a154ad35808fafb0295307_02",
        "rank": 1,
        "responsible": "provider",
        "title": "Finish the sandbox payer’s steps",
        "instructions": "Sandbox: these steps happen on the payer’s own site. Mark this task complete, with no values, once they are done.",
        "fields": [],
        "links": [],
        "template_document_id": null,
        "values": [],
        "complete": false,
        "completed_at": null,
        "created_at": "2026-10-19T15:00:00.000Z"
      }
    ],
    "documents": [],
    "notes": [],
    "rejection": null,
    "payer_reference": null,
    "history": [
      {
        "sequence": 1,
        "at": "2026-10-19T15:00:00.000Z",
        "from": null,
        "to": "payerworks_action_required",
        "by": "you",
        "reason_code": "preparing"
      },
      {
        "sequence": 3,
        "at": "2026-10-19T15:00:00.000Z",
        "from": "payerworks_action_required",
        "to": "provider_action_required",
        "by": "sandbox",
        "reason_code": null
      }
    ],
    "created_at": "2026-10-19T15:00:00.000Z",
    "updated_at": "2026-10-19T15:00:00.000Z",
    "submitted_at": "2026-10-19T15:00:00.000Z",
    "status_changed_at": "2026-10-19T15:00:00.000Z",
    "sent_to_payer_at": null,
    "live_at": null,
    "ended_at": null,
    "cancel_requested_at": null,
    "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances"
  }
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `task` | Task |  |
| `enrollment` | Enrollment | An enrollment request: never the tax id, only its last four. |

### POST /v1/enrollments/{id}/documents

**Upload a PDF for a task.** A signed upload address for one PDF of up to 10 MB, good for 15 minutes. Post the file there, then confirm it, or finish the task with its document_id, which confirms it too.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments/enr_01a154ad358059512fd26707/documents" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postEnrollmentsByIdDocuments("enr_01a154ad358059512fd26707", body);
```

With the Python client

```python
answer = pw.post_enrollments_by_id_documents("enr_01a154ad358059512fd26707", body)
```

request.json

```json
{
  "task_id": "tsk_01a154ad358059512fd26707_01",
  "field_key": "signed_form",
  "filename": "signed-form.pdf"
}
```

The answer (201)

```json
{
  "document": {
    "id": "doc_01a154ad358059512fd26707_e8039f84",
    "task_id": "tsk_01a154ad358059512fd26707_01",
    "field_key": "signed_form",
    "filename": "signed-form.pdf",
    "status": "pending",
    "size": null,
    "content_type": "application/pdf",
    "source": "you",
    "created_at": "2026-10-19T15:00:00.000Z",
    "uploaded_at": null
  },
  "upload": {
    "url": "https://uploads.example.com/",
    "method": "POST",
    "fields": {
      "key": "pending/pwk_0123456789abcdef/enr_01a154ad358059512fd26707/doc_01a154ad358059512fd26707_e8039f84.pdf",
      "Content-Type": "application/pdf"
    },
    "expires_at": "2026-10-19T15:15:00.000Z"
  }
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `document` | Document |  |
| `upload` | object | A signed form POST: one PDF, up to 10 MB, within 15 minutes. It takes no key. |

### POST /v1/documents/{id}/confirm

**Confirm an upload.** Checks that the file arrived and is a PDF of up to 10 MB. One that is not is deleted, and the document is marked failed.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/documents/doc_01a154ad358059512fd26707_e8039f84/confirm" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.postDocumentsByIdConfirm("doc_01a154ad358059512fd26707_e8039f84");
```

With the Python client

```python
answer = pw.post_documents_by_id_confirm("doc_01a154ad358059512fd26707_e8039f84")
```

The answer (200)

```json
{
  "id": "doc_01a154ad358059512fd26707_e8039f84",
  "task_id": "tsk_01a154ad358059512fd26707_01",
  "field_key": "signed_form",
  "filename": "signed-form.pdf",
  "status": "uploaded",
  "size": 48213,
  "content_type": "application/pdf",
  "source": "you",
  "created_at": "2026-10-19T15:00:00.000Z",
  "uploaded_at": "2026-10-19T15:00:00.000Z"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `id` | string | doc_, the enrollment’s 24 hexadecimal characters, an underscore and 8 more. |
| `task_id` | string or null |  |
| `field_key` | string or null |  |
| `filename` | string |  |
| `status` | one of "pending", "uploaded", "failed" |  |
| `failure` | string | Why it failed: not_a_pdf, too_large or upload_expired. |
| `size` | integer or null | Bytes. |
| `content_type` | the value "application/pdf" |  |
| `source` | one of "you", "payerworks" | Who added it. |
| `created_at` | string |  |
| `uploaded_at` | string or null |  |

### GET /v1/documents/{id}

**Download a document.** A signed download address, good for 15 minutes, for a PDF you uploaded or a form Payerworks attached to a task.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/documents/doc_01a154ad358059512fd26707_e8039f84" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getDocumentsById("doc_01a154ad358059512fd26707_e8039f84");
```

With the Python client

```python
answer = pw.get_documents_by_id("doc_01a154ad358059512fd26707_e8039f84")
```

The answer (200)

```json
{
  "document": {
    "id": "doc_01a154ad358059512fd26707_e8039f84",
    "task_id": "tsk_01a154ad358059512fd26707_01",
    "field_key": "signed_form",
    "filename": "signed-form.pdf",
    "status": "uploaded",
    "size": 48213,
    "content_type": "application/pdf",
    "source": "you",
    "created_at": "2026-10-19T15:00:00.000Z",
    "uploaded_at": "2026-10-19T15:00:00.000Z"
  },
  "download": {
    "url": "https://downloads.example.com/signed-form.pdf",
    "expires_at": "2026-10-19T15:15:00.000Z"
  }
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `document` | Document |  |
| `download` | object | A signed GET, good for 15 minutes. |

### DELETE /v1/documents/{id}

**Delete a document.** Refused while a finished task names it: reopen the task first. Deleting again answers the same.

Request

```bash
curl -sS -X DELETE "$PAYERWORKS_BASE_URL/v1/documents/doc_01a154ad358059512fd26707_e8039f84" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.deleteDocumentsById("doc_01a154ad358059512fd26707_e8039f84");
```

With the Python client

```python
answer = pw.delete_documents_by_id("doc_01a154ad358059512fd26707_e8039f84")
```

The answer (200)

```json
{
  "deleted": true,
  "id": "doc_01a154ad358059512fd26707_e8039f84"
}
```

| Field | Type | What it is |
| --- | --- | --- |
| `deleted` | the value true |  |
| `id` | string |  |

### GET /v1/enrollment-requirements

**Payers with published steps.** Every payer Payerworks holds published enrollment steps for, the four Medicare DME MACs and CMS’s HETS, and the sandbox payer: per transaction, who files, the fields needed and each step, with its source and the day it was read.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/enrollment-requirements" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getEnrollmentRequirements();
```

With the Python client

```python
answer = pw.get_enrollment_requirements()
```

The answer (200)

```json
{
  "object": "list",
  "data": [
    {
      "payer": {
        "id": "16013",
        "name": "Medicare DME MAC Jurisdiction A",
        "sandbox": false
      },
      "transactions": [
        {
          "transaction": "eligibility",
          "x12": "270/271",
          "applies": false
        },
        {
          "transaction": "claim_status",
          "x12": "276/277",
          "applies": true
        }
      ]
    },
    {
      "payer": {
        "id": "17013",
        "name": "Medicare DME MAC Jurisdiction B",
        "sandbox": false
      },
      "transactions": [
        {
          "transaction": "eligibility",
          "x12": "270/271",
          "applies": false
        },
        {
          "transaction": "claim_status",
          "x12": "276/277",
          "applies": true
        }
      ]
    }
  ],
  "checked_on": "2026-10-19",
  "scope": "The payers Payerworks holds published enrollment steps for, and the sandbox payer. Every other payer id answers published: false with no steps; that never means nothing is required."
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "list" |  |
| `checked_on` | string |  |
| `scope` | string |  |
| `data` | list of object |  |

### GET /v1/enrollment-requirements/{payer_id}

**What a payer asks.** For any payer id, per transaction: whether Payerworks’ route is open, who files, the fields needed and each published step with its source. A payer Payerworks holds nothing for answers published: false, never not required. Add ?transaction= for one.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/enrollment-requirements/19003" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getEnrollmentRequirementsByPayerId("19003");
```

With the Python client

```python
answer = pw.get_enrollment_requirements_by_payer_id("19003")
```

The answer (200)

```json
{
  "object": "enrollment_requirements",
  "payer": {
    "id": "19003",
    "name": "Medicare DME MAC Jurisdiction D",
    "sandbox": false
  },
  "published": true,
  "checked_on": "2026-10-19",
  "transactions": [
    {
      "transaction": "eligibility",
      "x12": "270/271",
      "applies": false,
      "ask": {
        "payer_id": "CMS",
        "words": "Traditional Medicare eligibility is asked of CMS’s HETS, not a DME MAC. File eligibility with payer CMS.",
        "source": {
          "url": "https://www.cms.gov/data-research/cms-information-technology/hipaa-eligibility-transaction-system-hets/hets-electronic-data-interchange-edi-enrollment",
          "label": "CMS: HETS EDI Enrollment (page last modified 10/13/2026)",
          "checked_on": "2026-10-19"
        }
      }
    },
    {
      "transaction": "claim_status",
      "x12": "276/277",
      "applies": true,
      "route": {
        "open": false,
        "waiting_on": "payerworks",
        "words": "Payerworks is not yet a CEDI trading partner, so it cannot exchange 276/277 files with any DME MAC. A request for this waits at payerworks_action_required and nothing is sent."
      },
      "where": {
        "name": "CEDI, the front end for all four DME MACs",
        "url": "https://cedi.wellpointfederal.com/enrollment"
      },
      "who_files": "provider",
      "fields_required": [
        "ptan"
      ],
      "steps": [
        {
          "key": "npi_active_in_pecos",
          "who": "provider",
          "words": "The provider’s NPI is active in PECOS, Medicare’s enrollment system. CEDI checks it before it signs the provider up for EDI, and denies the EDI agreement when it cannot find it.",
          "source": {
            "url": "https://www.cms.gov/regulations-and-guidance/guidance/manuals/downloads/clm104c24.pdf",
            "label": "CMS Medicare Claims Processing Manual (Pub. 100-04), chapter 24, section 30.1",
            "checked_on": "2026-10-19"
          }
        },
        {
          "key": "edi_agreement",
          "who": "provider",
          "words": "Every provider that exchanges files with Medicare, directly or through a clearinghouse, signs the EDI enrollment agreement before CEDI accepts its claims or sends it any file. For the DME MACs that agreement is CEDI’s online packet.",
          "source": {
            "url": "https://www.cms.gov/regulations-and-guidance/guidance/manuals/downloads/clm104c24.pdf",
            "label": "CMS Medicare Claims Processing Manual (Pub. 100-04), chapter 24, section 30.2",
            "checked_on": "2026-10-19"
          }
        }
      ],
      "timing": {
        "words": "CEDI processes a new enrollment request within 5 business days of receipt, and a large request may take longer. A rejected packet is emailed with its reasons, and a new packet is needed.",
        "source": {
          "url": "https://cedi.wellpointfederal.com/documents/20124/298616/DME_CEDI_FAQ.pdf/5b891dee-4847-d113-e04d-ba5130fb36ae",
          "label": "CEDI Frequently Asked Questions (last revision 03/19/2026)",
          "checked_on": "2026-10-19"
        }
      }
    }
  ],
  "words": "These are the payer’s own published steps, read on 10/19/2026. Payerworks is not registered with this payer."
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment_requirements" |  |
| `payer` | object |  |
| `published` | boolean | false: Payerworks holds no published steps for this payer, which never means nothing is required. |
| `checked_on` | string |  |
| `transactions` | list of RequirementTransaction |  |
| `words` | string |  |

### POST /v1/sandbox/enrollments/{id}/advance

**Advance a sandbox enrollment.** The sandbox payer’s next move on a test request, with the events it raised. A test key only; the last word of the provider’s name picks the scenario.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/sandbox/enrollments/enr_01a154ad35802c85a436872c/advance" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.postSandboxEnrollmentsByIdAdvance("enr_01a154ad35802c85a436872c");
```

With the Python client

```python
answer = pw.post_sandbox_enrollments_by_id_advance("enr_01a154ad35802c85a436872c")
```

The answer (200)

```json
{
  "enrollment": {
    "object": "enrollment",
    "id": "enr_01a154ad35802c85a436872c",
    "mode": "test",
    "provider": {
      "id": "prv_01a154ad35807d5d51823b6e",
      "name": "Sample Family Clinic SLOW",
      "npi": "1234567893",
      "tax_id_last_four": "6789"
    },
    "payer": {
      "id": "PWSANDBOX",
      "name": "PAYERWORKS SANDBOX PAYER",
      "sandbox": true
    },
    "transaction": "remittances",
    "x12": "835",
    "status": "live",
    "status_words": "Sandbox: live with the sandbox payer. It is invented, so no files flow.",
    "waiting_on": null,
    "reason_code": null,
    "route": {
      "open": true,
      "sandbox": true,
      "words": "The sandbox payer answers every enrollment in the sandbox. Nothing is sent anywhere."
    },
    "primary_contact": {
      "organization_name": "Sample Family Clinic LLC",
      "first_name": null,
      "last_name": null,
      "email": "enrollment@sampleclinic.example",
      "phone": "8015550100",
      "phone_extension": null,
      "address": {
        "line1": "100 Main St",
        "line2": null,
        "city": "Salt Lake City",
        "state": "UT",
        "zip": "84101"
      }
    },
    "notify_email": "dev@sampleclinic.example",
    "requested_effective_date": null,
    "era_aggregation": null,
    "ptan": null,
    "note": "",
    "tasks": [],
    "documents": [],
    "notes": [],
    "rejection": null,
    "payer_reference": "PWSENR3814935860",
    "history": [
      {
        "sequence": 1,
        "at": "2026-10-19T15:00:00.000Z",
        "from": null,
        "to": "payerworks_action_required",
        "by": "you",
        "reason_code": "preparing"
      },
      {
        "sequence": 2,
        "at": "2026-10-19T15:00:00.000Z",
        "from": "payerworks_action_required",
        "to": "with_payer",
        "by": "sandbox",
        "reason_code": null
      }
    ],
    "created_at": "2026-10-19T15:00:00.000Z",
    "updated_at": "2026-10-19T15:00:00.000Z",
    "submitted_at": "2026-10-19T15:00:00.000Z",
    "status_changed_at": "2026-10-19T15:00:00.000Z",
    "sent_to_payer_at": "2026-10-19T15:00:00.000Z",
    "live_at": "2026-10-19T15:00:00.000Z",
    "ended_at": null,
    "cancel_requested_at": null,
    "requirements_url": "/v1/enrollment-requirements/PWSANDBOX?transaction=remittances"
  },
  "moved": {
    "from": "with_payer",
    "to": "live"
  },
  "events": [
    {
      "id": "evt_bd653cd8c0654191bf653ffe",
      "type": "enrollment.live"
    }
  ]
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `enrollment` | Enrollment | An enrollment request: never the tax id, only its last four. |
| `moved` | object or null |  |
| `events` | list of object |  |

### POST /v1/enrollments/import/check

**Check an enrollment import.** Send { csv } with the template’s header and up to 100 rows, one enrollment request a row. Each row is checked exactly as POST /v1/providers and POST /v1/enrollments check their bodies, each problem named by its column, and said as ready, invalid or duplicate (a request that already stands, or an earlier row asking the same). With a live key, each NPI is looked up in the NPI registry. Nothing is saved.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments/import/check" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postEnrollmentsImportCheck(body);
```

With the Python client

```python
answer = pw.post_enrollments_import_check(body)
```

request.json

```json
{
  "csv": "provider_name,npi,tax_id,tax_id_type,payer_id,payer_name,transaction,contact_organization_name,contact_first_name,contact_last_name,contact_email,contact_phone,contact_phone_extension,contact_address_line1,contact_address_line2,contact_city,contact_state,contact_zip,notify_email,requested_effective_date,era_aggregation,ptan,note,submit\r\nSample Family Clinic,1234567893,12-3456789,,PWSANDBOX,,remittances,SAMPLE FAMILY CLINIC LLC,,,enrollment@example.com,5555550100,,100 MAIN STREET,,SPRINGFIELD,IL,62701,dev@example.com,,,,,\r\nSample Family Clinic,1234567893,12-3456789,,PWSANDBOX,,eligibility,SAMPLE FAMILY CLINIC LLC,,,enrollment@example.com,5555550100,,100 MAIN STREET,,SPRINGFIELD,IL,62701,dev@example.com,,,,,true\r\nSample Family Clinic,1234567890,12-3456789,,PWSANDBOX,,remittances,SAMPLE FAMILY CLINIC LLC,,,enrollment@example.com,5555550100,,100 MAIN STREET,,SPRINGFIELD,IL,6270,dev@example.com,,,,,"
}
```

The answer (200)

```json
{
  "object": "enrollment_import_check",
  "saved": false,
  "rows": 3,
  "results": {
    "ready": 2,
    "invalid": 1,
    "duplicate": 0
  },
  "data": [
    {
      "row": 1,
      "line": 2,
      "provider": {
        "id": null,
        "exists": false
      },
      "enrollment": null,
      "problems": [],
      "warnings": [],
      "npi_registry": {
        "checked": false,
        "npi": "1234567893",
        "reason": "test_key",
        "words": "A test key's NPIs are invented, so they are not looked up in the NPI registry. A live key's are."
      },
      "result": "ready"
    },
    {
      "row": 2,
      "line": 3,
      "provider": {
        "id": null,
        "exists": false
      },
      "enrollment": null,
      "problems": [],
      "warnings": [],
      "npi_registry": {
        "checked": false,
        "npi": "1234567893",
        "reason": "test_key",
        "words": "A test key's NPIs are invented, so they are not looked up in the NPI registry. A live key's are."
      },
      "result": "ready"
    }
  ]
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment_import_check" |  |
| `saved` | the value false | Nothing was saved. |
| `rows` | integer |  |
| `results` | object | How many rows ended each way. |
| `data` | list of ImportRow |  |

### POST /v1/enrollments/import

**Import enrollment requests.** The same file, each valid row made into one request, and its provider when your key has none with that NPI and tax id. A provider you already have is used as it is, never changed. Each row answers created, invalid, duplicate, refused or not_run; rows not started in time are not_run from not_run_from_row, so send those again. A row is submitted only when its submit cell says true.

Request

```bash
curl -sS -X POST "$PAYERWORKS_BASE_URL/v1/enrollments/import" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json
```

With the JavaScript client

```js
const answer = await pw.postEnrollmentsImport(body);
```

With the Python client

```python
answer = pw.post_enrollments_import(body)
```

request.json

```json
{
  "csv": "provider_name,npi,tax_id,tax_id_type,payer_id,payer_name,transaction,contact_organization_name,contact_first_name,contact_last_name,contact_email,contact_phone,contact_phone_extension,contact_address_line1,contact_address_line2,contact_city,contact_state,contact_zip,notify_email,requested_effective_date,era_aggregation,ptan,note,submit\r\nSample Family Clinic,1234567893,12-3456789,,PWSANDBOX,,remittances,SAMPLE FAMILY CLINIC LLC,,,enrollment@example.com,5555550100,,100 MAIN STREET,,SPRINGFIELD,IL,62701,dev@example.com,,,,,\r\nSample Family Clinic,1234567893,12-3456789,,PWSANDBOX,,eligibility,SAMPLE FAMILY CLINIC LLC,,,enrollment@example.com,5555550100,,100 MAIN STREET,,SPRINGFIELD,IL,62701,dev@example.com,,,,,true\r\nSample Family Clinic,1234567890,12-3456789,,PWSANDBOX,,remittances,SAMPLE FAMILY CLINIC LLC,,,enrollment@example.com,5555550100,,100 MAIN STREET,,SPRINGFIELD,IL,6270,dev@example.com,,,,,"
}
```

The answer (200)

```json
{
  "object": "enrollment_import",
  "saved": true,
  "rows": 3,
  "results": {
    "created": 2,
    "invalid": 1,
    "duplicate": 0,
    "refused": 0,
    "not_run": 0
  },
  "data": [
    {
      "row": 1,
      "line": 2,
      "provider": {
        "id": "prv_01a15aba4882eabbf1056c4e",
        "created": true
      },
      "enrollment": {
        "id": "enr_01a15aba4882c925e2480746",
        "status": "draft",
        "waiting_on": "you"
      },
      "problems": [],
      "warnings": [],
      "npi_registry": {
        "checked": false,
        "npi": "1234567893",
        "reason": "test_key",
        "words": "A test key's NPIs are invented, so they are not looked up in the NPI registry. A live key's are."
      },
      "result": "created"
    },
    {
      "row": 2,
      "line": 3,
      "provider": {
        "id": "prv_01a15aba4882eabbf1056c4e",
        "created": false
      },
      "enrollment": {
        "id": "enr_01a15aba488250af02bb4634",
        "status": "live",
        "waiting_on": null
      },
      "problems": [],
      "warnings": [],
      "npi_registry": {
        "checked": false,
        "npi": "1234567893",
        "reason": "test_key",
        "words": "A test key's NPIs are invented, so they are not looked up in the NPI registry. A live key's are."
      },
      "result": "created"
    }
  ]
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment_import" |  |
| `saved` | boolean |  |
| `rows` | integer |  |
| `results` | object | How many rows ended each way. |
| `data` | list of ImportRow |  |
| `not_run_from_row` | integer | The first row not started in time: send it and the rows after it again. |

### GET /v1/enrollments/export

**Export your enrollments.** Every request matching the list’s filters, as CSV text in the answer, up to 5,000 rows: status, whose turn, provider, payer, transaction and the dates. No contact, note or full tax id. A cell a spreadsheet would run as a formula starts with an apostrophe. It takes no limit or starting_after.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/enrollments/export" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getEnrollmentsExport();
```

With the Python client

```python
answer = pw.get_enrollments_export()
```

The answer (200)

```json
{
  "object": "enrollment_export",
  "content_type": "text/csv",
  "filename": "payerworks-enrollments-2026-10-20.csv",
  "row_count": 1,
  "columns": [
    "id",
    "status"
  ],
  "csv": "id,status,waiting_on,reason_code,provider_id,provider_name,npi,tax_id_last_four,payer_id,payer_name,transaction,x12,notify_email,requested_effective_date,era_aggregation,ptan,open_tasks,payer_reference,created_at,updated_at,submitted_at,sta…"
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment_export" |  |
| `content_type` | the value "text/csv" |  |
| `filename` | string |  |
| `row_count` | integer |  |
| `columns` | list of one of "id", "status", "waiting_on", "reason_code", "provider_id", "provider_name", "npi", "tax_id_last_four", "payer_id", "payer_name", "transaction", "x12", "notify_email", "requested_effective_date", "era_aggregation", "ptan", "open_tasks", "payer_reference", "created_at", "updated_at", "submitted_at", "status_changed_at", "sent_to_payer_at", "live_at", "ended_at" |  |
| `csv` | string | The CSV’s text: a cell a spreadsheet would run as a formula starts with an apostrophe. |

### GET /v1/enrollments/durations

**How long your requests took.** By payer and transaction, how long your own requests spent waiting on Payerworks, on the provider and with the payer, and from submitted to live: how many finished, and once at least five did, the median and the middle half in hours. Fewer than five says not enough history. From your key’s own history only: Payerworks has no other figures.

Request

```bash
curl -sS -X GET "$PAYERWORKS_BASE_URL/v1/enrollments/durations" \
  -H "Authorization: Bearer $PAYERWORKS_API_KEY"
```

With the JavaScript client

```js
const answer = await pw.getEnrollmentsDurations();
```

With the Python client

```python
answer = pw.get_enrollments_durations()
```

The answer (200)

```json
{
  "object": "enrollment_durations",
  "basis": "This key's own requests, from their own history: no other key's requests, no figure from anywhere else and no model. A payer's time is shown only once this key has enough finished stays with it.",
  "floor": 5,
  "as_of": "2026-10-20T19:12:00.138Z",
  "statuses": [
    "payerworks_action_required",
    "provider_action_required"
  ],
  "data": [
    {
      "payer": {
        "id": "PWSANDBOX",
        "name": "PAYERWORKS SANDBOX PAYER"
      },
      "transaction": "eligibility",
      "requests": 1,
      "submitted_to_live": {
        "n": 1,
        "open": 0,
        "enough": false,
        "median_hours": null,
        "p25_hours": null,
        "p75_hours": null,
        "words": "Not enough history: 1 finished stay from submitted to live on this key, and 5 are needed before a figure is given."
      },
      "in_status": {
        "payerworks_action_required": {
          "n": 1,
          "open": 0,
          "enough": false,
          "median_hours": null,
          "p25_hours": null,
          "p75_hours": null,
          "words": "Not enough history: 1 finished stay in payerworks_action_required on this key, and 5 are needed before a figure is given."
        },
        "provider_action_required": {
          "n": 0,
          "open": 0,
          "enough": false,
          "median_hours": null,
          "p25_hours": null,
          "p75_hours": null,
          "words": "Not enough history: 0 finished stays in provider_action_required on this key, and 5 are needed before a figure is given."
        },
        "with_payer": {
          "n": 1,
          "open": 0,
          "enough": false,
          "median_hours": null,
          "p25_hours": null,
          "p75_hours": null,
          "words": "Not enough history: 1 finished stay in with_payer on this key, and 5 are needed before a figure is given."
        }
      }
    },
    {
      "payer": {
        "id": "PWSANDBOX",
        "name": "PAYERWORKS SANDBOX PAYER"
      },
      "transaction": "remittances",
      "requests": 1,
      "submitted_to_live": {
        "n": 0,
        "open": 0,
        "enough": false,
        "median_hours": null,
        "p25_hours": null,
        "p75_hours": null,
        "words": "Not enough history: 0 finished stays from submitted to live on this key, and 5 are needed before a figure is given."
      },
      "in_status": {
        "payerworks_action_required": {
          "n": 0,
          "open": 0,
          "enough": false,
          "median_hours": null,
          "p25_hours": null,
          "p75_hours": null,
          "words": "Not enough history: 0 finished stays in payerworks_action_required on this key, and 5 are needed before a figure is given."
        },
        "provider_action_required": {
          "n": 0,
          "open": 0,
          "enough": false,
          "median_hours": null,
          "p25_hours": null,
          "p75_hours": null,
          "words": "Not enough history: 0 finished stays in provider_action_required on this key, and 5 are needed before a figure is given."
        },
        "with_payer": {
          "n": 0,
          "open": 0,
          "enough": false,
          "median_hours": null,
          "p25_hours": null,
          "p75_hours": null,
          "words": "Not enough history: 0 finished stays in with_payer on this key, and 5 are needed before a figure is given."
        }
      }
    }
  ]
}
```

Shortened here: lists show their first two items and long strings are cut. The whole answer is this route’s example in [/openapi.json](https://payerworks.com/openapi.json).

| Field | Type | What it is |
| --- | --- | --- |
| `object` | the value "enrollment_durations" |  |
| `basis` | string |  |
| `floor` | the value 5 |  |
| `as_of` | string |  |
| `statuses` | list of string |  |
| `data` | list of object |  |

## Reading the answer

- A request’s `status` is one of eight, with `waiting_on` saying whose turn it is and `reason_code` why. The statuses and what moves each are listed below.
- Every change is an event (`enrollment.updated` and the rest) with a `sequence` that only increases, so a receiver can tell an old event from a new one.

## Troubleshooting

- `provider_exists` (409): This key already has a provider with that NPI and tax id; the error names it, so use that one.
- `enrollment_exists` (409): The provider already has an open request for that payer and transaction; the error names it and its status.
- `task_blocked` (409): Tasks are finished in rank order; the error names the open task before this one and who holds it.
- `upload_missing` (409): Confirm only after the PDF reached the upload address the API answered.
- `sandbox_nothing_to_advance` (409): The sandbox payer has no move to make now: the next move is yours, or the request has ended.
- `changed_meanwhile` (409): The request changed while yours ran, so nothing was saved: read it again and send again.

Every refusal these routes may answer, with its status. Any route may also answer the codes every route shares, on [Every error](https://payerworks.com/docs/errors).

| Code | Status | What it means |
| --- | --- | --- |
| `export_takes_no_paging` | 400 | An export holds every request that matches its filters, so it takes no limit or starting_after. |
| `invalid_date_filter` | 400 | A date filter is a day, YYYY-MM-DD, or an instant, YYYY-MM-DDTHH:MM:SSZ. |
| `invalid_document_id` | 400 | A document id is doc_, the enrollment’s 24 hexadecimal characters, an underscore and 8 more. |
| `invalid_enrollment_id` | 400 | An enrollment id is enr_ followed by 24 lowercase hexadecimal characters. |
| `invalid_npi_filter` | 400 | npi is the provider’s 10-digit NPI, with a valid check digit. |
| `invalid_payer_filter` | 400 | payer_id is 1 to 80 letters and digits. |
| `invalid_payer_id` | 400 | A payer id is 1 to 80 letters and digits. |
| `invalid_provider_filter` | 400 | provider_id is prv_ followed by 24 lowercase hexadecimal characters. |
| `invalid_provider_id` | 400 | A provider id is prv_ followed by 24 lowercase hexadecimal characters. |
| `invalid_starting_after` | 400 | starting_after is the next_cursor of an earlier page, or the id of an item on an earlier page. |
| `invalid_status_filter` | 400 | status is one or more of the eight enrollment statuses, separated by commas. |
| `invalid_task_id` | 400 | A task id is tsk_, the enrollment’s 24 hexadecimal characters, an underscore and two digits. |
| `invalid_tax_id_filter` | 400 | tax_id is the provider’s 9-digit EIN, with or without the hyphen after the second digit. |
| `invalid_transaction_filter` | 400 | transaction is eligibility, claim_status, professional_claims or remittances. |
| `invalid_waiting_on_filter` | 400 | waiting_on is you, provider, payerworks or payer. |
| `q_too_long` | 400 | q is at most 100 characters. |
| `document_not_found` | 404 | This key has no document with that id. |
| `enrollment_not_found` | 404 | This key has no enrollment request with that id. |
| `provider_not_found` | 404 | This key has no provider with that id. |
| `task_not_found` | 404 | This key has no task with that id. |
| `changed_meanwhile` | 409 | This request changed while yours ran, so nothing was saved. Send it again. |
| `document_in_use` | 409 | A completed task names this document. Reopen the task first (complete: false), then delete it. |
| `document_limit_reached` | 409 | An enrollment request holds at most 20 documents. Delete one you no longer need. |
| `document_not_uploaded` | 409 | This document has not been uploaded and confirmed, so there is nothing to download. |
| `enrollment_ended` | 409 | This request is canceled, rejected or ended; nothing more can change. File a new request. |
| `enrollment_exists` | 409 | This provider already has an open request for this payer and transaction; the error names it and its status. |
| `enrollment_limit_reached` | 409 | A key holds at most 5,000 enrollment requests (a test key 500). Delete drafts and ended requests you no longer need. |
| `enrollment_not_deletable` | 409 | Only a draft, canceled or rejected request can be deleted. Cancel it first. |
| `enrollment_not_draft` | 409 | Only a draft is submitted; this request already was. |
| `enrollment_sent` | 409 | This request has gone to the payer, so its fields can no longer change. Cancel it and file a new one. |
| `provider_exists` | 409 | This key already has a provider with this NPI and tax id; the error names it. |
| `provider_has_enrollments` | 409 | This provider has requests that are open or live; cancel them first. The error names them. |
| `provider_in_use` | 409 | The NPI and tax id can no longer change: a request for this provider has gone to a payer. The error names those requests. |
| `provider_limit_reached` | 409 | A key holds at most 500 providers (a test key 50). Delete one you no longer use. |
| `sandbox_nothing_to_advance` | 409 | The sandbox payer has no move to make now: the next move is yours, the request has ended, or this scenario never moves. The error says whose turn it is. |
| `task_blocked` | 409 | A task ranked before this one is still open; the error names it, its rank and who holds it. Tasks are finished in rank order. |
| `task_is_payerworks` | 409 | This task is Payerworks’ to do, not the provider’s. It is shown so you can see what Payerworks is waiting on. |
| `task_not_open` | 409 | This request is not waiting on the provider, so its tasks cannot change now. |
| `upload_missing` | 409 | Nothing has arrived at the upload address yet. Upload the PDF, then confirm again. |
| `export_too_large` | 413 | Every request matching these filters does not fit in one export. Narrow the filters (a payer, a transaction, a created range) and export each part. |
| `document_too_large` | 422 | A document is at most 10 MB. It was deleted; upload a smaller PDF. |
| `field_not_a_document` | 422 | That field of the task does not take a document. |
| `invalid_cancel` | 422 | reason is text of at most 200 characters, with no run of eight or more digits. |
| `invalid_document_request` | 422 | Send task_id, field_key and filename (ending .pdf, at most 120 characters); each problem is listed with its field. |
| `invalid_enrollment` | 422 | One or more enrollment fields would be refused; nothing was saved. Each problem is listed with its field. |
| `invalid_import` | 422 | The CSV could not be read as an enrollment import, so no row was checked or saved. Each problem is listed; the columns are in the import template. |
| `invalid_provider` | 422 | One or more provider fields would be refused; nothing was saved. Each problem is listed with its field. |
| `invalid_task_values` | 422 | One or more task values would be refused; nothing was saved. Each problem is listed with its field. |
| `not_a_pdf` | 422 | The uploaded file is not a PDF (it does not start %PDF-). It was deleted; upload the PDF again. |
| `upload_unavailable` | 503 | No upload address could be made just now; nothing was saved. Retry in a moment. |

## Code lists

### The eight statuses

| Status | Waiting on | What it means | Who moves it |
| --- | --- | --- | --- |
| `draft` | `you` | Being written. Only this key sees it. | You: submit, change or delete it. |
| `payerworks_action_required` | `payerworks` | Submitted; Payerworks’ turn. reason_code says why. | Payerworks staff on the desk, or the sandbox. |
| `provider_action_required` | `provider` | One or more provider tasks are open. | You, completing the tasks in rank order. |
| `with_payer` | `payer` | Payerworks sent the request to the payer and follows up. Never set while the route is not open. | Payerworks staff, recording the payer’s answer. |
| `live` | nobody | The payer confirmed. Files of this kind may flow. | Payerworks staff, if the payer later ends it. |
| `rejected` | `you` | The payer, or Payerworks before sending, refused it. rejection holds the words and the remedy. | None: fix it and file a new request. |
| `canceled` | nobody | Ended at your request or by Payerworks before it went live. | None. |
| `ended` | nobody | Was live; the payer ended the route. | None: a new request starts again. |

### The transactions a request names

| Transaction | X12 | In words |
| --- | --- | --- |
| `eligibility` | 270/271 | Eligibility and benefits: Payerworks writes the 270 and reads the 271. |
| `claim_status` | 276/277 | Claim status: Payerworks writes the 276 and reads the 277. |
| `professional_claims` | 837P | Professional claims: Payerworks writes and checks the 837P. |
| `remittances` | 835 | Remittances: Payerworks reads and explains the 835. |

### The enrollment sandbox’s provider name endings

| Name ends in | What it does |
| --- | --- |
| any other word | Sandbox: a provider whose name ends in any other word goes live in one call: submitting moves it to payerworks_action_required (preparing), then with_payer, then live, with an event for each move. Advance has nothing to do. |
| `WAITS` | Sandbox: a provider whose name ends in WAITS waits at payerworks_action_required (route_not_open) and stays there. That is the state every live request is in today, so build that screen first. |
| `TASKS` | Sandbox: a provider whose name ends in TASKS gets two provider tasks on submit: rank 0 asks for a packet number (an identifier), rank 1 is steps done elsewhere, closed with no values. Once both are complete it waits for review; advance moves it to with_payer, then live. |
| `SIGN` | Sandbox: a provider whose name ends in SIGN gets one task with a document field, signed_form, and an invented one-page form as its template. Download the template, upload a signed PDF, complete the task; advance moves it to with_payer, then live. |
| `BLOCKED` | Sandbox: a provider whose name ends in BLOCKED gets a Payerworks task at rank 0 and a provider task at rank 1. Completing rank 1 first answers 409 task_blocked, naming the Payerworks task. Advance completes the Payerworks task; complete yours; advance moves it to with_payer and live. |
| `REPLACE` | Sandbox: a provider whose name ends in REPLACE starts as TASKS. The first advance deletes the open rank 0 task and adds a new one in its place (enrollment.task.deleted with superseded_by, then enrollment.task.assigned). |
| `REJECT` | Sandbox: a provider whose name ends in REJECT goes with_payer on submit; advance rejects it with the payer’s words and the remedy, carried whole. |
| `ENDS` | Sandbox: a provider whose name ends in ENDS goes live on submit; advance ends the live route. |
| `SLOW` | Sandbox: a provider whose name ends in SLOW goes with_payer on submit and stays there until advance moves it to live. |

### What enrollment keeps, and for how long

Enrollment is the one part of the API that keeps what you send: the providers and enrollment requests you create (names, NPIs, tax ids, contacts and notes) and the PDFs you upload for a task, because a request lives for weeks and Payerworks people work it. They are for a practice’s business facts; never put a patient’s information in them. A test key’s providers and requests expire 30 days after their last change, and its PDFs 30 days after each was uploaded, or about a day after you delete one; a PDF uploaded but never confirmed goes after a day, whatever the key. A live key’s are kept until you delete them, and the copy of a deleted live PDF for 30 days more. Apart from that, our backups hold every PDF that was there each night, a test key’s included, for 35 days, and each Sunday’s for a year.

## Example

[enrollment.mjs](https://payerworks.com/docs/examples/enrollment.mjs) runs every step below against the API with a test key. It needs [payerworks.mjs](https://payerworks.com/sdk/payerworks.mjs) and [sample-data.mjs](https://payerworks.com/docs/examples/sample-data.mjs) beside it.

enrollment.mjs

```js
// Payerworks example: transaction enrollment with the sandbox payer. Docs: https://payerworks.com/docs/enrollment
//
// Run it with Node 18 or later, with the JavaScript client (https://payerworks.com/sdk/payerworks.mjs)
// and sample-data.mjs beside this file:
//   PAYERWORKS_API_KEY=pw_test_... PAYERWORKS_BASE_URL=<the base URL shown with your key> node enrollment.mjs
// A test key and invented data only. Payerworks sends nothing to a payer: every file it writes is yours.
import { pathToFileURL } from 'node:url';
import { Payerworks, PayerworksError } from './payerworks.mjs';
import { PROVIDER, ENROLLMENT_CONTACT, copy, refusalOf } from './sample-data.mjs';

/** @param {Payerworks} pw */
export async function run(pw) {
  // 1. The provider, once. Enrollment keeps what you send (a practice's business facts, never a patient's).
  //    The sandbox payer reads the last word of the provider's name: SLOW waits with the payer until you advance it.
  const provider = await pw.postProviders({ ...copy(PROVIDER), name: `${PROVIDER.name} SLOW` });

  // 2. Ask the sandbox payer PWSANDBOX for its remittances, and hand the request to Payerworks at once.
  const requested = await pw.postEnrollments({
    provider_id: provider.id, payer: { id: 'PWSANDBOX' }, transaction: 'remittances',
    primary_contact: copy(ENROLLMENT_CONTACT), notify_email: 'dev@sampleclinic.example', submit: true,
  });

  // 3. The sandbox payer's next move: with the payer, then live. Each move is an event too.
  const advanced = await pw.postSandboxEnrollmentsByIdAdvance(requested.id);

  // 4. The failure path: a live request has nothing left for the sandbox payer to do.
  const refused = await refusalOf(() => pw.postSandboxEnrollmentsByIdAdvance(requested.id), { PayerworksError });

  return { submitted: requested.status, moved: advanced.moved, now: advanced.enrollment.status, events: advanced.events.map((e) => e.type), refused };
}

// Run as a script: node <this file>, with PAYERWORKS_API_KEY and PAYERWORKS_BASE_URL set.
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  console.log(JSON.stringify(await run(new Payerworks()), null, 2));
}
```

What it answered, run against the API in Payerworks’ own tests (your request ids will differ)

```json
{
  "submitted": "with_payer",
  "moved": {
    "from": "with_payer",
    "to": "live"
  },
  "now": "live",
  "events": [
    "enrollment.live"
  ],
  "refused": {
    "status": 409,
    "code": "sandbox_nothing_to_advance",
    "request_id": "req_4"
  }
}
```
