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

# Determinations

> Read the signed determination and its evidence package for any of your policies.

A **determination** is MicroCrop's signed, independently verifiable answer to one
question: did the parametric trigger fire for this policy, and by how much? It is
hashed over a chain-neutral, currency-neutral canonical body, signed off-chain, and
anchored by a notary. The **evidence package** is the self-contained artifact a
regulator or a reinsurer can re-verify without any MicroCrop access at all.

Determinations are produced for **every** policy, on both service tiers:

| Service tier                   | MicroCrop determines | MicroCrop settles the farmer                                  |
| ------------------------------ | -------------------- | ------------------------------------------------------------- |
| `DETERMINATION`                | Yes                  | **No** — you settle, off-platform, off your own balance sheet |
| `DETERMINATION_AND_SETTLEMENT` | Yes                  | Yes                                                           |

## Endpoints

All three require the `determination:read` capability. Your organization API key
(`x-api-key`) has it.

```bash theme={null}
GET /api/determinations
GET /api/determinations/{determinationId}
GET /api/determinations/{determinationId}/evidence
GET /api/determinations/{determinationId}/evidence?download=1
```

Under the `DETERMINATION` tier there are two more, covered in
[Telling us what you paid](#telling-us-what-you-paid):

```bash theme={null}
POST /api/determinations/{determinationId}/settlement-report
GET  /api/determinations/{determinationId}/settlement-report
```

List filters: `page`, `limit` (max 100), `status`, `kind`, `policyId`.

```bash theme={null}
curl "https://app.microcrop.app/api/determinations?policyId=$POLICY_ID" \
  -H "x-api-key: $KEY"
```

You only ever see determinations for **your own** policies. A determination
belonging to another organization returns `404 NOT_FOUND` — identical to an id that
does not exist, so the endpoint never confirms that someone else's id is real.

## Response — three facts, never collapsed into one status

A determination answers three separate questions, and merging them is how integrations
go wrong. The response keeps them as three sibling objects:

<CodeGroup>
  ```json Tier 1 — DETERMINATION theme={null}
  {
    "success": true,
    "data": {
      "id": "b1f0c8e2-3f21-4b1a-9a77-2c9f0a5d1e44",
      "policy": {
        "id": "44444444-4444-4444-4444-444444444444",
        "policyNumber": "MC-KE-2026-000123",
        "sumInsured": "100000.00",
        "currency": "KES",
        "coverageType": "DROUGHT",
        "settlementMode": "DETERMINATION"
      },

      "determined": {
        "kind": "CROP_DAMAGE",
        "schemaVersion": "1.0",
        "methodologyVersion": "crop-dualindex-1.0",
        "unitCode": null,
        "triggered": true,
        "thresholdBp": 1000,
        "damagePercentBp": 1650,
        "assessedAt": "2026-09-02T00:00:00.000Z",
        "determinedAt": "2026-09-02T06:14:22.101Z",
        "canonicalHash": "5e2151a6…",
        "signerAddress": "0x3f9a…",
        "notary": { "provider": "stellar", "reference": "GBX…", "anchoredAt": "…", "txHash": "9c2f…" },
        "evidence": {
          "available": true,
          "href": "/api/determinations/b1f0c8e2-…/evidence",
          "verifiable": true
        }
      },

      "settlement": {
        "mode": "DETERMINATION",
        "settledByMicrocrop": false,
        "status": "NOT_SETTLED_BY_MICROCROP",
        "reason": "This policy was sold under the DETERMINATION service tier. …",
        "amountOwed": {
          "amountMinor": "1650000",
          "amount": "16500.00",
          "currency": "KES",
          "exponent": 2,
          "damagePercentBp": 1650,
          "basis": "policy.sumInsured × damagePercentBp / 10000, truncated to the minor unit"
        }
      },

      "partnerReport": {
        "status": "NOT_REPORTED",
        "attestedByPartner": false,
        "verifiedByMicrocrop": false,
        "reportedAt": null,
        "reference": null,
        "amount": null,
        "note": "MicroCrop has received no settlement report for this determination. …"
      }
    }
  }
  ```

  ```json Tier 2 — DETERMINATION_AND_SETTLEMENT theme={null}
  {
    "settlement": {
      "mode": "DETERMINATION_AND_SETTLEMENT",
      "settledByMicrocrop": true,
      "status": "SETTLEMENT_SUBMITTED_ON_CHAIN",
      "reason": null,
      "amountOwed": { "amountMinor": "1650000", "amount": "16500.00", "currency": "KES", "exponent": 2 },
      "failureReason": null,
      "onChain": {
        "chainId": 8453,
        "verifyingContract": "0x…",
        "submittedTxHash": "0x…",
        "blockNumber": "12345678",
        "payoutAmountUsdc": "126923076"
      }
    },
    "partnerReport": { "status": "NOT_APPLICABLE", "…": "…" }
  }
  ```
</CodeGroup>

* **`determined`** — what MicroCrop determined. Signed, hashed, anchored, and
  independently verifiable from the evidence package.
* **`settlement`** — whether MicroCrop settled. On the `DETERMINATION` tier it states
  explicitly that MicroCrop **deliberately did not** settle, and what the policy owes.
* **`partnerReport`** — what *you* tell MicroCrop happened. Always labelled
  partner-attested and **not verified** by MicroCrop. Never merged into `settlement`.

`settlement.status` values: `NOT_SETTLED_BY_MICROCROP`, `NO_PAYOUT_DUE` (Tier 1) and
`SETTLEMENT_PENDING`, `SETTLEMENT_IN_PROGRESS`, `SETTLEMENT_SUBMITTED_ON_CHAIN`,
`SETTLEMENT_BLOCKED_UNDERFUNDED`, `SETTLEMENT_FAILED` (Tier 2).

## `amountOwed` — your currency, no exchange rate

On the `DETERMINATION` tier you settle the farmer yourself, in local currency. So the
amount is **derived from the policy you sold**, not converted from any crypto figure:

```
amountOwedMinor = (sumInsuredMinor × damagePercentBp) / 10000     — integer, truncated
```

with `sumInsuredMinor` being `policy.sumInsured` in minor units of `policy.currency`.

* `amountMinor` is authoritative and is a **decimal string** in minor units
  (`"1650000"` = 16,500.00 KES). `amount` is a human convenience string. Neither is
  ever a JSON number.
* Multiplication happens **before** division, and the result is **truncated toward
  zero** — never rounded up. The rule is stated in `basis` so you can reproduce the
  figure byte-for-byte in any language.
* There is **no FX call** in this path and no USDC anywhere in a `DETERMINATION`-tier
  response.
* If `policy.currency` has no registered minor-unit exponent, `amountOwed` is `null`
  and `amountOwedUnavailableReason` explains why. MicroCrop will not guess a scale for
  a monetary obligation.

`triggered` is reported separately from the amount. When a determination measures
damage below the methodology's `thresholdBp`, `triggered` is `false`, `amountOwed` is
zero, and `settlement.status` is `NO_PAYOUT_DUE` — the determination itself succeeded.

## Evidence package

```bash theme={null}
curl "https://app.microcrop.app/api/determinations/$DET_ID/evidence" \
  -H "x-api-key: $KEY"
```

Returns the signed canonical body, its hash, signature and signer, the source
provenance you can re-fetch to rebuild the index inputs yourself, the linked policy,
the notary anchor receipt, and the package's own verification result. Add
`?download=1` to receive it as a file attachment.

The package is chain-neutral and currency-neutral by construction: it contains no USDC
amount and no chain domain, in either tier. Verify it independently by recomputing the
SHA-256 of the canonical body (RFC 8785 / JCS subset, minified UTF-8, keys sorted) and
recovering the signer from the signature over that hash.

## Telling us what you paid

Under the `DETERMINATION` tier **you** settle the farmer, off-platform and off your own
balance sheet. MicroCrop never moves that money and never sees it. This endpoint is how
you put your own statement of what happened next to our determination, so the record is
complete for your regulator and your reinsurer.

```bash theme={null}
POST /api/determinations/{determinationId}/settlement-report
GET  /api/determinations/{determinationId}/settlement-report
```

`POST` requires the `settlement:report` capability; `GET` requires `determination:read`.

It is only available on policies sold under `DETERMINATION`. Reporting against a policy
MicroCrop settles itself returns `403 NOT_PARTNER_SETTLED` — there the `Payout` record is
the authoritative settlement fact and an unverified claim must not sit beside it.

```bash theme={null}
curl -X POST "https://app.microcrop.app/api/determinations/$DET_ID/settlement-report" \
  -H "x-api-key: $KEY" -H "content-type: application/json" \
  -d '{
    "partnerReference": "QK73HG9XYZ",
    "outcome": "SETTLED_FULL",
    "method": "MOBILE_MONEY",
    "settledAmountMinor": "1650000",
    "settlementCurrency": "KES",
    "settledAt": "2026-09-02T09:14:00Z",
    "attestingOfficerName": "A. Officer",
    "attestingOfficerTitle": "Head of Claims"
  }'
```

| Field                            | Notes                                                                                                                                                                                                                                               |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `partnerReference`               | **Your** settlement reference — M-Pesa code, bank reference, receipt number. Together with the determination id it is the **idempotency key**: resending it returns the stored report unchanged, with `replayed: true`. Make it stable per payment. |
| `outcome`                        | `SETTLED_FULL`, `SETTLED_PARTIAL` (needs `shortfallReason`) or `DECLINED` (needs `declineReason` and amount `"0"`).                                                                                                                                 |
| `method`                         | `MOBILE_MONEY`, `BANK_TRANSFER`, `CASH`, `ACCOUNT_CREDIT`, `IN_KIND`, `OTHER`.                                                                                                                                                                      |
| `settledAmountMinor`             | Minor units, as a **canonical decimal string** — no sign, no decimal point, no exponent, no leading zeros. A JSON number is an IEEE-754 double and would lose precision on a large KES or GHS amount.                                               |
| `settlementCurrency`             | Must equal the policy's own currency. MicroCrop does **not** convert on this path.                                                                                                                                                                  |
| `attestingOfficerName` / `Title` | Who at your organization is making the statement. Required for a decline too.                                                                                                                                                                       |
| `evidenceRef` / `evidenceHash`   | Optional pointers to your own receipt. We never fetch or validate them.                                                                                                                                                                             |

<Warning>
  **We never verify these.** `verificationStatus` is structurally one-valued
  (`UNVERIFIED`) and every response restates `verifiedByMicrocrop: false`. The report is
  your statement, stored and echoed back — it is never presented as a MicroCrop fact.
</Warning>

### Bounds we do enforce

* **Never more than we determined.** A single report cannot exceed the `amountOwed`, and
  neither can the **sum of all live reports** on a determination. Instalments are fine —
  two partial reports that add up to the amount owed are accepted; a second full one is
  not.
* `settledAt` cannot be in the future, and cannot precede the determination itself.

### Corrections

Reports are **append-only**. Nothing is ever edited. To correct one, POST a new report
with a **new** `partnerReference` and `supersedesReportId` set to the id of the report it
replaces. The old row is stamped (`supersededAt`, `supersededByReportId`) with every value
it was attested with intact, and the whole chain stays visible on `GET`. Each new report —
corrections included — emits `determination.settlement_report_recorded` with
`correction: true`, so your subscribers can replace rather than append.

### The reporting window

When a Tier 1 determination triggers and something is owed, it is stamped
`AWAITING_PARTNER_REPORT` with a due date (30 days by default; the operator sets
`PARTNER_SETTLEMENT_REPORT_DUE_DAYS`). The due date is frozen at issue, so changing the
setting never re-ages determinations already issued. If nothing arrives by then the
determination becomes `OVERDUE` and
[`determination.settlement_report_overdue`](/guides/webhooks) fires once.

A determination that did not trigger, or that owes zero, creates **no** reporting duty and
is never chased.

<Note>
  `OVERDUE` is a **reporting** state and nothing more. MicroCrop did not settle the policy,
  owes nothing on it, and has moved no money.
</Note>

## Getting notified

Rather than polling, subscribe to the [`determination.delivered`](/guides/webhooks)
webhook. It fires once per determination and carries the same `amountOwed` block.
[`determination.settlement_report_recorded`](/guides/webhooks) and
[`determination.settlement_report_overdue`](/guides/webhooks) track the Tier 1 reporting
state above.
