> 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 the value *is*. `{"type": "number"}` could be a quantity or an amount of money. `{"type": "string"}` could be a paragraph, a phone number, or a mailing address. An annotation helps extraction read the field. It also makes the in-app editors render the field correctly.

Annotations are **optional**. A schema with none behaves exactly as before. Every annotated schema is still plain, valid JSON Schema. It uses standard `format` where one exists, and `x-cr-*` vendor keywords for the rest. A validator that does not know `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`** names the field type. **`x-cr-currency`** is a per-field setting for `currency`. Six field types need neither: `date`, `datetime`, `email`, and `url` use standard JSON Schema `format`, and `select` / `multi_select` use `enum`.

Combine annotations with the rest of your schema as usual. Nullability is the common case:

```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 as before.

Annotations change **how extraction reads the document**. Extraction knows that a `currency` field is money. So `$1,234.56` on the page becomes `1234.56`, not a string. A `date` field comes back as an ISO date. An `address` is one contiguous postal address, not a line of prose. Where a document is ambiguous, extraction keeps the value exactly as written. `03/04/2026` has no reading that a schema can settle, so it comes back verbatim, not guessed into the wrong month.

**Unknown field types are inert.** The API ignores an `x-cr-kind` value it does not recognize. It never rejects one. The field falls back to its declared base type. This is deliberate. New field types can appear without a break for callers pinned to an older understanding. A schema you write today keeps working.

## Working within the schema dialect

Annotations do not loosen the [extraction schema dialect](/paperwork/capabilities/extract/schema). The API checks the dialect first:

* **`select` must use `enum`.** The API rejects `oneOf`, `anyOf`, `allOf`, `const`, and `pattern` anywhere in the schema. 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 caps still apply**: 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 uses 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 extraction read the values, not how the API returns them:

```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](/paperwork/capabilities/extract#example-response).

## The same vocabulary in the app

The CloudRaker schema builders read and write these annotations. A schema you send to the API opens in the in-app editor with the correct control per field: a currency input, a date picker, or a dropdown of your `enum` values. A schema you build in the app exports with the same keywords. One vocabulary covers the API and the product. You can edit a saved [config](/paperwork/capabilities/actions) from either side.

An unannotated schema renders as it always has. `text`, `number`, `boolean`, `select`, and `multi_select` carry no marker, because they are 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.