> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cloudraker.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cloudraker.com/_mcp/server.

# Field types

A schema field says what *type* a value has. A field type says what it *is*: `{"type": "number"}` could be a quantity or an amount of money, and `{"type": "string"}` could be a paragraph, a phone number, or a mailing address. Annotating it makes extraction better at reading it — and makes the in-app editors render it properly.

Annotations are **optional**. A schema with none behaves exactly as it does today, and every annotated schema is still plain, valid JSON Schema: standard `format` where one exists, and `x-cr-*` vendor keywords for the rest. A validator that has never heard of `x-cr-*` still reads the schema correctly.

## The 13 field types

| Field type     | Emitted JSON Schema                                                      | Marked by                                                       |
| -------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------- |
| `text`         | `{ "type": "string" }`                                                   | nothing — the bare type                                         |
| `long_text`    | `{ "type": "string", "x-cr-kind": "long_text" }`                         | `x-cr-kind`                                                     |
| `number`       | `{ "type": "number" }`                                                   | nothing — the bare type                                         |
| `currency`     | `{ "type": "number", "x-cr-kind": "currency", "x-cr-currency": "CAD" }`  | `x-cr-kind` (+ the `x-cr-currency` setting, omitted when unset) |
| `boolean`      | `{ "type": "boolean" }`                                                  | nothing — the bare type                                         |
| `date`         | `{ "type": "string", "format": "date" }`                                 | standard `format`                                               |
| `datetime`     | `{ "type": "string", "format": "date-time" }`                            | standard `format`                                               |
| `select`       | `{ "type": "string", "enum": ["a", "b"] }`                               | structure — `enum`                                              |
| `multi_select` | `{ "type": "array", "items": { "type": "string", "enum": ["a", "b"] } }` | structure — an array of `enum`                                  |
| `email`        | `{ "type": "string", "format": "email" }`                                | standard `format`                                               |
| `phone`        | `{ "type": "string", "x-cr-kind": "phone" }`                             | `x-cr-kind`                                                     |
| `url`          | `{ "type": "string", "format": "uri" }`                                  | standard `format`                                               |
| `address`      | `{ "type": "string", "x-cr-kind": "address" }`                           | `x-cr-kind`                                                     |

Only two vendor keywords exist: **`x-cr-kind`**, which names the field type, and **`x-cr-currency`**, a per-field setting for `currency`. Five field types need neither — `date`, `datetime`, `email` and `url` ride on standard JSON Schema `format`, and `select` / `multi_select` on `enum`.

Combine annotations with the rest of your schema as usual — nullability especially:

```json
{
  "type": "object",
  "properties": {
    "total": { "type": ["number", "null"], "x-cr-kind": "currency", "x-cr-currency": "CAD" },
    "due_date": { "type": ["string", "null"], "format": "date" },
    "status": { "type": ["string", "null"], "enum": ["draft", "sent", "paid", null] }
  }
}
```

## What annotations change, and what they don't

**They are hints, not shape changers.** A `currency` value comes back as a number, not `{"amount": …, "currency": …}`. A `date` comes back as a string. A `multi_select` comes back as an array of strings. Strip every `x-cr-*` keyword from your schema and it validates the same responses it did before.

What they do change is **how the document is read**. Extraction knows that a `currency` field is money — so `$1,234.56` on the page becomes `1234.56` rather than a string — that a `date` field should come back as an ISO date, and that an `address` is one contiguous postal address rather than a line of prose. Where a document is genuinely ambiguous, the value is left exactly as written: `03/04/2026` has no reading that a schema can settle, so it comes back verbatim rather than guessed into the wrong month.

**Unknown field types are inert.** A `x-cr-kind` value the API doesn't recognize is ignored, never rejected — the field falls back to its declared base type. That is deliberate: new field types can appear without breaking a caller pinned to an older understanding, and a schema written today keeps working.

## Working within the schema dialect

Annotations don't loosen the [extraction schema dialect](/capabilities/extract/schema), which is checked first:

* **`select` must use `enum`.** `oneOf`, `anyOf`, `allOf`, `const` and `pattern` are rejected anywhere in the schema, so a choice expressed as `oneOf: [{ "const": "draft" }, …]` comes back as `400 invalid_schema`. The `enum` form above is the only encoding that passes.
* **Depth and size still cap out** at 5 levels and 64 KB. Annotations add keywords, not levels — every field type in the table is a scalar or an array of scalars.

## A full request

One call using seven of the field types:

```bash
curl -X POST https://api.cloudraker.com/v1/extract \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": { "url": "https://example.com/invoice.pdf", "name": "invoice.pdf" },
    "schema": {
      "type": "object",
      "properties": {
        "vendor_name": { "type": ["string", "null"] },
        "vendor_address": { "type": ["string", "null"], "x-cr-kind": "address" },
        "vendor_phone": { "type": ["string", "null"], "x-cr-kind": "phone" },
        "billing_email": { "type": ["string", "null"], "format": "email" },
        "invoice_date": { "type": ["string", "null"], "format": "date" },
        "total": { "type": ["number", "null"], "x-cr-kind": "currency", "x-cr-currency": "CAD" },
        "payment_terms": {
          "type": ["string", "null"],
          "enum": ["net_15", "net_30", "net_60", null]
        },
        "notes": { "type": ["string", "null"], "x-cr-kind": "long_text" }
      }
    }
  }'
```

The result is ordinary JSON — the annotations shaped how the values were read, not how they're returned:

```json
{
  "vendor_name": "Northwind Supply Co.",
  "vendor_address": "88 Rue Sainte-Catherine O, Montréal, QC H3B 1A9",
  "vendor_phone": "+1 514 555 0142",
  "billing_email": "ap@northwind.example",
  "invoice_date": "2026-03-04",
  "total": 1234.56,
  "payment_terms": "net_30",
  "notes": "Delivery scheduled in two shipments."
}
```

Citations work the same way as on any other field — see [extract](/capabilities/extract#example-response).

## The same vocabulary in the app

These annotations are what the CloudRaker schema builders read and write. A schema you send to the API opens in the in-app editor with the right control per field — a currency input, a date picker, a dropdown of your `enum` values — and a schema you build in the app exports with the same keywords. It's one vocabulary across the API and the product, so a saved [action](/capabilities/actions) is editable from either side.

An unannotated schema renders as it always has: `text`, `number`, `boolean`, `select` and `multi_select` carry no marker at all, because they're structurally identical to plain `string`, `number`, `boolean`, `enum` and array-of-`enum`.

## Next steps

#### [Extraction schema dialect](/capabilities/extract/schema)

The five rules your `schema` must satisfy, and what each rejection means.

#### [Extract](/capabilities/extract)

The endpoint, its configuration, and the response shape.