Read our books, programmatically
Every number on this site is available as JSON. The transparency endpoints are read-only by design — no API key, no rate-limit tier, CORS open to any origin. Minting and redemption are never exposed as a public write API, because an endpoint that can mint is an endpoint that can be abused.
The cash-out API is a separate, authenticated set of endpoints for partner wallets. It requires an API key created by a registered member and scopes every order to the key that created it.
Transparency
/api/public/reservesLatest signed attestation: total reserves, TSD circulating supply, collateralization, cold/hot split, and breakdowns by chain, token and address group. Falls back to a live scan before the first attestation exists.
Try it/api/public/reserves/history?range=24h | 7d | 30d | 90d | allThe append-only signed series behind the charts on /reserves. Each point carries its payload hash and signature so you can prove a historical value was never edited.
Try it/api/public/supplyAggregator-shaped supply data: symbol, chain, Omni property id, circulating supply, backing assets, reserves and collateralization.
Try it/api/public/statusPeg health, fee/limit configuration, instant redemption capacity per chain, redemption queue depth, and background job heartbeats.
Try itPartner cash-out
Use this to let your users convert TSD back to USDC without leaving your app. Get a key from the account page and send it as the x-api-key header (or Authorization: Bearer). /orders accepts a chain of ethereum, base, or bsc.
/api/public/v1/cashout/settingsx-api-keyLive flag, minimum/maximum order sizes, the global redemption fee in basis points, and an `account` block for the member behind your key: their permanent TEXITcoin deposit address, permanent EVM address, saved cash-out address, and their effective (possibly discounted or zero) fee.
/api/public/v1/cashout/deposit-addressx-api-keyThe reusable TEXITcoin deposit address for the member behind your key (safe to cache and display as “your TSD address”), plus their permanent EVM address, saved cash-out address, and effective fee. All fee fields are numbers: redeemFeeBps, defaultRedeemFeeBps, feePercent.
/api/public/v1/cashout/payout-addressx-api-keyThe USDC payout address saved on the member’s account, plus their permanent TEXITcoin deposit address and effective fee. Use this to auto-fill both sides of a cash-out without asking the user to look anything up.
/api/public/v1/cashout/payout-addressx-api-keySave the USDC destination for this member once; afterwards every order may omit payoutAddress. An explicit payoutAddress on an order still overrides it for that order.
{"payoutAddress":"0x…"}/api/public/v1/cashout/couponx-api-keyCheck whether a coupon code is valid and see the fee it would apply. Never consumes a use.
{"code":"EARLYBIRD"}/api/public/v1/cashout/ordersx-api-keyStart a TSD → USDC redemption on behalf of your user. The response tells you exactly where the user must send TSD: depositAddress (also returned as address, txcDepositAddress and sendTo — same value), with asset: "TSD", network: TEXITcoin Omni property 39, and memo: null (Omni has no memo/tag). Show that address, not the account-level one. payoutAddress and refundAddress are optional — we fall back to the cash-out address and permanent TEXITcoin address on your account, and an explicit payoutAddress always overrides the account default. The member’s negotiated fee is applied automatically (a coupon can only lower it).
{"amount":100,"payoutAddress":"0x…","refundAddress":"TXC…","chain":"ethereum","couponCode":"EARLYBIRD","source":"HME Wallet"}/api/public/v1/cashout/orders/:idx-api-keyRead the current status, the deposit address to send TSD to (depositAddress / address / sendTo), amount received, payout amount, and settlement txids. Only the API key that created the order can read it.
Dollar tokens (TSD, CAN)
The same engine issues more than one 1:1 USD-backed token on TEXITcoin. TSD fronts tsd.honest.money; CAN fronts CannabisCoins.com. They share these vaults, this relayer and one proof-of-reserves feed — only the ticker, limits and fees differ. Send your key as x-api-key and name the token with asset. Payouts are always USDC; the TEXITcoin leg always uses a legacy T… address.
/api/public/v1/stables/assetspublicEvery 1:1 USD-backed token this desk issues on TEXITcoin — TSD (Texas Stable Dollar) and CAN (CannabisCoins.com) — with its Omni property id, accepted deposit stablecoins, min/max order size, mint and redeem fees in bps, circulating supply and whether it is live. No key required: poll this to build your UI and to disable submit when a token is paused or not yet issued.
/api/public/v1/stables/ordersx-api-keyOne shape for every token. direction 'mint' takes a stablecoin deposit (USDC/USDT/PYUSD/DAI on Ethereum, Base or BNB Smart Chain) and grants the token to a legacy T… TEXITcoin address; the response carries the freshly derived deposit address. direction 'redeem' returns the token to the issuer and pays out USDC to payoutAddress; the response tells you where to send it. Poll the order with the cash-out order endpoint.
{
"asset": "CAN",
"direction": "mint",
"chain": "base",
"token": "USDC",
"recipient": "T…",
"amount": 250
}Wrapping desk (majors)
Wrap Bitcoin, Litecoin and Ethereum into Omni tokens on TEXITcoin (wBTC, wLTC, wETH) and unwrap them back to the native coin. Same auth model as cash-out: send your key as x-api-key. Each wrap order gets its own freshly derived deposit address on the base chain; unwrap orders return the wrapped token to the issuer's legacy TEXITcoin address. The wrapped leg is custodial — reserves are held by the issuer and published on /reserves.
/api/public/v1/wrap/assetspublicRegistry of every major we wrap: base and wrapped symbol, network, Omni property id, required confirmations, min/max order size, wrap and unwrap fees in bps, whether the desk is live, plus live reserves, wrapped supply and collateralization. No key required — poll this to build your UI and to disable submit when a desk is paused.
/api/public/v1/wrap/ordersx-api-keydirection is 'wrap' (native in, wrapped out) or 'unwrap' (wrapped in, native out). For a wrap, payoutAddress is the customer's legacy T… TEXITcoin address and the response carries the per-order deposit address on the base chain. For an unwrap, payoutAddress is their BTC/LTC/ETH address and the response tells you where to send the wrapped token. refundAddress and reference are optional; reference is echoed back on every poll.
{
"direction": "wrap",
"asset": "BTC",
"amount": 0.01,
"payoutAddress": "T…", // legacy TEXITcoin address
"refundAddress": "bc1…", // optional
"reference": "seeds:order:123" // optional, echoed back
}/api/public/v1/wrap/orders/:idx-api-keyCurrent status, deposit address (depositAddress / sendTo), amounts, confirmations vs required, fee, and every txid (deposit, mint, burn, payout). Accepts the uuid or the TX-XXXXXXXX short reference. Polling also nudges the order forward, so state is fresh. Only the key that created the order can read it.
Wallet linking & rewards
Lets a partner wallet (Beekeeper, CryptoPOP, HME Wallet) bind itself to a TSD member account by scanning a QR. The wallet shares its TEXITcoin account extended public key only — it is watch-only, so we can read TSD balances and never move funds. We derive addresses across both branches with a gap limit of 20, sample the total TSD balance every hour, and expose a 30-day rolling average for level-up rewards. Linking also fills in the member's TSD and USDC payout addresses so they never type one again.
/api/public/v1/wallet-link?token=…public (single-use token)The QR a member shows in their TSD Swap account encodes this URL. Fetch it with Accept: application/json to get the manifest, or render the page and read the <script type="hm-link-xpubs"> block. It tells you what to sign, which chains we want, who is asking, when the challenge expires, and whether re-binding a new wallet is allowed. Tokens are single-use and live 5 minutes.
/api/public/v1/wallet-linksignatureSend the manifest payload back with a BIP-137 signature over canonicalJson(payload) — keys sorted recursively, no whitespace, UTF-8 bytes, TEXITcoin magic prefix, base64 — signed by m/44'/696969'/0'/0/0. xpubs.TXC is required and must be the account-level extended public key (watch-only); xpubs.EVM is required (plain 0x address or an EVM xpub, where m/0/0 is taken) and becomes the member's automatic USDC redemption payout address; xpubs.BASE is optional and defaults to EVM. We verify the signature, store the xpub, auto-fill the member's TSD and USDC payout addresses, start watching every derived address for TSD, and return a freshly minted partner API key in api_key (scopes cashout + rewards) — so a single scan both links the wallet and authorises the app, replacing any pasted key. The key is shown once; rescanning issues a new one and revokes the previous one. 401 invalid signature, 409 wallet already linked to another account, 403 unknown_signer when re-binding without consent, 410 token used or expired.
{
"payload": {
"v": 1,
"type": "hm-link-xpubs",
"challenge_id": "<from manifest>",
"from": "tsd.honest.money",
"callback_url": "https://tsd.honest.money/api/public/v1/wallet-link?token=…",
"chains": ["TXC", "EVM", "BASE"],
"xpubs": {
"TXC": "xpub…", // required — account xpub, watch-only
"EVM": "0x…", // required — default EVM wallet (or an xpub)
"BASE": "0x…" // optional — defaults to EVM
},
"wallet": "HME Wallet",
"exp": 1767225600,
"issued_at": "2026-09-04T09:32:01.234Z"
},
"signature": "<base64 BIP-137>",
"address": "T…" // signing address, legacy base58
}/api/public/v1/rewards/balance?address=…&days=30x-api-key (rewards)For mineHME level-up rewards. address can be any address we can tie back to a member: their signing address, any address derived from their linked xpub, their permanent TSD Swap inbox, or their linked ETH/Base address. Returns currentBalance, averageDailyBalance over the window, sample count, and which field matched. Balances are Omni TSD (property 39) sampled hourly, so the average can't be gamed by topping up once a day. Requires a key with the 'rewards' scope. Never returns an email or any other personal data.
TEXITcoin address format (legacy only)
TSD is an Omni Layer property on the TEXITcoin blockchain. Omni reference outputs only recognise legacy base58check addresses — the ones that start with a capital T. A bech32 txc1… address will be silently ignored by Omni and the tokens will never arrive, so every endpoint that accepts a TEXITcoin address rejects bech32 before it ever touches the chain.
- Starts with a capital
T, 26–35 characters, base58 (no0,O,Iorl). - Version byte
0x42(P2PKH) or0x32(P2SH) — both are accepted. - Full base58check checksum is verified, so a single mistyped character is rejected.
txc1…bech32 is rejected with a message pointing the user to the legacyT…address in their wallet (Receive → Tokens tab).- No memo, tag or destination tag is required — Omni property 39 has no such field. Any address you send us
refundAddressfor must be a valid legacy address.
The same validation runs on every path: the API, the member dashboard, and the admin console share one checkTxcAddress routine. If an address passes there, it passes everywhere.
Status callbacks (skip the polling)
Each API key can carry an https callback URL, set on your account page under API keys. Every milestone of an order created with that key — deposit seen, deposit confirmed, burn, payout sent, and any failure — is POSTed to that URL as JSON:
{
"type": "payout_sent",
"message": "Sent 99 USDC on ethereum",
"amount": 99,
"chain": "ethereum",
"txid": "0x…",
"occurredAt": "2026-08-06T11:00:00.000Z",
"order": { "id": "…", "status": "released", "payoutAmount": 99, … }
}x-tsd-timestampholds unix seconds;x-tsd-eventrepeats the event type.x-tsd-signatureissha256=followed by the hex HMAC-SHA256 oftimestamp + "." + rawBody, keyed with the signing secret shown next to your key. Compare it with a timing-safe compare and reject timestamps older than a few minutes.- Respond
2xxquickly. Deliveries are best-effort and not retried, so treat them as a fast path and keep the poll endpoint as your source of truth for reconciliation.
Inbound partner webhooks
Partners can push status events back to us so a missed deposit or a payout confirmation is never silent. Each partner has its own shared secret, compared in constant time; if the secret is unset the endpoint returns 503 rather than opening up. Nothing here moves funds — it records an auditable order_events row and pages operations, so a compromised caller cannot spend money.
POST /api/public/v1/webhooks/tsdswap— HME Wallet / Seeds, guarded by theTSDSWAP_API_KEYsecret.POST /api/public/v1/webhooks/cannabis— CannabisCoins.com, guarded by theCAN_WEBHOOKsecret.
Send the secret as Authorization: Bearer or x-api-key. The body is { event, order_id?, message?, amount?, chain?, txid?, data? } — order_id may be a short TX-XXXXXXXX or a full UUID. We respond { ok: true, recorded: true|false, order?: "TX-…" } and page ops in the same beat.
Verifying an attestation
Each attestation is canonicalized before it is hashed, so anyone can recompute the hash from the published fields. The rule is fixed and public:
- Object keys are sorted alphabetically at every level.
- All numbers are rounded to 6 decimal places; non-finite values become null.
payload_hash = sha256(json), hex encoded.signature = hmac_sha256(secret, payload_hash)— the key is held by the issuer, so the signature proves the row was written by us and never edited afterwards.
Attestations are append-only: rows are never updated or deleted. Recompute the hash for any historical point and compare it with the published payload_hash. If they differ, the number changed and we are caught.
Cadence commitment
We commit to recording a reserve attestation at least once per hour, continuously. The current cadence and the timestamp of the last attestation are both published on /status. A gap in the series is itself evidence — we would rather you see a gap than a fabricated number.
Fair use
Responses are cached for 15–120 seconds. Please poll no more than once per minute; the underlying data does not change faster than that. If you are building something that needs more, get in touch and we will work out a push feed.