{"openapi":"3.1.0","info":{"title":"UnyKorn RWA Operating System API","version":"1.0.0","description":"Structure, document, mint and administer real-world assets. Engineering output for counsel — not legal advice, and not an offer of any security. Free endpoints are the catalogue; structuring and generation are metered per call in USDC over x402, with a daily free tier per API key.","contact":{"name":"UnyKorn","url":"https://rwa.unykorn.org"}},"servers":[{"url":"https://rwa.unykorn.org"}],"security":[{"ApiKey":[]}],"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"x-api-key"},"X402":{"type":"apiKey","in":"header","name":"x-payment","description":"Signed EIP-3009 payment authorization. Presented after a 402 challenge."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"detail":{}}},"StructureRequest":{"type":"object","required":["assetClassKey","jurisdiction","raiseUsd","expectedHolders","retailIntended","wantsGeneralSolicitation"],"properties":{"assetClassKey":{"type":"string","example":"water-rights"},"jurisdiction":{"type":"string","enum":["US","EU","UK","SG","AE","CH","CA","NON_US"]},"pathwayKey":{"type":"string","description":"Force a pathway instead of letting the engine select."},"raiseUsd":{"type":"string","example":"5,000,000"},"expectedHolders":{"type":"integer","minimum":1},"retailIntended":{"type":"boolean"},"wantsGeneralSolicitation":{"type":"boolean"},"maxHolderPct":{"type":"integer","minimum":1,"maximum":100},"allowedCountries":{"type":"array","items":{"type":"string"}},"rails":{"type":"array","items":{"type":"string"},"example":["apostle","base"]}}}}},"paths":{"/api/health":{"get":{"summary":"Service health and catalogue counts","security":[],"responses":{"200":{"description":"ok"}}}},"/api/v1/asset-classes":{"get":{"summary":"Every supported asset class with its proof requirements and its trap","security":[],"responses":{"200":{"description":"ok"}}}},"/api/v1/asset-classes/{key}":{"get":{"summary":"One asset class","security":[],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"ok"},"404":{"description":"unknown class"}}}},"/api/v1/pathways":{"get":{"summary":"Offering pathways by jurisdiction, with eligibility, solicitation and holding period","security":[],"responses":{"200":{"description":"ok"}}}},"/api/v1/rails":{"get":{"summary":"Settlement and register rails, and which have institutional custody today","security":[],"responses":{"200":{"description":"ok"}}}},"/api/v1/structure":{"post":{"summary":"Generate a structure: wrapper, pathway, compliance module set, signing matrix, document set, fees, timeline","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructureRequest"}}}},"responses":{"200":{"description":"structure"},"402":{"description":"payment required"},"422":{"description":"no eligible pathway"}}}},"/api/v1/documents":{"post":{"summary":"Generate counsel-ready PPM, subscription agreement and operating agreement drafts with a redline checklist","responses":{"200":{"description":"documents"},"402":{"description":"payment required"}}}},"/api/v1/spv-plan":{"post":{"summary":"SPV formation plan by wrapper and jurisdiction, with evidence per step","responses":{"200":{"description":"plan"},"402":{"description":"payment required"}}}},"/api/v1/mint":{"post":{"summary":"Produce and execute the deployment plan across the register rail and each settlement mirror, ending in the mandatory negative control","responses":{"200":{"description":"mint result"},"402":{"description":"payment required"},"422":{"description":"rejected"}}}},"/api/v1/preclear":{"post":{"summary":"Evaluate a transfer against the bound compliance modules before it is submitted","responses":{"200":{"description":"allowed or blocked with reasons"}}}},"/api/v1/guard/stablecoin":{"post":{"summary":"GENIUS Act guard. Refuses any dollar-denominated payment instrument without a named permitted issuer and qualifying reserves","security":[],"responses":{"200":{"description":"disposition"}}}},"/api/v1/guard/role":{"post":{"summary":"Architectural boundary guard: never lender, bank, custodian, venue, adviser or issuer of record","security":[],"responses":{"200":{"description":"clean or breaches"}}}},"/api/v1/guard/security-triage":{"post":{"summary":"Howey and Reves triage","security":[],"responses":{"200":{"description":"assessment"}}}},"/api/v1/intake":{"post":{"summary":"Submit an asset for review. Applies the three-question threshold test and returns the exact proofs required","security":[],"responses":{"201":{"description":"received"},"400":{"description":"invalid"}}}},"/api/v1/admin/intake":{"get":{"summary":"Tenant intake queue","responses":{"200":{"description":"ok"},"401":{"description":"unauthorized"}}}},"/api/v1/admin/receipts/verify":{"get":{"summary":"Re-derive every hash in the receipt chain and report the first break","responses":{"200":{"description":"verification"},"401":{"description":"unauthorized"}}}},"/api/v1/receipts/verify":{"get":{"summary":"Replay the whole receipt chain and report whether it holds","description":"Public and unauthenticated on purpose. Recomputes every hash from the row's own stored contents and checks it against both its recorded hash and the previous row's, so an edit, an insertion, a deletion or a reordering all fail — and the response names the first sequence where it happens. Receipt payloads are withheld because they carry counterparty references; a party to a receipt reads its body through their own statement.","security":[],"responses":{"200":{"description":"verified true/false, chain length, head hash, and brokenAt when it fails"}}}},"/api/v1/network/stats":{"get":{"summary":"Live network counts, read from the ledger at request time","description":"No figure here is illustrative, smoothed or seeded — a zero is a real zero. Dollar volume is deliberately absent: those amounts belong to the parties on the lines. payouts.eventsMissingLines is an integrity check that is published rather than hidden and must read zero.","security":[],"responses":{"200":{"description":"counts by introducer, book, payout, circumvention and receipt chain"}}}},"/api/v1/network/policies":{"get":{"summary":"Split policies: pool share, bracket, decay half-life, engagement floor, clawback window","security":[],"responses":{"200":{"description":"ok"}}}},"/api/v1/network/kinds":{"get":{"summary":"The six introducer categories and what each may lawfully be paid on","security":[],"responses":{"200":{"description":"ok"}}}},"/api/v1/network/eligibility":{"post":{"summary":"Can this introducer be paid on this transaction, and if not what would release it","description":"Returns PAY, ROUTE_THROUGH_BD, ACCRUE_HOLD or REFUSE with the reason, the authority it rests on, and the remedy. Only REFUSE carries accrues:false — issuer personnel under Rule 3a4-1 may not receive transaction-based compensation, and that answer does not change with time.","security":[],"responses":{"200":{"description":"decision, reason, remedy, authority, accrues"},"400":{"description":"invalid"}}}},"/api/v1/network/project":{"post":{"summary":"Project earnings on a given platform fee, chain depth and relationship age","description":"Integer parts-per-million throughout. weightPpm and engagementPpm are the raw integers; weight and engagement are the same values rendered for display.","security":[],"responses":{"200":{"description":"projection"},"400":{"description":"invalid"}}}},"/api/v1/network/introducers":{"post":{"summary":"Register an introducer","description":"A registered representative requires both a CRD and the broker-dealer of record — commissions flow through the firm, so the record has to name it. An upline that is not itself registered is refused.","security":[],"responses":{"201":{"description":"registered"},"409":{"description":"email already registered"},"422":{"description":"rejected"}}}},"/api/v1/network/introducers/{id}/public":{"get":{"summary":"Standing, counts and chain anchor for one introducer - no figures","description":"The id-only surface. An introducer id is published by design - it is what a downline enters as their upline - so this route deliberately carries no earnings, no payout lines, no client references, no email and no wallet. Those read from /statement with the access key minted at registration.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"standing"},"404":{"description":"no such introducer"}}}},"/api/v1/network/introducers/{id}":{"get":{"summary":"An introducer with their book, downline and payout lines","description":"Access key required, as `Authorization: Bearer UBK-...` or `?key=`. Lookup is by id only; matching on email was removed because knowing an introducer's work address was enough to pull their client book.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"ok"},"401":{"description":"no key, or the wrong key"},"403":{"description":"registered before access keys existed - an operator must rotate one in"},"404":{"description":"not found"}}}},"/api/v1/network/introducers/{id}/statement":{"get":{"summary":"Every payout line for one introducer, with the arithmetic that produced each","description":"Access key required. A statement for an id that does not exist is a 404, not a clean set of zeroes - zero lines and no such introducer are different answers.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"statement"},"401":{"description":"no key, or the wrong key"},"403":{"description":"no key on file for this introducer"},"404":{"description":"no such introducer"}}}},"/api/v1/network/introducers/{id}/rotate-key":{"post":{"summary":"Issue a new access key for one introducer (operator only)","description":"Admin key required. Returns the new key exactly once and invalidates any previous one immediately. Appends introducer.key.rotated to the receipt chain, so a credential can never be swapped without a trace behind a disputed payout.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"new key, shown once"},"401":{"description":"unauthorized"},"404":{"description":"no such introducer"}}}},"/api/v1/network/introducers/{id}/score":{"get":{"summary":"Introducer Network Score and tier, snapshotted as history","description":"Drives pool priority, support level and vest speed. Deliberately does NOT drive the split arithmetic — a share is property, not a rating.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"score breakdown and history"},"404":{"description":"not found"}}}},"/api/v1/network/commit":{"post":{"summary":"Commit a client without naming them","description":"Stores sha256(clientRef || salt). The client is not named anywhere in the record. Without the salt the claim cannot be revealed or resolved.","security":[],"responses":{"201":{"description":"committed"},"404":{"description":"unknown introducer"}}}},"/api/v1/network/reveal":{"post":{"summary":"Reveal a committed client and record the attribution","security":[],"responses":{"201":{"description":"attribution recorded, with its rank"},"409":{"description":"rejected"},"422":{"description":"reveal does not match the commitment"}}}},"/api/v1/network/attribute":{"post":{"summary":"Record an attribution directly, for a client who was never a secret","security":[],"responses":{"201":{"description":"recorded"},"404":{"description":"unknown introducer"}}}},"/api/v1/network/clients/{ref}/claims":{"get":{"summary":"Every claim over one client, in rank order","description":"Both parties to a contested client can see both claims. Rank 1 is the earliest live claim; nothing pays until a contest is settled.","security":[],"parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"ok"}}}},"/api/v1/network/payout":{"post":{"summary":"Resolve a transaction against the network and write the payout lines","description":"The event and all its lines are written in a single batch, so a statement can never land half-written. Each line carries the eligibility decision, the authority behind it and the arithmetic in full. A blocked line still accrues against the relationship — except REFUSE, which never becomes payable.","security":[],"responses":{"200":{"description":"no introducer holds this client for this scope"},"201":{"description":"resolved, with every line and the formula"},"409":{"description":"contested or terminated attribution"}}}},"/api/v1/network/lines/{id}/settle":{"post":{"summary":"Release one vested line","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"settled"},"401":{"description":"unauthorized"},"409":{"description":"not vested, nothing payable, or already settled"}}}},"/api/v1/network/attributions/{id}/onchain":{"get":{"summary":"What to send to IntroducerRegistry for an attribution","description":"The registry never holds funds: settle() pulls from the funder and pushes to the introducer in one transaction, and refuses any line compliance has not cleared.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"call plan"},"404":{"description":"not found"}}}},"/api/v1/network/match":{"post":{"summary":"Score two counterparties against each other using the intake matcher","description":"Stateless: no book is read, nothing is written, no receipt is appended. Compares hashes only — names are normalised and every other identifier is digested first. Returns the weights and thresholds alongside the verdict so the sum can be checked.","security":[],"responses":{"200":{"description":"match, thresholds, weights and outcome"},"400":{"description":"invalid"}}}},"/api/v1/network/screen":{"post":{"summary":"Screen a new counterparty against every live attribution and raise claims automatically","description":"Runs at intake so the introducer does not have to be watching. A match at or above the auto-attach threshold attaches with no human action; one above the review threshold holds the deal from opening. Pass dryRun:true to compute the real result against the real book and write nothing.","security":[],"responses":{"200":{"description":"dry run"},"201":{"description":"screened, claims recorded"},"400":{"description":"invalid"}}}},"/api/v1/network/claims":{"get":{"summary":"Circumvention claims, newest first","security":[],"parameters":[{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["open","attached","declined"]}}],"responses":{"200":{"description":"ok"}}}},"/api/v1/network/claims/{id}/resolve":{"post":{"summary":"Attach or decline a claim","description":"A claim can be attached or declined, never removed. Declining requires a named person and a stated reason, enforced by a database constraint rather than by policy — a refusal with neither is not a decision, it is a disappearance. The resolution is written to the receipt chain and the introducer can read it.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"resolved"},"400":{"description":"missing named resolver or reason"},"401":{"description":"unauthorized"},"409":{"description":"already resolved"}}}},"/api/v1/network/engagement":{"post":{"summary":"Attest an engagement event for an introducer","description":"Attested by a named operator, never self-reported. Counts toward the engagement multiplier for twelve months; a passive introducer keeps the policy floor and never falls to nothing.","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"recorded"},"401":{"description":"unauthorized"},"404":{"description":"unknown introducer"}}}},"/api/v1/network/interest":{"post":{"summary":"Register interest in the introducer network","security":[],"responses":{"200":{"description":"already on the list"},"201":{"description":"recorded"},"400":{"description":"invalid"}}}},"/api/v1/network/admin/overview":{"get":{"summary":"Network totals by kind, decision and book size","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"ok"},"401":{"description":"unauthorized"}}}}}}