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

# Schemas

> Discover the schemas provisioned for your account, the input keys each one requires, and the fields each one returns.

A [**schema**](/guides/concepts#schema) defines the structured output fields a request returns and which inputs are required to submit one. Pass its `schemaId` on `POST /v1/requests` to invoke it.

These endpoints make integration self-service. Read the schemas your account is provisioned for. Read the fields a schema returns. Read the input keys a schema needs.

| Endpoint | Purpose |
| - | - |
| [`GET /v1/schemas`](/api-reference/schemas/list-schemas) | List the schemas owned by the account associated with your API key. |
| [`GET /v1/schemas/{schemaId}`](/api-reference/schemas/retrieve-a-schema) | Return one schema's detail: its name, its request type, and every field it can return in `results`. |
| [`GET /v1/schemas/{schemaId}/required-inputs`](/api-reference/schemas/required-inputs-for-a-schema) | Return the input keys required to submit a request against a given schema. |
| [`POST /v1/schemas/{schemaId}/required-payer-inputs`](/api-reference/schemas/resolve-payer-names-against-a-schemas-required-inputs) | Resolve a batch of payer names to their per-payer required inputs (opt-in: see [Per-Payer Required Inputs](/guides/payer-required-inputs)). |

Every endpoint here uses the same bearer-token authentication as the rest of the API. All non-2xx responses use the uniform `{error, message, [details]}` envelope (see [Errors](#errors)).

## List your schemas

```bash theme={null}
curl -H "Authorization: Bearer <token>" \
  https://robodialer-service-api-9nc4t1p9.uc.gateway.dev/v1/schemas
```

### Response

```json theme={null}
{
  "schemas": [
    {
      "schemaId": "fWxzG4nqtpHsJxS5Lm3q",
      "name": "Claim Status (Commercial)",
      "requestType": "claim-status"
    },
    {
      "schemaId": "qP2bN8rT6mK1xC3vW9aL",
      "name": "Verification of Benefits",
      "requestType": "vob"
    }
  ]
}
```

| Field | Type | Notes |
| - | - | - |
| `schemaId` | string | Pass to [`POST /v1/requests`](/guides/creating-a-request) as `schemaId`. |
| `name` | string | Human-readable label. Falls back to the `schemaId` when no name is set. |
| `requestType` | string | The kind of extraction this schema produces (e.g. `claim-status`, `vob`). Server-derived. Useful for filtering the list, but you don't pass it on `POST /v1/requests`. It surfaces on `RequestResponse.requestType` after the request runs. |

Schemas that are no longer accessible for your account are filtered out of this list.

## Look up the fields a schema returns

`GET /v1/schemas/{schemaId}` returns one schema's detail. The part you build against is `resultsFields`: every field the schema can produce in `results` on [`GET /v1/requests/{requestId}`](/guides/reading-requests). Read it to build your ingest mapping and your destination table before you run a request.

```bash theme={null}
curl -H "Authorization: Bearer <token>" \
  https://robodialer-service-api-9nc4t1p9.uc.gateway.dev/v1/schemas/fWxzG4nqtpHsJxS5Lm3q
```

### Response

```json theme={null}
{
  "schemaId": "fWxzG4nqtpHsJxS5Lm3q",
  "name": "Claim Status (Commercial)",
  "requestType": "claim-status",
  "resultsFields": [
    {
      "name": "checkNumber",
      "label": "Check Number",
      "description": "What is the check number?",
      "type": "alphanumeric"
    },
    {
      "name": "claimReceived",
      "label": "Claim Received",
      "description": "Did the payer receive the claim?",
      "type": "boolean"
    },
    {
      "name": "claimStatus",
      "label": "Claim Status",
      "description": "What is the status of the claim?",
      "type": "multiple",
      "allowedValues": ["PAID", "DENIED", "PENDING"]
    },
    {
      "name": "paidAmount",
      "label": "Paid Amount",
      "description": "What amount was paid on the claim?",
      "type": "dollar"
    },
    {
      "name": "paidDate",
      "label": "Paid Date",
      "description": "On what date was the claim paid?",
      "type": "date"
    }
  ]
}
```

`name` and `requestType` are the same values [`GET /v1/schemas`](#list-your-schemas) returns for this schema. Inputs are not included here; use the [required-inputs endpoint](#look-up-required-and-optional-inputs) for what to send.

Each entry in `resultsFields` carries:

| Field | Type | Notes |
| - | - | - |
| `name` | string | The `results` key for this field. Also the value that appears in the top-level `missingFields`. Always present. |
| `label` | string | Display name. Falls back to `name` when the schema sets none. Always present. |
| `description` | string | What the field captures, usually the question the agent asks. Can hold literal `{placeholder}` tokens; those are input *names*, never values. Omitted when empty. |
| `type` | string | Declared value type. See [Value types](#value-types) below. Omitted when the schema declares none. |
| `allowedValues` | array of strings | The declared choices, on `multiple` fields. Omitted when the schema declares none. |

An optional key is omitted, never `null`. Entries are sorted by `name`. The list is never empty: a schema with no readable fields returns `500`.

`name` matches the top-level `missingFields` exactly. Do not join it against `callSteps[].missingFields`: that list falls back to raw question text for a skipped question that carries no alias.

The endpoint does not report whether a field is required. Even a field the schema always asks for goes missing when the payer will not give it up, so requiredness is not a property you can build a `NOT NULL` column on. Read `missingFields` on a completed request to see what that run did not capture.

<Note>
  **Every column you build from this inventory must be nullable.** For this schema the inventory is a superset of any one response. Most fields on a large schema are gated on another field's answer, so they are absent on any given request. An unanswered field is absent from `results`; it is never `null`. Map on `name`, treat every field as optional, and ignore keys you do not map. The endpoint does not report which fields are gated.
</Note>

### Value types

| `type` | Wire shape |
| - | - |
| `boolean` | JSON `true` or `false` |
| `date` | ISO `yyyy-mm-dd` string |
| `dollar` | Bare-numeric string **or** JSON number. Accept both. No `$` and no thousands separator. |
| `number` | Bare-numeric string **or** JSON number. Accept both. |
| `percentage` | Bare-numeric string **or** JSON number. Accept both. |
| `multiple` | String, one of `allowedValues` |
| `text` | String |
| `alphanumeric` | String |
| `address` | String |
| `phoneNumber` | String |
| `faxNumber` | String |

Those eleven are the full vocabulary. A schema can still declare a type outside the list. That type is returned as-is, so treat an unrecognised `type` as an opaque string.

<Warning>
  **`allowedValues` is not a closed set.** The value `CANNOT ANSWER - <reason>` passes through verbatim as a string on any type, including `boolean` and `multiple`. A strict enum parse or boolean parse fails on it. Detect it by string prefix. It does not appear in `missingFields`: an explicit non-answer counts as answered.
</Warning>

<Note>
  **A chained request can return keys beyond this schema.** A request can open a follow-up leg: a second call against a different schema, listed as an extra entry in [`callSteps`](/guides/reading-requests#calls-behind-a-request). That leg's captured values merge into the same top-level `results`, under the leg schema's own field names. `resultsFields` covers one schema and does not list them. Read `callSteps[].schemaId` on a completed request, then call this endpoint again for that ID.
</Note>

`resultsFields` describes the schema's current latest version. A request that already ran was pinned to the version that was latest at run time. So an older request's `results` can carry keys this endpoint no longer lists, or omit keys it now lists. Read the endpoint again and diff the field list to find a change.

## Look up required and optional inputs

Once you have a `schemaId`, fetch the input keys it accepts. The response carries two sorted, disjoint lists: `requiredInputs.fields` (must be supplied or you get `INVALID_INPUTS`) and `optionalInputs.fields` (accepted but not required, useful for "build a request" forms that want to show every key the schema declares). Both lists describe what this schema declares; neither is a limit on what `inputs` accepts.

```bash theme={null}
curl -H "Authorization: Bearer <token>" \
  https://robodialer-service-api-9nc4t1p9.uc.gateway.dev/v1/schemas/fWxzG4nqtpHsJxS5Lm3q/required-inputs
```

### Response

```json theme={null}
{
  "schemaId": "fWxzG4nqtpHsJxS5Lm3q",
  "requiredInputs": {
    "fields": [
      "beginningDateOfService",
      "billingProviderName",
      "billingProviderTaxId",
      "claimChargeAmount",
      "memberId",
      "patientDateOfBirth",
      "patientFirstName",
      "patientLastName",
      "payerName",
      "phoneNumber",
      "renderingProviderName",
      "renderingProviderNpi"
    ]
  },
  "optionalInputs": {
    "fields": [
      "memberId2"
    ]
  }
}
```

Field-name keys are returned verbatim: spell them in `inputs` on `POST /v1/requests` exactly as they come back here. If SuperDial updates the schema, call this endpoint again (or refresh your cache) before relying on a fixed list in code.

<Note>
  If your account is enabled for [payer phone number lookup](/guides/payer-resolution), `phoneNumber` moves out of `requiredInputs.fields` and into `optionalInputs.fields` for this endpoint, because you can omit it and let SuperDial fill it in from `payerName`. With lookup off (the default), `phoneNumber` stays required.
</Note>

<Note>
  If your account is enabled for [per-payer required inputs](/guides/payer-required-inputs), some payers require additional inputs that aren't listed here. Treat this list as the baseline; a request for one of those payers may need more.
</Note>

<Note>
  This endpoint reports what the schema declares, not everything `POST /v1/requests` will take. You can send [extra keys](/guides/creating-a-request#extra-inputs) that appear in neither list, to give the call context the schema never asked to collect.
</Note>

## End-to-end discovery flow

```python theme={null}
import requests

BASE = "https://robodialer-service-api-9nc4t1p9.uc.gateway.dev"

def list_schemas(token):
    r = requests.get(f"{BASE}/v1/schemas", headers={"Authorization": f"Bearer {token}"})
    r.raise_for_status()
    return r.json()["schemas"]

def schema_inputs(token, schema_id):
    r = requests.get(
        f"{BASE}/v1/schemas/{schema_id}/required-inputs",
        headers={"Authorization": f"Bearer {token}"},
    )
    r.raise_for_status()
    body = r.json()
    return body["requiredInputs"]["fields"], body["optionalInputs"]["fields"]

def schema_results_fields(token, schema_id):
    r = requests.get(
        f"{BASE}/v1/schemas/{schema_id}",
        headers={"Authorization": f"Bearer {token}"},
    )
    r.raise_for_status()
    return r.json()["resultsFields"]

# Use it
schemas = list_schemas(token)
schema = next(s for s in schemas if s["requestType"] == "claim-status")
required, optional = schema_inputs(token, schema["schemaId"])
print("required:", required)
# ['beginningDateOfService', 'billingProviderName', ..., 'phoneNumber']
print("optional:", optional)
# ['memberId2']

returned = schema_results_fields(token, schema["schemaId"])
print("returns:", [f["name"] for f in returned])
# ['checkNumber', 'claimReceived', 'claimStatus', 'paidAmount', 'paidDate']
```

After this you have both sides of the schema. To submit, pass the `schemaId` and populate every key in `required` inside the `inputs` object. You can add the `optional` keys, and [extra keys of your own](/guides/creating-a-request#extra-inputs), on top of that. To ingest, map those field names onto your own columns, every one of them nullable. The `requestType` is server-derived; you'll see it on the response.

## Errors

Every non-2xx response uses the uniform envelope:

```json theme={null}
{
  "error": "MACHINE_CODE",
  "message": "Human-readable description.",
  "details": { /* optional, only on INVALID_INPUTS */ }
}
```

| HTTP code | `error` code | When |
| - | - | - |
| `400` | `INVALID_REQUEST` | The `schemaId` path parameter was empty, contained `/`, started with `_` or `.`, or exceeded 1500 characters. Applies to every endpoint that takes a `schemaId` in the path. |
| `401` | (gateway envelope) | Bearer token missing, malformed, or expired. The gateway uses `{code, message}`, not the envelope above. |
| `404` | `SCHEMA_NOT_FOUND` | No schema with that ID exists for your account, or it has been retired and is no longer accessible. |
| `404` | `ACCOUNT_NOT_FOUND` | The API key resolves to an account that no longer exists. Contact support. |
| `500` | `INTERNAL_ERROR` | Unexpected server failure. Also returned by `GET /v1/schemas/{schemaId}` when the schema's stored version record is unreadable or carries no fields: an empty `resultsFields` is never returned as a `200`. Retry once; escalate if persistent. |

### Example error responses

```json theme={null}
// 400: invalid schemaId path parameter
{
  "error": "INVALID_REQUEST",
  "message": "The provided schemaId is invalid."
}
```

```json theme={null}
// 404: schema not found, or has been retired
{
  "error": "SCHEMA_NOT_FOUND",
  "message": "No schema with that ID exists for your account."
}
```

```json theme={null}
// 404: API key doesn't resolve to a provisioned account
{
  "error": "ACCOUNT_NOT_FOUND",
  "message": "No account is associated with this API key. Contact support if you believe this is an error."
}
```

```json theme={null}
// 500: unexpected server failure
{
  "error": "INTERNAL_ERROR",
  "message": "An internal error occurred. Please try again or contact support if the problem persists."
}
```

For the full response and parameter schemas, see the [API Reference → Schemas](/api-reference/schemas/list-schemas).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.