Safe integration flow
The decision-first flow, cache semantics and refresh discipline for production integrations.
Kyro has one recommended integration shape: check the decision, act on the verdict, mint a receipt when you need proof. Every other endpoint is evidence you can consult when a verdict needs context. This page walks the flow and the data semantics that keep it safe.
Decision first
GET /api/v1/decision/{wallet}?useCase= is the entry point. It answers 200 for every valid wallet address, known or not. When Kyro has never seen the wallet the response is a conservative baseline verdict, never a 404 and never a guess.
- reasons drive the verdict. warnings are advisory coverage notes and never change it. See Reason and warning codes.
- A baseline verdict tells you evidence is missing, not that the wallet is bad. Missing evidence alone never produces a block.
When you hit a baseline for a wallet you care about:
- Start indexing with intake:
POST /api/v1/intake/{wallet}. - Poll
GET /api/v1/score/{wallet}untilcacheStatusiscached. - Re-run the decision. The verdict now rests on committed evidence.
Which read when
| Surface | Use it for |
|---|---|
| Decision | A verdict with a recommended limit. The default for payments, marketplaces, escrow and lending. |
| Score | The raw 0 to 100 score with component breakdown, for building your own policy on top. |
| Interaction graph | Observed counterparties from saved chain snapshots. Display and investigation evidence, score-neutral. |
| Trust graph | Verified relationship evidence: attestation-backed edges between registered identities. |
What cacheStatus means
| Value | Meaning | What to do |
|---|---|---|
cached | A committed snapshot backs the answer. | Trust the verdict at its stated freshness. |
indexing_required | No committed evidence yet. The answer is a conservative baseline. | Run intake, poll the score until cached, then re-check. |
Committed evidence older than 24 hours adds the DATA_STALE reason to decisions. The freshness object also carries lastIndexedAt and refreshInProgress so you can see exactly what backs a verdict.
Reading the interaction graph honestly
GET /api/v1/interaction-graph/{wallet} is anonymous, database-only and side-effect-free: it reads persisted snapshots and never starts a scan.
metrics: nullis not zero. A node withmetrics: nullmeans no countable evidence is captured for that counterparty yet: the snapshot predates stats capture or the evidence is Arc aggregate-only. A node with a metrics object carries real saved counts.- An empty graph is not proof of isolation. Check
coverage.statusfirst:not_indexedmeans Kyro has no snapshot at all andpartialmeans some chains are missing. Only acompletescan with zero nodes supports "no observed counterparties". lowerBound: truemeans "at least". A counted chain hit a provider history cap or some contributing chains have no captured stats.basisreports how many chains were counted, are pending capture or are unavailable.
Refresh discipline
POST /api/v1/interaction-graph/{wallet}/refresh re-indexes a wallet through the same pipeline as intake. Four rules keep it cheap and safe:
- It needs an API key. Anonymous calls answer
401 NOT_ALLOWED. A wallet Kyro has never seen can be indexed once anonymously through intake instead. - Fresh means free and done. A snapshot committed within the last 60 minutes answers
200withstatus: freshand aretryAfterSeconds. Nothing starts and nothing is charged. - Refreshes are single-flight. Concurrent requests for the same wallet join the run already in flight:
202withstatus: indexing, free. Firing more POSTs never speeds anything up. - Poll the GET, do not re-POST. After a
202withstatus: started(5 units, against the daily refresh cap for a re-index or the daily intake cap for a wallet's first index), pollGET /api/v1/interaction-graph/{wallet}with backoff until coverage reports the new snapshot. Per-plan caps are on the refreshInteractionGraph reference page.
You rarely need manual refresh
Kyro re-indexes registered wallets on a rolling daily cadence, so scores and graphs for registered identities stay current without integrator action. This is current product behavior, not a contract term: build against the freshness fields in each response rather than assuming a schedule. Manual refresh is for on-demand freshness, for example right before releasing a large escrow.
Observation is not trust
The interaction graph records what happened on chain: deduplicated counterparties with saved counts. It is score-neutral and it is not an endorsement. A high transaction count with a wallet proves contact, not confidence. verifiedKyroPeer: true on a node means the separate Trust Graph also contains that wallet; observation alone never creates a trust edge, a metric or a score contribution.
Verified attestations are instant trust evidence
Trust edges come only from verified attestations: a real Arc transaction, both wallets participating, verified on chain, accepted by the counterparty. Once verification and acceptance complete, the edge is trust evidence immediately. No re-index or refresh run is needed for it to appear in GET /api/v1/trust/{wallet}. Verified attestations also feed the verifiedAttestations and capped propagatedTrust score components. See Trust graph for the full verification rules.
Where to go next
- Integration patterns for per-use-case recipes: payments, payouts, marketplaces, escrow, audits.
- Response envelope for the shared success and error shape.
- Data coverage for provider states and coverage metadata.
- Rate limits for budgets, unit costs and daily caps.