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

# Credit policy

> The frame the Platform fixes, the versions it and you publish, and the recorded act by which you adopt one.

A **Credit policy** is the set of rules an application is decided by: knockouts that settle it outright, a scorecard that awards points, and cutoff bands that turn the score into an outcome. The Platform ships content for its markets; you adopt a version of it, or author your own inside the same frame.

Three things are deliberately separate, and knowing which is which is most of understanding this surface.

| Thing | Who owns it | How it changes |
| - | - | - |
| The frame | The Platform, in code | A release |
| The content | The Platform ships **packs**; you publish your own versions | A release publishes the next pack version; you publish yours at the Console. No version is ever edited or dropped |
| The adoption | You | You state it per configuration, and the latest statement for a configuration governs |

A pack is a starting point rather than a ceiling. Reading one and publishing it back under your own name, with your own numbers, is the flow this surface is built for.

## The frame

The **frame** fixes what a policy can be made of. Content that steps outside it is not served, and the Platform refuses to start rather than decide under it.

A policy is made of three rule forms and reads a closed vocabulary of attributes.

| Form | What it does | What it may carry |
| - | - | - |
| Knockout | Compares one attribute against one bound and settles the application outright | `refuse`, `refer`, or `not_offered` where the rule says who the product is sold to; never an approval. A refusing knockout may carry a moratorium |
| Scorecard entry | Awards integer points for the bands of one attribute's values | Bands covering that attribute's whole domain, and points for each absent state it admits |
| Cutoff band | Names the outcome for a range of the score | An approval carries an exact annual rate and a principal ceiling; a refusal may carry a moratorium; a referral carries nothing; never `not_offered` — a score decides credit, a rule decides eligibility |

Every rule carries a stable identifier and a text. The identifier is what a support conversation, your own reporting and an eventual regulator quote, so it never names a different rule in a later version. The text belongs to the rule rather than to the screen that renders it, and it is copied into every decision's trace, which is what lets a refusal explain itself years later.

Identifiers are namespaced to whoever wrote the rule. Everything the Platform publishes carries `capcells:`; everything you publish carries your own tenancy identifier. Content lifted from a pack keeps the Platform's codes and is refused until you take authorship of them, the party that tuned the numbers is the author of what the rules now do.

### The vocabulary

A policy reads only attributes in the vocabulary, each with a name, a unit and bounds. An application carrying anything else is refused naming it: a value the Platform will not read is one you believe entered the decision and did not.

The vocabulary has two halves.

| Half | Who defines it | Who answers for it |
| - | - | - |
| The Platform's | The Platform, in code, the same for every tenancy | The Platform: every entry carries our written rationale and our verdict that reading it is permitted |
| Yours | You, at the Console, under your own namespace | You: every entry carries your rationale and the basis you state for reading it |

Attributes come in three kinds.

| Kind | Who supplies it | Example |
| - | - | - |
| Declared | You, in the application, the Platform's declared attributes and your own alike | `monthly_income_minor`, `capyplazo:shipping_name_mismatch` |
| Derived | The Platform, computed from declared values and the requested principal | `obligations_to_income_bps` |
| Read | The Platform, from a source you enabled | `rcc_worst_delay_periods` |

A derived or read attribute is the Platform's answer, and an application that states one is refused naming it.

<Info>
  Four attributes are read rather than declared: the `rcc_*` come from Círculo de Crédito's consumer report, under [the source you enable](/lending/circulo). There is no device signal, no e-mail, no postcode and no marketing channel in the Platform's half. Every other attribute is a fact you declare about a client you already have, one of ours, or one of your own.
</Info>

### Your attributes

A fact only you hold: whether the name on a shipment matched the name on the KYC file, a store's repeat-customer flag, a velocity count, a payroll confirmation, is one you declare and then read like any other. Read the whole vocabulary at `GET /v1/tenants/{tenant_id}/attributes`; it answers the Platform's half and yours, each marked.

You declare at the Console, as an administrator acting as a person: `PUT /v1/tenants/{tenant_id}/attribute-declarations/{local}` with the unit, the bounds, which absences a value may arrive in, how old a value may be, your rationale and the basis on which you hold that reading it is permissible. The attribute is available to your policies at once, spelled `{tenant_id}:{local}`.

| Rule | What it means |
| - | - |
| Only integers | A count, an amount, a ratio in basis points, a duration, or a flag that is 0 or 1. No text, no date, no identifier: the Platform holds no personal data, and a text attribute would be the channel it arrived through. Compute a name comparison on your side and declare the result |
| Checked for form, not for meaning | The same checks the Platform's own entries pass: a unit, bounds in order, absences from the two, a maximum age, both texts present. Nobody reviews what the attribute is for. You state it, and you answer for it |
| Refused by word | A name, a rationale or a basis containing a word from [the lexicon](#the-lexicon) is refused naming the word |
| Immutable | A declaration is never edited. A different bound is a different name: every version naming the attribute was validated against it as declared |
| Withdrawable, never deleted | `POST …/attribute-declarations/{local}/withdrawal` with a reason. A withdrawn attribute enters no new version; every version already published, every adoption and every decision keep reading it. A withdrawn name is not declared again |
| Bounded | 200 live declarations per tenancy; names of two to sixty-four lower-case letters, digits and underscores; texts of at most 2 000 characters |

A decision stating your attribute records it exactly as it records the Platform's: with its name, its state, its value, and the points it earned.

### The lexicon

The Platform publishes, at `GET /v1/tenants/{tenant_id}/attribute-lexicon`, the protected characteristics and sensitive-data categories it refuses a declaration by, sex, race, religion, nationality, disability, health, pregnancy, marital status, sexual orientation, genetic and biometric data, political and union membership, in English and Spanish. A declaration whose local name, rationale or basis contains one of these as a whole word is refused naming the word.

<Warning>
  It is a check on words and not a review of purpose. A declaration that paraphrases a category past the list has stated a rationale and a basis under your name, and you answer for both under the agreement. What the list buys is that the Platform never lends its frame to the obvious case, and can say which word it refused on.
</Warning>

### Value states

An attribute value is a **state** and, only where that state is `present`, a number.

| State | What it says |
| - | - |
| `present` | You hold the fact and state it |
| `not_applicable` | The client has no such fact, no employer beneath a months-of-employment attribute |
| `unavailable` | Nobody gathered it, or a source failed |

The frame says, per attribute, which of the two absences it admits, and a scorecard entry must band every one it admits. An entry silent about `unavailable` does not ignore that case: it would award whatever an unstated band awards, most often exactly when something has broken.

A derived attribute whose inputs permit no number answers `not_applicable`, never a number standing in for the absence. A ratio over an income of zero is not applicable; it is not zero, and it is not the largest value in the domain.

### Content rules

The Platform checks its own content before it serves, and refuses to start rather than decide under a policy with a hole in it.

| Check | What it refuses |
| - | - |
| Vocabulary | An attribute the frame does not define |
| Bounds | A band lying outside its attribute's bounds |
| Totality over values | A value in no scorecard band, or in two |
| Totality over states | An admitted state with no band, or a band for a state the attribute does not admit |
| Cutoff cover | A reachable score in no band, or in two |
| Terms | An approving band with no rate or a non-positive ceiling; a refusing or referring band carrying either |
| Eligibility | A cutoff band naming `not_offered` |
| Identifiers | A missing identifier or text, one used twice, or one outside the author's namespace |
| Discrimination | A knockout that fires for every value its attribute admits, or for none of them |

The last one is worth its own sentence. A knockout that fires on everything refuses every applicant; a knockout that can never fire is a control somebody believes is in force and is not. Both are the same defect, a rule whose truth does not depend on the applicant, and both are visible from the content alone.

## Versions

Content is published as versions numbered consecutively from 1, per policy. A published version is immutable, is stored whole rather than as a difference against its predecessor, and stays readable forever: a decision references the version it was decided under, and that reference resolves for the life of the decision.

Changed content is the next version. Nothing is edited in place, by you or by us.

A number past the next one is refused. A number skipped resolves to nothing for the life of every decision that would name it, and publishing is append-only, so it can never be filled.

### The digest

Every version carries a **digest**: a value derived from a canonical rendering of everything that decides under it, the attributes it reads with their bounds and admitted states, every knockout with its bound, every scorecard entry with its bands and points, and every cutoff band with its outcome, rate and ceiling.

A version number is a label somebody assigns; a digest is a fact about content, and only the second can be checked. Every decision records both.

<Warning>
  If the Platform ever started while its published content rendered to a digest other than the one recorded against that version, it would refuse to serve rather than decide under content that silently replaced what earlier decisions named.
</Warning>

## Adoption

**Adoption** is the recorded act by which you name, for one configuration, the version the applications naming it are decided under. Nothing is adopted by default or by silence.

* A configuration you have adopted nothing for has every application naming it refused, naming that nothing is adopted there.
* The latest adoption for a configuration governs the applications naming it decided after.
* A decision already recorded keeps the version it names, whatever you adopt afterwards.
* An adoption may state `enforce_bar: true`. Applications naming that configuration for a client a recorded refusal bars are then refused unrecorded rather than decided. See [Moratorium and bar](/lending/decisions#moratorium-and-bar).
* The adoptable set is the Platform's packs together with your own confirmed versions. Adopting anything else, a version past the end, a version of your own that nobody has confirmed, another tenancy's policy, a configuration you do not have, is refused naming it, and the adoption you already hold for that configuration still governs.

You hold one adoption per configuration, and one version may be adopted for several. That is the axis rather than a convenience: a policy's approving bands carry an exact annual rate, and that rate has to fall inside the rate corridor of the configuration each application names. A tenancy selling payday at 300% and instalment at 60% cannot judge both books by one policy, under a single adoption, one of the two products is refused for the corridor on every application.

Correcting an adoption is adopting again for the same configuration. No call answers any adoption but the current one, per configuration, and an adoption for one configuration never disturbs another's; what an earlier one governed is readable through the decisions that recorded it.

Adopting a live tenancy's policy is a person's act. An agent credential is refused it on a live tenancy and served it on a sandbox.

## Authoring

You publish policy versions of your own at the Console, inside the frame above and over your whole vocabulary, the Platform's attributes and your own. Three acts, and the platform stores only the last two.

<Steps titleSize="h3">
  <Step title="Validate">
    Post candidate content and read back every finding the publication would refuse on, or that it would publish and the digest it would publish under. Nothing is stored: no draft, no attempt, no partial state. Your working copy is yours.

    The findings are the whole list rather than the first thing wrong, in the version's own order.
  </Step>

  <Step title="Publish">
    The version is written with the person who published it, and is immutable from that moment. Stating the digest validation answered is how you publish exactly what you validated; the Platform checks the claim and refuses a mismatch.

    Publishing the same content twice under one number is a retry and answers what is already published. Different content under a taken number is refused.
  </Step>

  <Step title="Confirm">
    A second person records that they stand behind it, which is the whole of what makes the version adoptable. Nothing reviews the content a second time and the Platform could not.

    On a sandbox Tenancy the publisher may confirm their own version. See [one signature on a sandbox](#one-signature-on-a-sandbox).
  </Step>
</Steps>

Publishing and confirming require the `org:admin` role and a person. An agent credential validates and signs nothing, on a sandbox tenancy exactly as on a live one.

<Warning>
  On a live Tenancy the person who published a version cannot confirm it. A record of one person signing twice would assert something untrue.
</Warning>

A confirmation stands. There is no un-confirming: a tenancy that no longer wants a version governing adopts something else.

### One signature on a sandbox

Nothing on a sandbox Tenancy is owed to anybody, so one administrator can put a policy into force there alone.

| On a sandbox Tenancy | What happens |
| - | - |
| The publisher confirms their own version | Accepted. The version is adoptable |
| The confirmation reads back | `confirmed_by` names the publisher, and `self_confirmed` is `true` |
| A Decision is taken under that version | It carries `self_confirmed_version: true`, for its whole life |
| An agent confirms | Refused, as on a live Tenancy |

The mark exists so a sandbox Decision never reads as one a second person stood behind.

A sandbox confirmation reaches no live Tenancy. Versions belong to the Tenancy that published them. The same content published on your live Tenancy waits there for a second person.

These three are served at the Console door and nowhere else. The tenant API serves no route that publishes a policy, and never will: an API key proves a machine and no person, and what a policy does to an application is signed by named people.

## Limits

The refusals are stated rather than implied.

| You cannot | Instead |
| - | - |
| Edit or delete a version, yours or a pack's | Publish the next version and adopt it |
| Take the name of a policy the Platform publishes | Choose another name. One name cannot mean two sets of rules |
| Put a version into force alone on a live Tenancy | Have a second person confirm it. On a sandbox Tenancy your own confirmation is enough, and is marked |
| Change the Platform's half of the vocabulary | Declare your own attribute instead. The Platform's entries are read for every tenancy and are the Platform's to answer for |
| Declare a text, a date or an identifier | Turn the fact into a number on your side and declare that. The Platform holds no personal data |
| Edit a declaration | Declare a new name. The old one stays readable by everything that names it |
| Disable one rule | Adopt a version that does not carry it. There is no configuration value, environment value or deployment setting that adds a rule, removes one or suppresses one |
| Read an adoption other than the current one for a configuration | Read the decisions, each of which names the version it was decided under |
| Adopt one version for a whole tenancy | Adopt it for each configuration. The same version may be adopted for every one of them |


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