Skip to main content
This is the core of what MicroCrop sells. A determination is not “our system says so” — it is an artifact you, your regulator, your reinsurer or a hostile counterparty can check offline, in any language, with our servers switched off. This page tells you exactly how, and gives you a runnable reproducer and a pinned conformance vector to test it against.

What you are checking

Three claims, in order. Each is independently falsifiable:
1

The body is what was signed

Re-serialize the canonical body under the rules below and SHA-256 it. If your digest equals canonical.hash, the body has not been altered by so much as a byte since signing.
2

MicroCrop signed it

Recover the secp256k1 signer from canonical.signature over that digest. If it equals canonical.signer — and that address is the signer MicroCrop published to you out of band — the determination is ours.
3

It predates the dispute

If notary is present, confirm the anchor transaction on the notary ledger. It commits the same hash at a time nobody can move.
None of these require calling MicroCrop. Steps 1 and 2 require no network at all.

Get the artifact

Ignore data.verification. It is MicroCrop’s own claim about MicroCrop’s own artifact. It is there for convenience; it is worth nothing as evidence. Compute your own.
If canonical is null, the record is a legacy EVM-only determination and cannot be independently re-verified this way — verification.available will be false with a reason. Any determination issued under the current schema carries a canonical block, and the API’s determined.evidence.verifiable flag tells you before you fetch.

The canonical form

The body is serialized under a deliberately strict, portable subset of RFC 8785 (JCS). The subset exists so that two independent implementations cannot disagree: The body additionally carries no chain domain and no USDC amountdomain, chainId, verifyingContract, and any key ending in usdc are structurally forbidden anywhere in the tree. Assert that yourself: a determination that names a chain or a settlement currency is not the artifact you were sold.

The signature

The signer signs the 32-byte SHA-256 digest as a raw digest — there is no EIP-191 \x19Ethereum Signed Message prefix and no EIP-712 domain. So recovery is exactly:
In ethers.js that is recoverAddress("0x" + hash, signature). The result is a checksummed address; compare case-insensitively.

Conformance vector

Pin this in your own test suite. If your implementation reproduces it byte-for-byte, it agrees with ours.
Note what the canonical bytes show: assessedAt first and subject last, because the keys are sorted — not the order they appear in the body above. Inside provenance, the embedded JSON in paramsJson is a string, escaped as one; it is not re-canonicalized.
Key ordering is a plain lexicographic sort over the key strings. JavaScript sorts by UTF-16 code unit and Python by Unicode code point; these differ only for characters outside the Basic Multilingual Plane. Every key in the MicroCrop schema is ASCII, so the two agree — but if you extend the schema, keep keys ASCII.

Runnable reproducer

Node 18+ and npm i ethers. This is the whole verifier — about 50 lines, no MicroCrop dependency, no network:
verify-determination.mjs

Test it against the vector

Save this as vector.json and run the reproducer on it. It is signed with a public, well-known test key — it is a conformance fixture, not a MicroCrop determination, and the signer address below is deliberately not one of ours:
vector.json
Then prove the check bites: change "4500" to "4501" and re-run. The hash comparison must fail. If it passes, your canonicalizer is wrong.

The hash check in other languages

Step 1 needs only a JSON parser and SHA-256 — no crypto library, no dependencies:
Check isinstance(v, bool) before any numeric branch in Python — bool is a subclass of int. And note that Python’s json.load will happily parse a raw number into the body; the canonicalizer above correctly refuses it, which is the behaviour you want. A body containing a raw number is not a valid canonical body.
For step 2 in Python, recover with eth_keys or coincurve over the same 32-byte digest — again with no message prefix.

Verifying the amount owed

The amount is derived, not asserted, so you can reproduce it from the policy you yourself sold:
  • sumInsuredMinor is policy.sumInsured in minor units of policy.currency (KES and GHS have exponent 2, so KES 100,000.00 → 10000000).
  • Multiply before dividing, and use integer arithmetic throughout — a BigInt, a Decimal, an int, never a float.
  • Truncate toward zero. Never round half-up; there is no tie-break rule to get wrong.
The signed canonical body carries the oracle’s own local-currency result.payoutAmount.amountMinor. Your derivation, the API’s settlement.amountOwed and that signed figure should all agree. If the API’s derived figure disagrees with the signed one, the response carries settlement.amountOwedDiscrepancy and you should stop and reconcile before paying anyone.

What verification does and does not establish

It establishes that the determination body has not been altered since signing, that it was signed by the key MicroCrop published, that the inputs and their source are named, and — with the notary anchor — that it existed at a stated time. It does not establish that the underlying weather data is correct, that the methodology is appropriate for the risk, or that the amount is legally owed to the farmer. Those are questions about the source, the product design, and your contract respectively. The provenance block is what lets you attack the first of those on your own terms: re-fetch provenance.url, apply provenance.paramsJson, recompute the index, and compare against the evidence inputs in the signed body. If they disagree, you have found something real and we want to hear about it. [PLACEHOLDER — FOR COUNSEL] Any statement about the evidentiary weight of a determination in a given jurisdiction, or about its admissibility in a dispute with a policyholder or a regulator, must be drafted by legal counsel. This page describes what the artifact cryptographically is, not what it legally means.

Determinations reference

Every field in the determination response.

Service tiers

Why the artifact, not the payout, is the product.