> ## Documentation Index
> Fetch the complete documentation index at: https://docs.verial.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Web Portal

> Browser-accessible simulations of real payer web portals with a matching REST API.

The web portal simulator exposes payer web portals your agent can drive with a browser automation tool. Each portal is a pixel-faithful reproduction of a real vendor site (login page, navigation, form fields, workflow) backed by the same sandbox state a REST API reads and writes. Criteria can verify work performed through the UI just like work performed through the API.

Use this simulator when your agent is designed to operate real payer portals end to end: logging in, searching patients, submitting prior authorizations, reading determinations from a browser. The verification engine scores `portal-state-match` criteria against the resulting portal state.

## Portal catalog

| Portal          | Slug          | Use case                                                                                                                           |
| --------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| **RadMD**       | `radmd`       | Radiology benefit management prior auth (Evolent). Multi-step wizard: patient lookup, physician, clinical questions, auth summary. |
| **CoverMyMeds** | `covermymeds` | Pharmacy prior auth (ePA) across many payers. Draft management, formulary lookup, prescriber verification.                         |

The `slug` goes in the `config.portal` field when you create the simulator.

## How your agent connects

Each sandbox gets its own credential pair, valid only for that sandbox's lifetime. When the benchmark run is created (or a sandbox is provisioned directly), the sandbox's `credentials` payload contains:

| Field        | Description                                   |
| ------------ | --------------------------------------------- |
| `portal_url` | URL to navigate a browser to (login page)     |
| `username`   | Username for the portal's login form          |
| `password`   | Password for the portal's login form          |
| `api_url`    | REST base for the same sandbox (backs the UI) |

The same backing state is shared between the UI and the API, so you can drive the portal with Playwright / Stagehand / browser-use *or* call the REST endpoints directly, and criteria will score either path identically.

## Endpoints (REST)

The REST API behind the portal is rooted at `api_url`. Key endpoints:

| Method | Endpoint                              | Description                                             |
| ------ | ------------------------------------- | ------------------------------------------------------- |
| `POST` | `{api_url}/prior-auths`               | Submit a prior authorization                            |
| `GET`  | `{api_url}/prior-auths/{auth_number}` | Retrieve a prior auth's current state and determination |
| `GET`  | `{api_url}/patients`                  | List patients with coverage                             |
| `GET`  | `{api_url}/providers`                 | List credentialed providers                             |

These match the direct-access endpoints documented under [Submit prior auth](/api-reference/payer/submit-prior-auth), [Get prior auth](/api-reference/payer/get-prior-auth), and [List payer patients](/api-reference/payer/list-patients).

## Driving the rollout

Browser path (Playwright):

```typescript theme={null}
import { chromium } from 'playwright'

const browser = await chromium.launch()
const page = await browser.newPage()
await page.goto(portalUrl)
await page.fill('input[name="username"]', username)
await page.fill('input[name="password"]', password)
await page.click('button[type="submit"]')
// ... drive the wizard to submit a prior auth
```

REST path:

```bash theme={null}
curl -X POST "$API_URL/prior-auths" \
  -H "Authorization: Bearer $RUN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "patient": { "member_id": "BCB123456789" },
    "procedure_code": "72148",
    "diagnosis_code": "M54.5"
  }'
```

For an end-to-end walkthrough, see the [Web Simulator Quickstart](/guides/quickstart-web-sim).

## Configuration

```bash theme={null}
curl -X POST https://api.verial.ai/simulators \
  -H "Authorization: Bearer $VERIAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'JSON'
{
  "type": "Payer",
  "name": "RadMD",
  "config": {
    "portal": "radmd",
    "determinations": [
      { "match": { "procedure_code": "70553" }, "response": { "status": "approved" } },
      { "match": { "procedure_code": "70551" }, "response": { "status": "denied", "reason": "not medically necessary" } }
    ],
    "default_determination": { "status": "pending", "delay_seconds": 0 }
  }
}
JSON
```

| Field                   | Type                       | Description                                                                                                                                             |
| ----------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `portal`                | `"radmd" \| "covermymeds"` | Which portal skin to render. Determines the `portal_url` host and the UI the agent drives.                                                              |
| `determinations`        | array                      | Rules that map a submitted PA (by `procedure_code` or `patient_member_id`) to a determination. First match wins.                                        |
| `default_determination` | object                     | Returned when no rule matches. Fields: `status` (`approved` \| `denied` \| `pending` \| `need_more_info`), optional `reason`, optional `delay_seconds`. |

## Verification

The `portal-state-match` check correlates a submitted PA (by `request_id`, `auth_number`, or another key) with its row in portal state and asserts on field values.

```json theme={null}
{
  "label": "Prior auth submitted with correct CPT",
  "weight": 1.0,
  "axis": "correctness",
  "assertion": {
    "assert": "portal-state-match",
    "correlate_by": { "resource": "prior_auth_requests", "key": "request_id" },
    "assertions": [
      { "path": "status", "expected": "submitted" },
      { "path": "cpt_code", "expected": "72148" }
    ]
  }
}
```

See the [Criteria concept page](/guides/concepts/criteria#portal-prior-auth-submitted) for more examples and the full assertion spec.

## Interaction evidence

Every UI action (form submit, patient search, auth submission) and every API call is recorded as a sandbox event alongside the request/response pair. Inspect them via `GET /sandboxes/{id}/events` to see exactly what your agent did during the rollout.

## Next Steps

<CardGroup cols={2}>
  <Card title="Web Simulator Quickstart" icon="rocket" href="/guides/quickstart-web-sim">
    Provision a RadMD sandbox and log in from a browser in under 5 minutes.
  </Card>

  <Card title="Criteria" icon="check-double" href="/guides/concepts/criteria">
    Full reference for `portal-state-match` assertions.
  </Card>

  <Card title="Payer API reference" icon="code" href="/api-reference/payer/submit-prior-auth">
    Direct-access prior-auth endpoints.
  </Card>

  <Card title="Simulators overview" icon="server" href="/guides/simulators/overview">
    Lifecycle, provisioning, and configuration patterns.
  </Card>
</CardGroup>
