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

# Tags and tag values

> How extracted lease terms are structured: categories, typed values, schedules, options, and amendment chains

A **tag** (`DocTag`) is one extracted lease term — a rent amount, a renewal option, a commencement date — anchored to the exact place in a document it came from. Tags are the payoff of Prophia's document processing: ask a lease for [its tags](https://docs.prophia.com/api-reference/v2/leases/list-tag.md) and you get the abstracted deal terms with citations.

```bash theme={null}
curl "https://api.prophia.com/rest/v2/accounts/{accountId}/leases/{leaseId}/tags?include=applicableSpaces" \
  -H "X-API-Key: <your-api-key>"
```

For the complete list of terms Prophia captures — every `tagName`, the units it can carry, and what its `customValue` fields hold — see the [tag reference](https://docs.prophia.com/api-reference/v2/concepts/tag-reference.md).

## Three unrelated "custom" things

Three features share the word *custom*. They have nothing to do with each other:

| Term | What it is | Where |
| - | - | - |
| **Custom terms** | Account-level *definitions* of extra term types your team tracks beyond Prophia's standard set | `GET /rest/v2/accounts/{accountId}/custom-terms` |
| **Custom tags** | Tag *instances* of those definitions — ordinary tags with `isCustomTag: true` | Any tag endpoint; filter with `isCustomTag` |
| **`customValue1`–`customValue6`** | Positional extra fields that appear on *any* tag, custom or not | Fields on the tag object (see below) |

## Categories

`category` tells you how much structure to expect:

| Category | Meaning |
| - | - |
| `STANDARD` | A single captured value — read `value`, and `schedule` when the term is a series. |
| `COMPLEX` | An option or right (renewal, termination, expansion…) — the substance lives in `tagComponents`. |
| `EXHIBIT` | A reference to exhibit material in the document. |

## Typed values: branch on `kind`

`value` is polymorphic. Every shape carries a `kind` discriminator plus the common fields `unit`, `capturedData` (the value as captured, as text) and `ocrText` (the raw source text). Empty fields are omitted.

| `kind` | Payload | Produced when the value was captured… |
| - | - | - |
| `money` | `value` (decimal **string**) + `currency` | as a number with a unit starting with `$` |
| `percent` | `value` (JSON number) | as a number with a unit starting with `%` |
| `number` | `value` (JSON number) | as any other number — read `unit` for what it counts |
| `date` | `value` (`yyyy-MM-dd`) | as a date |
| `dateRange` | `start`, `end` (`yyyy-MM-dd`) | with unit `range of dates` |
| `numberRange` | `start`, `end` (integers) | with any other `range of …` unit |
| `text` | `value` | as free text, or anything else — the fallback kind |

> [!WARNING]
>
> **Money values are decimal strings, not JSON numbers** — `"value": "120000.00"` — to preserve cent precision. Parse them as decimals, never as floats.

> [!NOTE]
>
> **`kind` alone is not enough — always read `unit` too.** A single `number` covers durations, areas and plain counts, and only `unit` separates them. And because the kind follows the captured unit rather than the term, the same `tagName` can hand you `money` on one lease and `percent` or `text` on another: `rentBump` and `opexCap` accept both dollar and percent units, and a rental rate captured as `FMV` or `landlordDefined` comes back as `text`.
>
> A `percent` value carries the percentage itself, so `3.5` means three and a half percent.

**Typed fields are best-effort.** They are populated by parsing `capturedData`, so a typed field is *omitted* when the captured text couldn't be parsed into that kind — common for dates a lease states in relative terms ("ninety days after substantial completion"). `capturedData` always holds the raw text, and it is the fallback whenever a typed field is missing.

> [accordion] Example: money
>
> ```json theme={null}
> { "kind": "money", "value": "8250.00", "currency": "USD", "capturedData": "$8,250.00" }
> ```

> [accordion] Example: percent
>
> ```json theme={null}
> { "kind": "percent", "value": 6, "unit": "%", "capturedData": "6", "ocrText": "six percent (6%)" }
> ```
>
> `value` is the percentage itself — six percent, not `0.06`.

> [accordion] Example: a rental rate captured as FMV
>
> ```json theme={null}
> { "kind": "text", "value": "FMV", "unit": "FMV", "ocrText": "Fair Market Rental Rate" }
> ```
>
> Stored as free text, so it arrives as `text` despite sitting on a field you might expect to be money.

> [accordion] Example: date that could not be parsed
>
> ```json theme={null}
> { "kind": "date", "capturedData": "90 days after substantial completion" }
> ```
>
> No `value` — only `capturedData`.

## Space-dependent and space-independent tags

Every term is defined as either **space-dependent** or **space-independent**, and this decides how the lease's tag list is assembled.

* **Space-dependent** terms are consolidated *per space*. Square footage, rent schedules, renewals, early terminations — each space the lease occupies can carry its own value. In the flattened list you get back, the same `tagName` can therefore appear **more than once**, once per space, with different values and different `applicableSpaces`.
* **Space-independent** terms are consolidated *per term name*, one value for the whole lease. Tenant legal name, effective date, exclusive use, permitted use.

In a lease's consolidated `tags` (`include=tags` on a lease), each tag appears once, with the spaces it wins in the consolidation:

* A space-independent tag has no `applicableSpaces`. It applies to the lease, not to a particular suite.
* A space-dependent tag lists the spaces it applies to. A term captured without any spaces applies to every space, so it lists all of them.
* Rent schedules, and the monthly and annual rents derived from them, can be consolidated differently per space. When that happens the same tag `id` appears once per space group, each copy with its own values and `applicableSpaces`.

Lease-level values that summarize every space, such as the lease's commencement and expiration dates and its total square footage, are on the lease's top-level fields (`commenceDate`, `expirationDate`, `squareFootage`, `suiteNumber`), not in `tags`.

> [!NOTE]
>
> Keying a client-side map on `tagName` alone will silently drop values for a multi-space lease. Key on `tagName` + `applicableSpaces` for space-dependent terms. The [tag reference](https://docs.prophia.com/api-reference/v2/concepts/tag-reference.md) marks which terms are which.

Request [`include=applicableSpaces`](https://docs.prophia.com/api-reference/v2/concepts/includes) to see which spaces a tag applies to. See [Spaces and encumbrances](https://docs.prophia.com/api-reference/v2/concepts/spaces-and-encumbrances.md) for how those entries match your space inventory.

## `customValue1`–`customValue6`: positional and tag-dependent

These six string fields mean **different things on different tags** — the position, not the name, carries the meaning. Some encode a whole multi-period schedule as `:-:`-delimited parallel arrays.

| Tag | Field | Holds |
| - | - | - |
| `rentAbatement`, `opexAbatement`, `taxAbatement` | `customValue1`–`4` | Parallel `:-:`-delimited arrays, one token per abatement period: period unit, discount unit, duration, amount |
| `rentAbatement` | `customValue5` | `:-:`-delimited `1`/`0` per period — whether opex and tax are included in the abated amount |
| `opexCap` | `customValue1`–`3` | `"varies"` / `"does not vary"`, then `:-:`-delimited years and amounts when it varies |
| `percentageRent` | `customValue1` | `"true"` when the rate applies against minimum rent (no breakpoints), `"false"` when breakpoints are given |
| `securityDeposit`, `letterOfCreditAmount` | `customValue1` | The reduced amount after the refund schedule is applied |
| `securityDepositRefundSchedule`, `letterOfCreditRefundSchedule` | `customValue1` | `"appliesToBaseRent"` when the reduction can be credited toward base rent |
| `prepaidRent` | `customValue1`, `customValue5` | Whether opex is included; the interval when structured as recurring rather than a lump sum |
| `tiRent`, `bsacRent` (GSA) | `customValue1`–`6` | How the rent period is expressed, its duration, and any delay |
| `rentSchedule`, `fee` | `customValue1` | Your MRI income category for the charge |
| `suiteNumber` | `customValue1` | The primary suite when several are selected |

> [!WARNING]
>
> Never interpret a `customValue` without knowing which `tagName` it belongs to. Treat undocumented combinations as opaque — they are not guaranteed to mean anything.

## Schedules

Tags whose value is a series carry a `schedule` of `{kind, entries}`. Branch on `kind`, which determines the entry shape: `RENT`, `PERCENT_RENT`, `ABATEMENT`, `REFUND`, or `FEE`.

Every entry has a 0-indexed `sequence`, and every entry except `REFUND` is bounded **either** by calendar dates (`startDate`/`endDate`) **or** by 1-indexed months from lease commencement (`startMonth`/`endMonth`, where month 1 is the commencement month) — whichever way the lease states it. Handle both.

* **`RENT`** — `baseRent` plus any fixed taxes, opex, and parking for the step, and `squareFootage` when the lease states rent per step against a changing premises size. The GSA-only fields (`fixedParking`, `annualTiRent`, `annualBsacRent`, `cpiIncreaseAmount`) are null on every other lease type.
* **`PERCENT_RENT`** — `percent` plus the sales `breakpoint` above which it applies, and `breakpointTerm` for breakpoints the lease states in prose.
* **`ABATEMENT`** — the `amount` abated per period, and `includesTaxAndOpex`.
* **`FEE`** — a recurring charge's `amount` per step.
* **`REFUND`** — a deposit or letter-of-credit burn-down. Dated by `effectiveDate`, derived from `unitType`/`unitValue` (months or years from commencement, or a date).

> [!WARNING]
>
> On a `REFUND` entry, **read `refundType` before `amount`** — it changes what the number means:
>
> | `refundType` | `amount` is |
> | - | - |
> | `TO` | The balance that **remains** after this step |
> | `BY` | The **size of the reduction** applied at this step |
>
> `reducedAmount` saves you the arithmetic: it is the deposit as it stands at that step, with every reduction up to and including it applied.

## Complex tags: components and rights

For `COMPLEX` tags, the substance is in `tagComponents` — polymorphic on its own `kind`: `RENEWAL`, `EARLY_TERMINATION`, `EXPANSION`, `CONTRACTION`, `RIGHT_OF_FIRST_REFUSAL`, `RIGHT_OF_FIRST_OFFER`, `PURCHASE`, `AUTO_RENEWAL`, `TENANT_IMPROVEMENT`, `FEE`, or `OTHER`.

All components share `rightStatus`, `effectiveDateOfRight`, `clause`, `customLabel`, an optional `amendingTag`, and `componentTags` (refs to the constituent tags the component was assembled from, keyed by component field). Each kind then adds its own:

| Kind | Adds |
| - | - |
| `RENEWAL` | `renewalPeriodTerm`, `numberOfAdditionalPeriods`, `advancedNoticePeriod`, `acceptancePeriod`, `rentalRate` |
| `AUTO_RENEWAL` | `autoRenewalTerm`, `autoRenewalPeriods`, `autoRenewalRate`, `autoRenewalRateBump`, and an `advancedNoticePeriod` that is the notice to **opt out**, not to exercise |
| `EARLY_TERMINATION` | `terminationFee`, `optionEndDate`, `earlyMoveOutDate`, `advancedNoticePeriod` |
| `CONTRACTION` | `contractionFee`, `contractionSpace`, `optionEndDate`, `earlyMoveOutDate` |
| `EXPANSION` | `expansionSpace`, `rentalRate`, `expirationDate` |
| `RIGHT_OF_FIRST_OFFER` | `offeredSpace`, `rentalRate`, `acceptancePeriod`, `expirationDateOfRight`, `oneTimeOrOngoing` |
| `RIGHT_OF_FIRST_REFUSAL` | `refusalSpace`, `rentalRate`, `acceptancePeriod`, `expirationDateOfRight`, `oneTimeOrOngoing` |
| `TENANT_IMPROVEMENT` | `tiAmount`, `tiRemaining`, `tiSunset` |
| `FEE` | `feeAmount`, `feeTerm`, `feeIncrease`, `encumberedSpaces` |
| `PURCHASE` | `advancedNoticePeriod` |
| `OTHER` | `encumberedSpaces` — everything else lives in `clause` and `componentTags` |

Where a deadline is stated in relative terms rather than as a parseable date, the date field is null and a paired `…Text` field carries the source wording (`expirationDateText`, `expirationDateOfRightText`).

The space-naming fields — `expansionSpace`, `contractionSpace`, `offeredSpace`, `refusalSpace`, `encumberedSpaces` — use the same shape and the same suite-name matching as a tag's `applicableSpaces`. See [Spaces and encumbrances](https://docs.prophia.com/api-reference/v2/concepts/spaces-and-encumbrances.md).

## Two status enums that are not the same thing

| | `lifecycleStatus` (on the tag) | `rightStatus` (on a component) |
| - | - | - |
| Tracks | The **tag record** across the lease's document history | The **option/right** the component describes |
| Values | `ACTIVE` (in force), `VOID` (superseded/withdrawn), `STRICKEN` (removed, commonly via amendment), `EXERCISED` (option taken) | `AVAILABLE` (still exercisable), `EXERCISED`, `STRICKEN`, `DECLINED` (tenant declined), `EXPIRED` (window passed unused), `UNKNOWN` (no status could be resolved) |

The two are **orthogonal, independently-resolved signals** — they can disagree, and neither overrides the other. A tag can be `lifecycleStatus: ACTIVE` while its component's right is `EXPIRED`.

## Amendment chains

Amendment chains track an **option**, not a lease. Every option carries a `referenceId`, and options that belong to the same chain share it. That shared key is what `amendingTag` exposes.

`amendingTag` resolves to different things depending on what carries it:

| On a… | `amendedTagId` points at |
| - | - |
| Option tag | The **earlier iteration of the same option chain** — the version in a prior document that this one amends |
| Component tag | The **parent option container** the component belongs to |

```mermaid theme={null}
flowchart TB
    subgraph chainA["Chain A — the 5-year renewal"]
        direction TB
        A1["<b>renewal</b> · original lease<br/>referenceId = A<br/><i>self-referencing — no amendingTag</i>"]
        A2["<b>renewal</b> · 1st amendment<br/>amendingTag.amendedTagId → A1"]
        A3["<b>renewal</b> · 3rd amendment<br/>amendingTag.amendedTagId → A2"]
        A1 --> A2 --> A3
    end
    subgraph chainB["Chain B — a new expansion right"]
        direction TB
        B1["<b>expansion</b> · 2nd amendment<br/>referenceId = B<br/><i>starts its own chain</i>"]
    end
```

Three consequences worth designing around:

1. **The pointer runs backwards.** `amendingTag.amendedTagId` is the id of the *earlier* tag. To find the current state of an option, start from the tag no other tag points at.
2. **`amendingTag.effectiveDate` is the *referenced* tag's effective date**, not this tag's. For when the current version takes effect, read the component's own `effectiveDateOfRight`.
3. **`amendingTag` is omitted on the first option in a chain**, which is stored as self-referencing. Its absence means "chain start", not "no chain".

A single amendment can start a new chain, amend an existing one, or do both — and a lease commonly runs several chains in parallel. `customLabel` is the human-readable name of the family ("Option 1 — 5 Year Renewal"); options sharing a `referenceId` should share a `customLabel`, so it is a useful grouping key when presenting chains to a user.

Superseded tags typically carry `lifecycleStatus: VOID` or `STRICKEN`, but treat that as corroboration rather than the primary signal — walk the chain.

## Citations: `tagSelections` and `pages`

With [`include=tagSelections,pages`](https://docs.prophia.com/api-reference/v2/concepts/includes), a tag brings its provenance: `tagSelections` are rectangles on document pages, and `pages` the geometry of those pages.

Bounding boxes are expressed in **basis points of page dimensions** — each axis runs 0–10,000 where 10,000 is 100% of the page's width or height, origin top-left. To place a box on a rendered page image:

```
pixel_x = box.x * page.width / 10000
```

and likewise for `y`, `width`, and `height`.


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