Welcome to The Crimson Market Developers Portal

Build powerful integrations with The Crimson Market API. Create OAuth applications, manage your credentials, and access our comprehensive documentation to bring trading functionality to your platform.

Developers Documentation

TCM OAuth Integration Docs

SDK-backed guidance for @crimsoncorp/oauth-react, plus portal-specific setup details for apps, scopes, and redirect registration.

Relic App Transfers

Send supported relic currencies from your app's funded treasury user to a target user without minting balance.

Local portal docs

Use this flow when your service needs to send a relic currency to one of your users from your own funded treasury account.

Relics is a configurable currency system. Approved businesses can create their own currency branches, decide whether each branch supports buy, sell, withdrawal, exchange, or closed-loop use, and settle value instantly through the relic ledger. A branch can be fully off-chain, or it can be paired with an on-chain asset strategy while still using relic balances for fast account settlement, treasury payouts, escrow, and payment authorization.

Use app transfers for treasury-funded movement: rewards, partner payouts, account credits, B2B settlement, customer service adjustments, or issuer-controlled distribution.

This API does not mint currency. Every transfer spends from the treasury user configured for your app.

Summary

  1. Create an app in the Developers portal and keep its clientId and clientSecret on your server.
  2. Ask TCM to enable relic app transfers for that client and map it to your treasury user.
  3. Keep your treasury user funded in the currencies your app will distribute.
  4. Call the public relic app-transfer endpoint whenever you want to send currency to a user.

Endpoint

POST https://www.thecrimsonmarket.com/relics/api/relics/app-transfer

Use your actual relic service base URL for the environment you are targeting.

List Available Currencies

Fetch enabled currencies before presenting transfer or treasury options:

GET https://www.thecrimsonmarket.com/relics/api/relics/currencies

Use data.currencies[].key as the relicType value. Capability flags describe the currency globally; your OAuth client must still be enabled for that currency before it can transfer it.

Authentication

Send your Developers app credentials in the request body:

  • clientId
  • clientSecret

Keep clientSecret server-side only.

Request fields

Required:

  • clientId
  • clientSecret
  • toUserId
  • amount
  • relicType
  • transactionId

Optional:

  • reason

Example request

{
  "clientId": "tcm_xxx",
  "clientSecret": "your-oauth-client-secret",
  "toUserId": "64c672ff9e49204d7f5dd5ca",
  "amount": 500,
  "relicType": "charades-coin",
  "reason": "Reward payout",
  "transactionId": "reward-2026-05-19-0001"
}

Behavior

  • The app credentials are validated before the transfer runs.
  • The transfer always spends from the treasury user configured for your app.
  • Your app can send only the currencies that have been enabled for that client.
  • If the treasury user does not have enough balance, the request fails.
  • transactionId is idempotent. Repeating the same request returns the already-processed transfer result instead of charging again.

Example success response

{
  "success": true,
  "data": {
    "type": "app_transfer",
    "relicType": "charades-coin",
    "clientId": "tcm_xxx",
    "treasuryUserId": "partner-treasury-user",
    "alreadyProcessed": false,
    "transactionId": "app_tx_out_example",
    "fromUser": {
      "userId": "partner-treasury-user",
      "previousAmount": 10000,
      "newAmount": 9500,
      "transferred": -500
    },
    "toUser": {
      "userId": "64c672ff9e49204d7f5dd5ca",
      "previousAmount": 0,
      "newAmount": 500,
      "received": 500
    },
    "reason": "Reward payout",
    "timestamp": "2026-05-19T12:00:00.000Z"
  }
}

Common failure cases

Invalid credentials

{
  "success": false,
  "error": "Invalid client credentials"
}

Currency not enabled for your app

{
  "success": false,
  "error": "This client is not allowed to transfer that currency"
}

Treasury balance too low

{
  "success": false,
  "error": "Treasury user has insufficient Charades Coin",
  "data": {
    "treasuryUserId": "partner-treasury-user",
    "currentBalance": 250,
    "requiredAmount": 500,
    "shortfall": 250
  }
}

Operational notes

  • This flow is for server-to-server use only.
  • Do not expose clientSecret in a browser or mobile client.
  • transactionId should be unique per payout attempt from your system.
  • This flow transfers existing balance. It is not a purchase flow and it is not a wallet withdrawal flow.
  • If you need this enabled for your app, contact TCM with your clientId, treasury user id, and the currencies you need to distribute.

Delegated User Transfers (v2)

Use this flow when your app moves relics on behalf of the currently signed-in user — for example one user tipping another. The sender is always the user, never a treasury, and no relics-side setup is required.

How it works

  1. Create a service client in the Developers portal (service-clients tab) with the service.relics audience and the relics:delegated-transfer scope.
  2. On your server, mint a client_credentials token from Portal with resource=service.relics.
  3. Call the endpoint with the user's own bearer token plus your service token:
POST https://www.thecrimsonmarket.com/relics/api/relics/delegated-transfer
Authorization: Bearer <signed-in-user-token>
x-service-token: <portal-service-token>
Content-Type: application/json
{
  "toUserId": "64c672ff9e49204d7f5dd5ca",
  "amount": 500,
  "relicType": "charades-coin",
  "reason": "Community alert tip",
  "transactionId": "community-alert-tip-0001"
}

Behavior

  • The sender is resolved from the user's bearer token. Your app never names the debit side and cannot move funds without the user's live token.
  • Any enabled currency is transferable by default. Your client is auto-registered with relics on first use; TCM admins can restrict currencies, cap amounts, or disable your integration from there.
  • transactionId is idempotent per client — retrying the same id returns the original result.
  • Failures carry a machine-readable code, e.g. service_token_invalid, invalid_audience, insufficient_scope, client_disabled, relic_type_not_allowed, amount_exceeds_limit, currency_not_enabled.

Deprecated: body-credential delegated transfers (v1)

Older integrations send clientId + clientSecret in the request body instead of x-service-token. That variant still works but is deprecated: it requires TCM to hand-provision your client inside relics with your currencies explicitly listed, and it puts your secret in every request body. New integrations should use the service-token flow above.

Buy Widget

Use the buy widget when you want to embed a purchase flow for a single currency inside your own service.

Widget URL

https://www.thecrimsonmarket.com/relics/widget/buy?relicType=charades-coin

Optional query parameters:

  • relicType required currency key to lock the widget to one currency
  • parentOrigin optional expected parent origin for stricter postMessage validation

Example:

https://www.thecrimsonmarket.com/relics/widget/buy?relicType=charades-coin&parentOrigin=https%3A%2F%2Fpartner.example.com

What the widget does

  • shows the configured currency only
  • shows the signed-in user's current public balance for that currency
  • lets the user enter a custom amount
  • opens the embedded Stripe checkout for that currency

Authentication model

Same-domain embeds can rely on the normal shared auth cookie.

Cross-domain embeds should use an iframe token handshake instead of relying on third-party cookies.

Child iframe behavior

The widget sends this message when it is ready:

{
  "type": "IFRAME_READY",
  "widget": "relics-buy"
}

The parent should respond with:

{
  "type": "TOKEN_DELIVERY",
  "token": "user-auth-token"
}

The widget then uses that token as a Bearer token for authenticated relic requests.

Example embed

<iframe
  src="https://www.thecrimsonmarket.com/relics/widget/buy?relicType=charades-coin&parentOrigin=https%3A%2F%2Fpartner.example.com"
  width="420"
  height="760"
  style="border:0;"
  allow="payment *"
></iframe>

Example parent handshake

<script>
  window.addEventListener('message', (event) => {
    if (event.origin !== 'https://www.thecrimsonmarket.com') return;
    if (event.data?.type !== 'IFRAME_READY') return;

    const iframe = document.getElementById('relic-buy-widget');
    iframe?.contentWindow?.postMessage({
      type: 'TOKEN_DELIVERY',
      token: window.mySignedInUserToken
    }, 'https://www.thecrimsonmarket.com');
  });
</script>

Notes

  • Keep the user token server-issued and scoped to the signed-in user.
  • Do not expose app clientSecret values in the widget or browser.
  • The widget is a purchase surface only. It does not mint arbitrary balances and it does not replace treasury-funded app transfers.