# Enter claims and adjudicate them

This playbook is for claims and integration teams that receive claims outside VBASoftware and want to key them in through VBAPI. You create a claim batch, add a claim and its service lines, read it back, and then adjudicate it right away, process it into the Claim table, or queue many claims for an overnight run.

|  |  |
|  --- | --- |
| **Who this is for** | Claims operations and integration developers |
| **Time to run** | About 20 minutes, plus the time a queue takes to run |
| **Writes data?** | Yes. Try it in a non-production database first if you have one. "Try it" calls in the API reference are real production calls. |
| **Operations used** | 15, linked in each step |


This changes production data
VBAPI clients connect to production, so the write calls on this page create or change real records in the database you name in `vbasoftware-database`. Try the steps in a non-production database first if VBA has given you one, use clearly fake values while you test, and keep the "Check it worked" calls, which only read data. "Try it" in the API reference also calls production.

## Before you start

- You have completed the [quick start](/developer-portal/get-started/quick-start) and your environment variables are set.
- A test subscriber and member, their group and division, and a servicing provider already exist in the database. The sample uses the fake IDs `DOCS-0001`, `DOCS-GRP1`, `DOCS-DIV1`, and `DOCS-PRV1`; replace them with your own test records in `claim.json` and at the top of each sample.
- Your API user has rights to claim batches, claim queues, and claim adjudication.
- You know the difference between a claim batch and a finalized claim. See the [data model](/developer-portal/concepts/data-model).


## How it fits together

A claim batch holds one or more claims. Each claim in a batch is identified by `batch_Number` plus `batch_Claim`, and each service line on a claim by `claim_Seq` plus `adjustment_Seq`. Claims stay in the batch tables until they are processed; only then do they get a `claim_Number` in the Claim table.

![Claim batches contain claims, and claims contain service lines](/assets/claim-entities.a0702bd155c6d28c25f7a973d48c79a4c0f2359b617716990f989bb59e2ddcde.afe294b5.png)

```mermaid
sequenceDiagram
  participant App as Your system
  participant API as VBAPI
  App->>API: POST /claim-batches
  API-->>App: batch_Number
  App->>API: POST /claim-batches/{batchNumber}/claims
  API-->>App: batch_Claim
  App->>API: POST .../claims/{batchClaim}/details
  App->>API: GET .../claims/{batchClaim}/full-claimbatch
  alt One claim, now
    App->>API: POST .../adjudicate or .../process
    API-->>App: 200 (or 202 if processing stopped)
  else Many claims, overnight
    App->>API: POST /claim-queues, then POST /claim-queues/{claimQueueKey}/details
    App->>API: POST /claim-queues/{claimQueueKey}/adjudicate
    API-->>App: 202
    App->>API: GET /claim-queues/{claimQueue_Key} until COMPLETE
  end
```

## Adjudicate or process?

Adjudication runs the claim through benefits, pricing, and claim rules and saves the results on the claim, but leaves it in the claim batch so an examiner can review it. Processing adjudicates the claim and, if no business rule stops it, moves it out of the claim batch into the Claim table. This summary comes from the VBAPI source (`FAClaim/Controllers/AdjudicationController.cs` and `FAClaim/Services/AdjudicationService.cs`):

| Operation | Waits for the result? | Success status | Where the claim ends up |
|  --- | --- | --- | --- |
| [`POST /claim-batches/{batchNumber}/claims/{batchClaim}/adjudicate`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/adjudicateclaim) | Yes | `200` with the adjudicated claim and lines | Still in the claim batch |
| [`POST /claim-batches/{batchNumber}/claims/{batchClaim}/adjudicate-no-response`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/adjudicateclaimnoresponse) | No body returned | `202` with a short message | Still in the claim batch |
| [`POST /claim-batches/{batchNumber}/claims/{batchClaim}/process`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/processclaim) | Yes | `200` if moved, `202` if a rule (for example a pend) stopped it | Claim table on `200`; claim batch on `202` |
| [`POST /claim-queues/{claimQueueKey}/adjudicate`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/adjudicateclaimqueue) | No, runs in the background | `202` | Still in the claim batch |
| [`POST /claim-queues/{claimQueueKey}/process`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/processclaimqueue) | No, runs in the background | `202` | Claim table for claims that pass |


Use adjudicate when an examiner should review results before payment, or to preview what a claim would pay. Use process when the claim should be finalized automatically if it passes. Both single-claim operations take an optional `requestingUser` query parameter that is written to the logs; it defaults to the API user.

## Steps

The samples run steps 1 to 4 and then one path, chosen with the `DOCS_CLAIM_RUN` environment variable: `adjudicate` (the default, step 5), `process` (step 6), or `queue` (steps 7 to 11).

### 1. Create a claim batch

[`POST /claim-batches`](/openapi/vbasoftware/vbasoftware.api/claim-batches/createclaimbatches)

A claim batch groups the claims you key in together, for example one batch per file or per day. `ClaimBatches` requires `batch_Number`, `process_By_Disability_Date`, and `use_Default_Date`. Send `batch_Number` as `0` and VBAPI assigns the next free number (`ClaimBatchesRepository.Create` in the API source).

C#
```csharp
        var batch = await api.PostAsync("/claim-batches", new
        {
            batch_Number = 0, // 0 asks VBAPI to assign the next batch number
            process_By_Disability_Date = false,
            use_Default_Date = false,
            description = "DOCS claims playbook",
        });
        var batchNumber = batch.Data!["batch_Number"]!.GetValue<int>();
        Console.WriteLine($"Created claim batch {batchNumber}");
```

Python
```python
    batch = api.post("/claim-batches", {
        "batch_Number": 0,  # 0 asks VBAPI to assign the next batch number
        "process_By_Disability_Date": False,
        "use_Default_Date": False,
        "description": "DOCS claims playbook",
    }).data
    batch_number = batch["batch_Number"]
    print("Created claim batch", batch_number)
```

TypeScript
```typescript
  const batch = (
    await api.post("/claim-batches", {
      batch_Number: 0, // 0 asks VBAPI to assign the next batch number
      process_By_Disability_Date: false,
      use_Default_Date: false,
      description: "DOCS claims playbook",
    })
  ).data;
  const batchNumber: number = batch.batch_Number;
  console.log("Created claim batch", batchNumber);
```

**Save from the response:** `data.batch_Number` (the `batchNumber` path parameter in every later step).

**Check it worked:** [`GET /claim-batches/{batchNumber}`](/openapi/vbasoftware/vbasoftware.api/claim-batches/getclaimbatches) returns the batch.

### 2. Add the claim header

[`POST /claim-batches/{batchNumber}/claims`](/openapi/vbasoftware/vbasoftware.api/claim-batch/createclaimbatch)

The claim header (`ClaimBatch`) carries the patient, provider, and dates. The schema has 675 properties and 36 required fields; 34 of the required fields are yes/no flags that should be `false` for a simple professional claim. Send `batch_Claim` as `0` and VBAPI assigns the next claim number in the batch (`ClaimBatchRepository.Create`). This is the minimal body the samples send, from `claim.json`:

```json
{
  "batch_Number": 0,
  "batch_Claim": 0,
  "claim_Type": "PROF",
  "subscriber_ID": "DOCS-0001",
  "member_Seq": "01",
  "group_ID": "DOCS-GRP1",
  "division_ID": "DOCS-DIV1",
  "provider_ID": "DOCS-PRV1",
  "patient_Account": "DOCS-PA-0001",
  "received_Date": "2030-01-15T00:00:00",
  "diagnostic_Code_Type": "0",
  "diagnostic_Code1": "Z0000",
  "total_COB": 0,
  "adjustment_Claim": false,
  "advance_Pay": false,
  "advice_To_Pay": false,
  "aeoB_Claim": false,
  "auto_Flex": false,
  "baseloadLookup": false,
  "calculate_Interest": false,
  "capitation_Claim": false,
  "context4_Override": false,
  "liability_Injury": false,
  "occupational": false,
  "orthodontics_Treatment": false,
  "other_Insurance": false,
  "override_Network_ID": false,
  "override_Payor_Account": false,
  "partial_Disability": false,
  "patient_Signature": false,
  "prosthesis_Replacement": false,
  "refund_Claim": false,
  "related_To_Accident": false,
  "related_To_Another_Party": false,
  "related_To_Auto": false,
  "related_To_Employment": false,
  "salary_Continuation": false,
  "sick_Time": false,
  "subscriber_Signature": false,
  "survivor_Benefit": false,
  "third_Party_Payment": false,
  "transaction_837": false,
  "vacation": false,
  "volume_Override": false,
  "waiting_Period_Claim": false
}
```

The fields that matter for a simple professional claim:

| Field | Sample value | Meaning |
|  --- | --- | --- |
| `batch_Number`, `batch_Claim` | from step 1, `0` | Batch and claim number; `0` lets VBAPI assign the claim number |
| `claim_Type` | `PROF` | Professional claim (other codes include `UB92`, `DENTAL`, `VIS`) |
| `subscriber_ID`, `member_Seq` | `DOCS-0001`, `01` | The patient; `subscriber_ID` allows 9 characters |
| `group_ID`, `division_ID` | `DOCS-GRP1`, `DOCS-DIV1` | The patient's enrollment |
| `provider_ID` | `DOCS-PRV1` | The servicing provider |
| `received_Date` | `2030-01-15T00:00:00` | When the claim was received |
| `diagnostic_Code_Type` | `0` | `0` means ICD-10 and `9` means ICD-9, per the schema |
| `diagnostic_Code1` | `Z0000` | First diagnosis code |
| `total_COB` | `0` | Coordination of benefits total; required |


See the [`ClaimBatch` schema](/openapi/vbasoftware/vbasoftware.api/claim-batch/createclaimbatch) for every other field.

C#
```csharp
        var claim = LoadBody("claim.json");
        claim["batch_Number"] = batchNumber;
        claim["batch_Claim"] = 0; // 0 asks VBAPI to assign the next claim number in this batch
        var createdClaim = await api.PostAsync($"/claim-batches/{batchNumber}/claims", claim);
        var batchClaim = createdClaim.Data!["batch_Claim"]!.GetValue<int>();
        Console.WriteLine($"Created claim {batchNumber} {batchClaim}");
```

Python
```python
    claim = load_body("claim.json")
    claim["batch_Number"] = batch_number
    claim["batch_Claim"] = 0  # 0 asks VBAPI to assign the next claim number in this batch
    batch_claim = api.post(f"/claim-batches/{batch_number}/claims", claim).data["batch_Claim"]
    print("Created claim", batch_number, batch_claim)
```

TypeScript
```typescript
  const claim = loadBody("claim.json");
  claim.batch_Number = batchNumber;
  claim.batch_Claim = 0; // 0 asks VBAPI to assign the next claim number in this batch
  const batchClaim: number = (await api.post(`/claim-batches/${batchNumber}/claims`, claim)).data.batch_Claim;
  console.log("Created claim", batchNumber, batchClaim);
```

**Save from the response:** `data.batch_Claim` (the `batchClaim` path parameter).

**Check it worked:** [`GET /claim-batches/{batchNumber}/claims/{batchClaim}`](/openapi/vbasoftware/vbasoftware.api/claim-batch/getclaimbatch) returns the header.

### 3. Add a service line

[`POST /claim-batches/{batchNumber}/claims/{batchClaim}/details`](/openapi/vbasoftware/vbasoftware.api/claim-batch-details/createclaimbatchdetail)

Each service line (`ClaimBatchDetail`) is one billed service. The schema has 47 required fields. Most are amounts and override flags that adjudication fills in, so send the amounts as `0` and the flags as `false`. This is the body from `service-line.json`:

```json
{
  "batch_Number": 0,
  "batch_Claim": 0,
  "claim_Seq": "01",
  "adjustment_Seq": "00",
  "procedure_Code": "99213",
  "service_Date": "2030-01-10T00:00:00",
  "service_Thru": "2030-01-10T00:00:00",
  "place_Of_Service": "11",
  "svc_Count": 1,
  "billed_Price": 150.0,
  "buccal": false,
  "capitation_Claim": false,
  "co_Ins_Amt": 0,
  "co_Pay_Amt": 0,
  "coB_Amt": 0,
  "deductible_Amt": 0,
  "discount_Amt": 0,
  "distal": false,
  "facial": false,
  "federal_Tax": 0,
  "fica": 0,
  "incisal": false,
  "interest": 0,
  "labial": false,
  "lingual": false,
  "mesial": false,
  "not_Covered_Amt": 0,
  "occlusal": false,
  "override_Benefit_Code": false,
  "override_Co_Ins_Amt": false,
  "override_Co_Pay_Amt": false,
  "override_COB_Amt": false,
  "override_Ded_Credit_Amt": false,
  "override_Deductible_Amt": false,
  "override_Federal_Tax": false,
  "override_Local_Tax": false,
  "override_Medicare_Tax": false,
  "override_Not_Covered_Amt": false,
  "override_Plan_Price": false,
  "override_Social_Security": false,
  "override_State_Tax": false,
  "override_With_Hold_Amt": false,
  "paid_Amt": 0,
  "partial_Loss": 0,
  "plan_Price": 0,
  "premium_Deduction": 0,
  "principal": 0,
  "root": false,
  "social_Security": 0,
  "state_Tax": 0,
  "ucR_Price": 0,
  "with_Hold_Amt": 0
}
```

The fields you set: `claim_Seq` and `adjustment_Seq` number the line (the sample uses `01` and `00`); `procedure_Code`, `service_Date`, `service_Thru`, `svc_Count` (units), `billed_Price`, and `place_Of_Service` describe the service. Repeat the call with a new `claim_Seq` for each extra line, or send all lines at once with [`PUT /claim-batches/{batchNumber}/claims/{batchClaim}/details-batch`](/openapi/vbasoftware/vbasoftware.api/claim-batch-details/updatebatchclaimbatchdetail).

C#
```csharp
        var line = LoadBody("service-line.json");
        line["batch_Number"] = batchNumber;
        line["batch_Claim"] = batchClaim;
        await api.PostAsync($"/claim-batches/{batchNumber}/claims/{batchClaim}/details", line);
```

Python
```python
    line = load_body("service-line.json")
    line["batch_Number"] = batch_number
    line["batch_Claim"] = batch_claim
    api.post(f"/claim-batches/{batch_number}/claims/{batch_claim}/details", line)
```

TypeScript
```typescript
  const line = loadBody("service-line.json");
  line.batch_Number = batchNumber;
  line.batch_Claim = batchClaim;
  await api.post(`/claim-batches/${batchNumber}/claims/${batchClaim}/details`, line);
```

**Save from the response:** `data.claim_Seq` and `data.adjustment_Seq` if you will update or delete the line later.

### 4. Read the claim back

[`GET /claim-batches/{batchNumber}/claims/{batchClaim}/full-claimbatch`](/openapi/vbasoftware/vbasoftware.api/adv.-claim/getfullclaimbatch)

This read-only call returns the header (`claimBatch`), the service lines (`claimBatchDetails`), and joined details such as member, group, and provider names, so you can confirm the claim matched the right records before you adjudicate it.

C#
```csharp
        var full = (await api.GetAsync($"/claim-batches/{batchNumber}/claims/{batchClaim}/full-claimbatch")).Data!;
        var lineCount = full["claimBatchDetails"]?.AsArray().Count ?? 0;
        Console.WriteLine($"claim_Status: {full["claimBatch"]?["claim_Status"]}, service lines: {lineCount}");
```

Python
```python
    full = api.get(f"/claim-batches/{batch_number}/claims/{batch_claim}/full-claimbatch").data
    print("claim_Status:", full["claimBatch"]["claim_Status"], "service lines:", len(full["claimBatchDetails"] or []))
```

TypeScript
```typescript
  const full = (await api.get(`/claim-batches/${batchNumber}/claims/${batchClaim}/full-claimbatch`)).data;
  console.log("claim_Status:", full.claimBatch.claim_Status, "service lines:", (full.claimBatchDetails ?? []).length);
```

**Check it worked:** `member_Last_Name`, `group_Name`, and `provider_Last_Name` (or `provider_Org_Name`) are filled in. Empty values usually mean an ID in the header does not match a record.

### 5. Adjudicate one claim and wait

[`POST /claim-batches/{batchNumber}/claims/{batchClaim}/adjudicate`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/adjudicateclaim)

Use this to see what the claim would pay without finalizing it. The call returns when adjudication is done, with the updated header and lines. The claim stays in the claim batch, so you can correct it and adjudicate again.

C#
```csharp
        var result = (await api.PostAsync($"/claim-batches/{batchNumber}/claims/{batchClaim}/adjudicate")).Data!;
        Console.WriteLine($"Adjudicated. claim_Status: {result["claimBatch"]?["claim_Status"]}");
        foreach (var line in result["claimBatchDetails"]?.AsArray() ?? new JsonArray())
            Console.WriteLine($"  line {line?["claim_Seq"]} status_Code: {line?["status_Code"]} paid_Amt: {line?["paid_Amt"]}");
```

Python
```python
    result = api.post(f"/claim-batches/{batch_number}/claims/{batch_claim}/adjudicate").data
    print("Adjudicated. claim_Status:", result["claimBatch"]["claim_Status"])
    for line in result["claimBatchDetails"] or []:
        print("  line", line["claim_Seq"], "status_Code:", line["status_Code"], "paid_Amt:", line["paid_Amt"])
```

TypeScript
```typescript
  const result = (await api.post(`/claim-batches/${batchNumber}/claims/${batchClaim}/adjudicate`)).data;
  console.log("Adjudicated. claim_Status:", result.claimBatch.claim_Status);
  for (const line of result.claimBatchDetails ?? []) {
    console.log("  line", line.claim_Seq, "status_Code:", line.status_Code, "paid_Amt:", line.paid_Amt);
  }
```

Example response (illustrative; field values are fake, and most fields are left out):

```json
{
  "data": {
    "claimBatch": {
      "batch_Number": 900001,
      "batch_Claim": 1,
      "claim_Type": "PROF",
      "claim_Status": "A",
      "ex_Code1": null
    },
    "claimBatchDetails": [
      {
        "claim_Seq": "01",
        "adjustment_Seq": "00",
        "procedure_Code": "99213",
        "billed_Price": 150.0,
        "plan_Price": 95.0,
        "paid_Amt": 75.0,
        "status_Code": "A"
      }
    ]
  },
  "error": null,
  "debug": { "activityID": "00000000-0000-0000-0000-000000000000" }
}
```

**What to look at:** `claimBatch.claim_Status` and the `ex_Code` fields on the header, and `status_Code`, `plan_Price`, and `paid_Amt` on each line. Claim status codes are listed in your database's claim status table.

### 6. Process one claim

[`POST /claim-batches/{batchNumber}/claims/{batchClaim}/process`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/processclaim)

Processing adjudicates the claim and moves it to the Claim table if nothing stops it. The response tells you which happened:

- `200`: `data` is the message "Claim was successfully processed and moved to the Claim table." The claim is no longer in the claim batch.
- `202`: a business rule, such as a pend, stopped the claim and it is still in the claim batch. With `includeDetails=true`, `data` holds the claim header and lines so you can see why; without it, `data` is a short message.


C#
```csharp
        var response = await api.PostAsync($"/claim-batches/{batchNumber}/claims/{batchClaim}/process?includeDetails=true");
        if (response.Status == HttpStatusCode.OK)
        {
            Console.WriteLine(response.Data); // the claim left the claim batch and is now in the Claim table
        }
        else
        {
            // 202: a business rule (for example a pend) stopped the claim, so it is still in the batch
            var header = response.Data?["claimBatch"];
            Console.WriteLine($"Not moved. claim_Status: {header?["claim_Status"]}, ex codes: {header?["ex_Code1"]} {header?["ex_Code2"]}");
        }
```

Python
```python
    response = api.post(
        f"/claim-batches/{batch_number}/claims/{batch_claim}/process",
        params={"includeDetails": "true"},
    )
    if response.status == 200:
        print(response.data)  # the claim left the claim batch and is now in the Claim table
    else:
        # 202: a business rule (for example a pend) stopped the claim, so it is still in the batch
        header = response.data["claimBatch"]
        print("Not moved. claim_Status:", header["claim_Status"], "ex codes:", header["ex_Code1"], header["ex_Code2"])
```

TypeScript
```typescript
  const response = await api.post(`/claim-batches/${batchNumber}/claims/${batchClaim}/process`, undefined, {
    includeDetails: true,
  });
  if (response.status === 200) {
    console.log(response.data); // the claim left the claim batch and is now in the Claim table
  } else {
    // 202: a business rule (for example a pend) stopped the claim, so it is still in the batch
    const header = response.data.claimBatch;
    console.log("Not moved. claim_Status:", header.claim_Status, "ex codes:", header.ex_Code1, header.ex_Code2);
  }
```

The process response does not include the new `claim_Number`. To find it, list the member's claims with [`GET /subscribers/{subscriberID}/members/{memberSeq}/list-member-claim`](/openapi/vbasoftware/vbasoftware.api/members/listmemberclaimbymember), match on `batch_Number` and `batch_Claim`, and read the finalized claim with [`GET /claims/{claimNumber}`](/openapi/vbasoftware/vbasoftware.api/claims/getclaim):

C#
```csharp
        var memberClaims = (await api.GetAsync($"/subscribers/{SubscriberId}/members/{MemberSeq}/list-member-claim")).Data?.AsArray() ?? new JsonArray();
        var match = memberClaims.FirstOrDefault(c =>
            c?["batch_Number"]?.GetValue<int>() == batchNumber &&
            c?["batch_Claim"]?.GetValue<int>() == batchClaim &&
            c?["claim_Number"] is not null);
        if (match is not null)
        {
            var finalized = (await api.GetAsync($"/claims/{match["claim_Number"]}")).Data;
            Console.WriteLine($"Claim {finalized?["claim_Number"]} claim_Status: {finalized?["claim_Status"]}");
        }
```

Python
```python
    member_claims = api.get(f"/subscribers/{SUBSCRIBER_ID}/members/{MEMBER_SEQ}/list-member-claim").data or []
    match = next(
        (c for c in member_claims
         if c["batch_Number"] == batch_number and c["batch_Claim"] == batch_claim and c["claim_Number"]),
        None,
    )
    if match:
        claim = api.get(f"/claims/{match['claim_Number']}").data
        print("Claim", claim["claim_Number"], "claim_Status:", claim["claim_Status"])
```

TypeScript
```typescript
  const memberClaims: any[] =
    (await api.get(`/subscribers/${SUBSCRIBER_ID}/members/${MEMBER_SEQ}/list-member-claim`)).data ?? [];
  const match = memberClaims.find(
    (c) => c.batch_Number === batchNumber && c.batch_Claim === batchClaim && c.claim_Number,
  );
  if (match) {
    const claim = (await api.get(`/claims/${match.claim_Number}`)).data;
    console.log("Claim", claim.claim_Number, "claim_Status:", claim.claim_Status);
  }
```

**Save from the response:** `claim_Number`, the claim's ID from now on.

### 7. Create a claim queue

[`POST /claim-queues`](/openapi/vbasoftware/vbasoftware.api/claim-queues/createclaimqueue)

For many claims, load them into a claim queue and run the whole queue in one call, for example from a job your system schedules every night. `ClaimQueue` requires only `claimQueue_Key`; send `0` and use the key in the response. Set `queue_Type` to `CHECK` for a queue you will adjudicate or `PROCESS` for one you will process: VBAPI rejects a queue run whose type does not match the operation. The sample also sets `queue_Status` to `QUEUED`, `queue_Priority` to `1`, and `queue_User`, which is how VBAPI builds the queue it uses internally for single-claim requests. The valid types come from [`GET /claim-queue-types`](/openapi/vbasoftware/vbasoftware.api/claim-queue-types/listclaimqueuetypes), and priorities and statuses from [`GET /claim-queue-priorities`](/openapi/vbasoftware/vbasoftware.api/claim-queue-priorities/listclaimqueuepriority) and [`GET /claim-queue-statuses`](/openapi/vbasoftware/vbasoftware.api/claim-queue-statuses/listclaimqueuestatus).

C#
```csharp
        var queue = await api.PostAsync("/claim-queues", new
        {
            claimQueue_Key = 0, // VBAPI assigns the key
            queue_Type = "CHECK", // CHECK runs with /adjudicate, PROCESS runs with /process
            queue_Status = "QUEUED",
            queue_Priority = 1,
            queue_User = Environment.GetEnvironmentVariable("VBAPI_USERNAME"),
        });
        var queueKey = queue.Data!["claimQueue_Key"]!.GetValue<int>();
        Console.WriteLine($"Created claim queue {queueKey}");
```

Python
```python
    queue = api.post("/claim-queues", {
        "claimQueue_Key": 0,  # VBAPI assigns the key
        "queue_Type": "CHECK",  # CHECK runs with /adjudicate, PROCESS runs with /process
        "queue_Status": "QUEUED",
        "queue_Priority": 1,
        "queue_User": os.environ["VBAPI_USERNAME"],
    }).data
    queue_key = queue["claimQueue_Key"]
    print("Created claim queue", queue_key)
```

TypeScript
```typescript
  const queue = (
    await api.post("/claim-queues", {
      claimQueue_Key: 0, // VBAPI assigns the key
      queue_Type: "CHECK", // CHECK runs with /adjudicate, PROCESS runs with /process
      queue_Status: "QUEUED",
      queue_Priority: 1,
      queue_User: process.env.VBAPI_USERNAME,
    })
  ).data;
  const queueKey: number = queue.claimQueue_Key;
  console.log("Created claim queue", queueKey);
```

**Save from the response:** `data.claimQueue_Key` (the `claimQueueKey` path parameter).

### 8. Add claims to the queue

[`POST /claim-queues/{claimQueueKey}/details`](/openapi/vbasoftware/vbasoftware.api/claim-queue-details/createclaimqueuedetail)

Add one entry per claim. `ClaimQueueDetail` requires `claimQueue_Key`, `batch_Number`, `batch_Claim`, and `claimQueueProcessor_Key`. The sample sends `claimQueueProcessor_Key` as `0`, the value VBAPI uses when it queues a single claim itself; the configured processors are listed by [`GET /claim-queue-processors`](/openapi/vbasoftware/vbasoftware.api/claim-queue-processors/listclaimqueueprocessor). For large queues, send all entries in one call with [`POST /claim-queues/{claimQueueKey}/details-mass-insert`](/openapi/vbasoftware/vbasoftware.api/adv.-claim/massinsertclaimqueuedetail), which takes an array of the same objects and returns `202`.

C#
```csharp
        await api.PostAsync($"/claim-queues/{queueKey}/details", new
        {
            claimQueue_Key = queueKey,
            batch_Number = batchNumber,
            batch_Claim = batchClaim,
            claimQueueProcessor_Key = 0, // the value VBAPI itself uses when it queues a single claim
        });
```

Python
```python
    api.post(f"/claim-queues/{queue_key}/details", {
        "claimQueue_Key": queue_key,
        "batch_Number": batch_number,
        "batch_Claim": batch_claim,
        "claimQueueProcessor_Key": 0,  # the value VBAPI itself uses when it queues a single claim
    })
```

TypeScript
```typescript
  await api.post(`/claim-queues/${queueKey}/details`, {
    claimQueue_Key: queueKey,
    batch_Number: batchNumber,
    batch_Claim: batchClaim,
    claimQueueProcessor_Key: 0, // the value VBAPI itself uses when it queues a single claim
  });
```

**Check it worked:** [`GET /claim-queues/{claimQueueKey}/details`](/openapi/vbasoftware/vbasoftware.api/claim-queue-details/listclaimqueuedetail) lists the claims in the queue.

### 9. Notify the examiners (optional)

[`POST /claim-queues/{claimQueueKey}/notify-user-groups`](/openapi/vbasoftware/vbasoftware.api/claim-queue-notify-user-groups/createclaimqueuenotifygroup)

Register a VBASoftware user group, such as your claims examiners, on the queue. `ClaimQueueNotifyGroup` requires `claimQueue_Key` and `userGroup_Key`; find the key with [`GET /user-groups`](/openapi/vbasoftware/vbasoftware.api/user-groups/listusergroup). The samples skip this step unless `DOCS_USER_GROUP_KEY` is set.

C#
```csharp
        var userGroupKey = Environment.GetEnvironmentVariable("DOCS_USER_GROUP_KEY");
        if (!string.IsNullOrEmpty(userGroupKey))
        {
            await api.PostAsync($"/claim-queues/{queueKey}/notify-user-groups", new
            {
                claimQueue_Key = queueKey,
                userGroup_Key = int.Parse(userGroupKey),
            });
        }
```

Python
```python
    if USER_GROUP_KEY:
        api.post(f"/claim-queues/{queue_key}/notify-user-groups", {
            "claimQueue_Key": queue_key,
            "userGroup_Key": int(USER_GROUP_KEY),
        })
```

TypeScript
```typescript
  const userGroupKey = process.env.DOCS_USER_GROUP_KEY;
  if (userGroupKey) {
    await api.post(`/claim-queues/${queueKey}/notify-user-groups`, {
      claimQueue_Key: queueKey,
      userGroup_Key: Number(userGroupKey),
    });
  }
```

### 10. Run the queue

[`POST /claim-queues/{claimQueueKey}/adjudicate`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/adjudicateclaimqueue)

This starts the run and returns `202` right away with a short message; the claims are adjudicated in the background. For a `PROCESS` queue, call [`POST /claim-queues/{claimQueueKey}/process`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/processclaimqueue) instead. Neither call has a request body.

C#
```csharp
        var accepted = await api.PostAsync($"/claim-queues/{queueKey}/adjudicate");
        Console.WriteLine($"Queue accepted: {(int)accepted.Status}"); // 202; the queue runs in the background
```

Python
```python
    accepted = api.post(f"/claim-queues/{queue_key}/adjudicate")
    print("Queue accepted:", accepted.status)  # 202; the queue runs in the background
```

TypeScript
```typescript
  const accepted = await api.post(`/claim-queues/${queueKey}/adjudicate`);
  console.log("Queue accepted:", accepted.status); // 202; the queue runs in the background
```

### 11. Wait for the queue to finish

[`GET /claim-queues/{claimQueue_Key}`](/openapi/vbasoftware/vbasoftware.api/claim-queues/getclaimqueue)

Poll the queue until `queue_Status` is `COMPLETE`. The schema describes two statuses: `QUEUED` while claims are being worked and `COMPLETE` when every claim has finished; `queue_End` records when the last claim finished. Then list the queue entries to see each claim's `queue_Result`. The possible results are listed by [`GET /claim-queue-results`](/openapi/vbasoftware/vbasoftware.api/claim-queue-results/listclaimqueueresult). A 15-second interval keeps polling well inside the [rate limits](/developer-portal/concepts/rate-limits-and-performance).

C#
```csharp
        var deadline = DateTimeOffset.UtcNow.AddMinutes(30);
        while ((await api.GetAsync($"/claim-queues/{queueKey}")).Data?["queue_Status"]?.GetValue<string>() != "COMPLETE")
        {
            if (DateTimeOffset.UtcNow > deadline)
                throw new TimeoutException($"Claim queue {queueKey} did not complete in 30 minutes");
            await Task.Delay(TimeSpan.FromSeconds(15));
        }

        await foreach (var detail in api.GetAllAsync($"/claim-queues/{queueKey}/details"))
            Console.WriteLine($"Claim {detail?["batch_Number"]} {detail?["batch_Claim"]} queue_Result: {detail?["queue_Result"]}");
```

Python
```python
    deadline = time.time() + 30 * 60
    while api.get(f"/claim-queues/{queue_key}").data["queue_Status"] != "COMPLETE":
        if time.time() > deadline:
            raise TimeoutError(f"Claim queue {queue_key} did not complete in 30 minutes")
        time.sleep(15)

    for detail in api.iter_pages(f"/claim-queues/{queue_key}/details"):
        print("Claim", detail["batch_Number"], detail["batch_Claim"], "queue_Result:", detail["queue_Result"])
```

TypeScript
```typescript
  const deadline = Date.now() + 30 * 60 * 1000;
  while ((await api.get(`/claim-queues/${queueKey}`)).data.queue_Status !== "COMPLETE") {
    if (Date.now() > deadline) throw new Error(`Claim queue ${queueKey} did not complete in 30 minutes`);
    await new Promise((resolve) => setTimeout(resolve, 15_000));
  }

  for await (const detail of api.getAll(`/claim-queues/${queueKey}/details`)) {
    console.log("Claim", detail.batch_Number, detail.batch_Claim, "queue_Result:", detail.queue_Result);
  }
```

For more detail on a claim that failed, [`GET /claim-queue-logs`](/openapi/vbasoftware/vbasoftware.api/claim-queue-logs/listclaimqueuelog) returns log entries with `batch_Number`, `batch_Claim`, `log_Action`, `log_Result`, and `log_Message`. The list has no filter parameters, so page through it and match on the batch and claim numbers.

## Verify the result

These calls only read data:

- After adjudication (step 5 or a `CHECK` queue), [`GET /claim-batches/{batchNumber}/claims/{batchClaim}/full-claimbatch`](/openapi/vbasoftware/vbasoftware.api/adv.-claim/getfullclaimbatch) shows the claim still in the batch with its adjudicated `claim_Status` and line amounts.
- After processing (step 6 or a `PROCESS` queue), the claim appears in [`GET /subscribers/{subscriberID}/members/{memberSeq}/list-member-claim`](/openapi/vbasoftware/vbasoftware.api/members/listmemberclaimbymember) with a `claim_Number`, and [`GET /claims/{claimNumber}`](/openapi/vbasoftware/vbasoftware.api/claims/getclaim) returns it. Claims that did not pass are still in the claim batch.


## Clean up

- A claim that is still in a claim batch can be removed with [`DELETE /claim-batches/{batchNumber}/claims/{batchClaim}/full-delete`](/openapi/vbasoftware/vbasoftware.api/adv.-claim/fulldeleteclaimbatch), which also removes its service lines and related records. Then delete the empty batch with [`DELETE /claim-batches/{batchNumber}`](/openapi/vbasoftware/vbasoftware.api/claim-batches/deleteclaimbatches). Both return `204`.
- Delete a test queue with [`DELETE /claim-queues/{claimQueue_Key}`](/openapi/vbasoftware/vbasoftware.api/claim-queues/deleteclaimqueue).
- A processed claim is a finalized claim in the Claim table. Do not delete it through the API; reverse it with your normal void or adjustment process in VBASoftware.


## Common errors

| Symptom | Likely cause | Fix |
|  --- | --- | --- |
| `400` or `422` when you create a claim or service line | A required field is missing, has the wrong type, or is longer than its `maxLength` | Send every field in `claim.json` or `service-line.json`; check lengths against the schema |
| `400` "Invalid Queue Type" when you run a queue | The queue's `queue_Type` does not match the operation | Run `CHECK` queues with the queue adjudicate operation and `PROCESS` queues with the queue process operation (step 10) |
| `404` from `full-claimbatch` after processing | The claim was processed and moved to the Claim table | Find it with `list-member-claim` as in step 6 |
| `202` from process | A business rule, such as a pend, stopped the claim | Call again with `includeDetails=true` and check `claim_Status` and the `ex_Code` fields |
| Joined names are empty in step 4 | An ID in the claim header does not match a record | Fix the subscriber, member, group, division, or provider ID and update the claim |
| Queue stays `QUEUED` | The run has not finished, or a claim is stuck | Keep polling; check `GET /claim-queue-logs`; send the `activityID` to support |
| `403` with `{"message":"Forbidden"}` on every call | The `x-api-key` header is missing or wrong | See [errors](/developer-portal/concepts/errors) |


Contacting support
Send VBA support:

- the `debug.activityID` from the response
- the date and time of the call, with time zone
- the method and path, for example `POST /claim-batches`
- the full `error` object from the response
- the request body, with passwords, tokens, and personal data removed


Never send your password, API key, or tokens. See [Support and escalation](/developer-portal/help/support).

## Variations

- **Many claims at once:** create claims with [`PUT /claim-batches/{batchNumber}/claims-batch`](/openapi/vbasoftware/vbasoftware.api/claim-batch/updatebatchclaimbatch) and lines with [`PUT /claim-batches/{batchNumber}/claims/{batchClaim}/details-batch`](/openapi/vbasoftware/vbasoftware.api/claim-batch-details/updatebatchclaimbatchdetail). Both return `207` with a result per item; check each item, because one failure does not fail the others.
- **Fire and forget for one claim:** [`POST /claim-batches/{batchNumber}/claims/{batchClaim}/adjudicate-no-response`](/openapi/vbasoftware/vbasoftware.api/claim-adjudication/adjudicateclaimnoresponse) returns `202` and runs the same adjudication without returning the result. Read the claim back with step 4 when you need the outcome.
- **Scheduled runs:** VBASoftware also has claim queue schedules ([`GET /claim-queue-schedules`](/openapi/vbasoftware/vbasoftware.api/claim-queue-schedules/listclaimqueueschedule)). Until VBA confirms how integrators should use them, run steps 7 to 11 from a job your own system schedules.
- **Safe to re-run?** No. Each run creates a new claim batch and claim. Adjudicating the same claim again is safe; it stays in the batch. Processing a claim that already moved fails because it is no longer in the batch.


## Download

The complete runnable samples are in the documentation repository under `_samples/playbooks/claims-intake-and-adjudication/`: `ClaimsIntakePlaybook.cs`, `claims_intake.py`, `claimsIntake.ts`, and the request bodies `claim.json` and `service-line.json`. Each sample uses the shared helper for its language described in the [quick start](/developer-portal/get-started/quick-start).

## Related

- Concepts: [data model](/developer-portal/concepts/data-model), [IDs and conventions](/developer-portal/concepts/ids-and-conventions), [requests and responses](/developer-portal/concepts/requests-and-responses)
- Next playbook: [Bill premiums and apply payments](/developer-portal/playbooks/premium-billing-and-payments)
- Ask the AI: "Using the Enter claims and adjudicate them playbook, write a Python job that processes every claim in claim batch 900001 overnight and reports the ones that pended."