1. Configure your endpoint
Webhook configuration lives under/api/organizations/me/webhook. Every route below
requires ORG_ADMIN — your organization API key holds it.
webhookSecret is generated automatically the first time you set a webhookUrl, and
PUT returns it in the same response. Read it back any time:
2. Events
The three
determination.* events are the whole notification surface for a
Tier 1 integration; payout.* never fires there, because
MicroCrop settles nothing.
3. Payload & headers
Every delivery is a JSON POST with this envelope:determination.delivered
Its data is currency-neutral and chain-neutral in both service tiers — one payload
shape, one parser:
amountOwed is stated in your policy’s own currency, derived as
sumInsured × damagePercentBp / 10000 truncated to the minor unit — never USDC, and
with no exchange rate anywhere in the path. If your policy’s currency has no registered
minor-unit exponent, amountOwed is null and amountOwedUnavailableReason is present
instead. See Determinations. On the
DETERMINATION_AND_SETTLEMENT tier you still receive the settled figure separately on
payout.completed, which is where amountUSDC belongs.
The event fires once per determination. It is keyed on the same idempotency key
MicroCrop uses to ingest the signed determination, so an oracle resubmitting the same
envelope emits nothing further. It is not emitted at all for a determination that could
not be attributed to one of your policies.
determination.settlement_report_recorded
Fires for every newly recorded Tier 1 settlement report, corrections included. A
replayed report — same determinationId and partnerReference — writes nothing and
emits nothing.
correction is true, report.supersedesReportId names the report this one
replaces — replace your stored attestation rather than appending a second one.
determination.settlement_report_overdue
Fires at most once per determination, when a Tier 1 determination reaches its reporting
due date with no report on file. It is a reporting state and nothing more: MicroCrop
did not settle the policy, owes nothing on it and has moved no money.
4. Verify the signature
ComputeHMAC-SHA256(secret, "{timestamp}.{rawBody}") and compare, in constant time, to
x-microcrop-signature. Use the raw request body (the exact bytes received), never a
re-serialized object — key order and whitespace would differ and the comparison would
fail.
2xx quickly — MicroCrop aborts the request after 10 seconds and treats the
timeout as a failed attempt. Do heavy work asynchronously.
5. Retries & delivery semantics
- Non-
2xxresponses (or timeouts) are retried up to 5 attempts with exponential backoff (~30s, 1m, 2m, 4m, 8m). After the last attempt the delivery is markedFAILED. - Delivery is at-least-once — the same event may arrive more than once.
Deduplicate by
id(orx-microcrop-delivery); automatic and manual retries re-send the samebody.id, so deduplicating on it is safe across every path. - Order is not guaranteed; treat each event as a state assertion and reconcile.
Delivery log
status filters on PENDING, DELIVERED or FAILED; limit is capped at 100. The
delivery payload is not returned by this endpoint — only the attempt metadata.
Manual retry
webhookUrl and current
secret, resets the row to PENDING, and re-sends the same body.id. It returns
400 INVALID_INPUT if the organization has no webhook URL configured, and
404 NOT_FOUND for a delivery id that is not yours.
6. Fallback: polling
Webhooks are a convenience layer over the same state you can always poll. If you miss deliveries beyond the retry window, reconcile withGET /api/determinations, GET /api/policies/{id}/status and (on Tier 2)
GET /api/payouts.
Need an event we don’t emit yet (e.g.
policy.expired, payout.processing)? Tell your
MicroCrop contact — the event set is easy to extend.