Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Tokens & Compliance

Who it's for: Issuers deploying a new tokenised asset and compliance officers who need to control which countries and investor types can hold it. Why it matters: Every RWA token comes with built-in compliance rules that automatically block ineligible investors, so issuers stay within regulatory boundaries without manual oversight.

POST /rwa/create — Deploy RWA Token

Auth: x-admin-secret header required.

Request
{
  "ownerAddress": "0xabc...",
  "name": "Accra Commercial Property",
  "symbol": "ACP",
  "decimals": 18,
  "assetType": 0,
  "assetId": "PROP-GH-001",
  "jurisdiction": "GH",
  "priceSource": {
    "baseUrl": "https://api.pricedata.com",
    "httpMethod": "GET",
    "pathTemplate": "/property/{assetId}/price",
    "priceRegex": "\"price\":(\\d+\\.?\\d*)",
    "priceDecimals": 8,
    "credentialsKey": "PRICE_API_KEY"
  }
}

The service automatically:

  1. Checks if ownerAddress has an SSI identity — creates one if not
  2. Deploys the RWA Diamond via GenericRWAFactory.createRWA()
  3. Wires compliance modules based on assetType
  4. Grants RouterHook and P2POfferBook AGENT_ROLE
  5. Stores priceSource credentials encrypted in D1

Response: { "id": "uuid", "status": "pending" } (202)


POST /rwa/:address/mint — Mint to Investor

{
  "investorAddress": "0xdef...",
  "amount": "1000000000000000000"
}

amount in token base units (typically 18 decimals for RWA).


POST /rwa/:address/burn

{ "from": "0xdef...", "amount": "500000000000000000" }

POST /rwa/:address/freeze — Freeze Investor

{ "investorAddress": "0xdef...", "freeze": true }

POST /rwa/:address/forced-transfer

Compliance-driven transfer between holders.

{ "from": "0xdef...", "to": "0xghi...", "amount": "100000000000000000" }

GET /rwa/list — All Active RWAs

{
  "tokens": [
    {
      "address": "0x...",
      "name": "Accra Commercial Property",
      "symbol": "ACP",
      "assetType": 0,
      "jurisdiction": "GH",
      "totalSupply": "100000000000000000000"
    }
  ]
}

GET /rwa/:address — Full Token State

{
  "address": "0x...",
  "name": "Accra Commercial Property",
  "symbol": "ACP",
  "totalSupply": "100000000000000000000",
  "paused": false,
  "complianceAddress": "0x...",
  "identityRegistry": "0xC44357...",
  "onchainID": "0x...",
  "assetConfig": { "assetType": 0, "jurisdiction": "GH" },
  "db": { "status": "active", "assetId": "PROP-GH-001" }
}

Compliance Modules

POST /rwa/compliance/:address/add-country-restrict

{ "allowedCountries": ["GH", "NG", "KE"] }

POST /rwa/compliance/:address/add-max-balance

{ "maxBalance": "10000000000000000000" }

AI Compliance Chat

core-rwa embeds an AI assistant for managing compliance configuration conversationally. It uses Server-Sent Events (SSE) streaming.

POST /rwa/compliance/chat/start

Start a new compliance chat session for a Diamond.

Request
{ "diamondAddress": "0xrwa..." }
Response
{
  "sessionId": "chat-uuid",
  "greeting": "Hi! I can see ACP has CountryRestrict and MaxBalance modules active...",
  "currentModules": ["CountryRestrictModule", "MaxBalanceModule"]
}

POST /rwa/compliance/chat/message (SSE)

Send a message and receive a streamed response.

Request
{ "sessionId": "chat-uuid", "message": "Add Nigeria to the allowed countries" }

ResponseContent-Type: text/event-stream

data: {"type": "token", "content": "I'll add Nigeria"}
data: {"type": "token", "content": " to the CountryRestrictModule."}
data: {"type": "ready", "jobId": "job-uuid", "config": { ... }}
data: {"type": "done"}

The AI proposes a change. When type: "ready" fires, the caller gets a jobId with the proposed config.

POST /rwa/compliance/apply

Execute the AI-proposed compliance change.

{ "jobId": "job-uuid" }

GET /rwa/compliance/job/:jobId

Poll status of a pending compliance change.

{ "jobId": "job-uuid", "status": "pending", "config": { ... } }