Skip to content

Project: Build a Loyalty Points Program ​

A complete, runnable project that registers your own token as a first-class asset, mints rewards to users, and burns on redemption — entirely outside the airtime/stablecoin path. This is the simplest way to add a brand-new token type without touching engine code — every generic /assets/:symbol/* endpoint works on it immediately once registered. What "register" means differs by chain, though: on an EVM chain you deploy a contract yourself first; on Stellar there's no contract to deploy at all — you register by issuer account instead.

▸API ConfigurationNot configured
Every endpoint, payload, and response on this page follows this choice.

What you'll build ​

A points.js script that registers a POINTS asset (once), then rewards and redeems it repeatably — the same reward/redeem cycle a real loyalty program runs on every purchase and checkout.

Prerequisites ​

  • Node.js 18+ (for global fetch)
  • A running comet-engine with a tenant API key/secret — see Authentication
  • A real on-chain artifact to register against: deploy your own ERC-20 with any standard tool (Hardhat/Foundry) on Celo, or decide on an issuer account on Stellar — neither is something this project does for you

Project setup ​

bash
mkdir loyalty-points && cd loyalty-points && npm init -y && npm install dotenv

.env:

env
COMET_BASE_URL=http://localhost:8100
COMET_API_KEY=your-tenant-api-key
COMET_API_SECRET=your-tenant-api-secret
CONTRACT_OR_ISSUER=0xYourDeployedERC20OrStellarIssuerAccount

Create points.js with this shared helper at the top — every step below adds to the same file:

js
import 'dotenv/config';

const base = process.env.COMET_BASE_URL;
const headers = {
  'Content-Type': 'application/json',
  'X-API-Key': process.env.COMET_API_KEY,
  'X-API-Secret': process.env.COMET_API_SECRET,
};

async function comet(method, path, body) {
  const res = await fetch(base + path, { method, headers, body: body ? JSON.stringify(body) : undefined });
  const data = await res.json();
  if (!res.ok) throw new Error(`${method} ${path} -> ${res.status}: ${JSON.stringify(data)}`);
  return data;
}

Step 1: Register your token (once) ​

You deploy the ERC-20 contract yourself (any standard implementation) — Comet Engine never deploys token contracts on your behalf. Once it exists on-chain, register it:

Register Contract (Celo)

🔒 Admin operation — always requires a Service Token, regardless of the panel above.

curl -X POST "http://localhost:8100/api/v1/admin/assets/POINTS/register?chain=celo" \
  -H "Content-Type: application/json" \
  -H "X-Service-Token: YOUR_SERVICE_TOKEN" \
  -d '{
  "contract": "0x9f8b2C4A1e6D53F0a7B4c6E2D1a9F3b8C5d7E1a0",
  "decimals": 18,
  "name": "FusionPoints",
  "type": "utility",
  "backing": "none"
}'
Response200
{
  "message": "asset POINTS registered on celo",
  "asset": {
    "symbol": "POINTS",
    "contract": "0x9f8b...E1a0"
  }
}

Step 2: Reward a user ​

Mint Points (Celo)
curl -X POST "http://localhost:8100/api/v1/assets/points/mint" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "userId": 24,
  "amountBase": "1000000000000000000000",
  "externalId": "reward-001"
}'
Response200
{
  "amount": 1000,
  "chain": "celo",
  "symbol": "POINTS",
  "txHash": "0x..."
}

Step 3: Redeem points ​

Redeem Points (Celo)
curl -X POST "http://localhost:8100/api/v1/assets/points/burn-by-holder" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "userId": 24,
  "amountBase": "500000000000000000000",
  "externalId": "redeem-001"
}'
Response200
{
  "txHash": "0x...",
  "chain": "celo",
  "symbol": "POINTS",
  "amount": 500
}

Step 4: Run registration + reward + redeem as one script ​

Add main() to points.js:

js
async function main() {
  await comet('POST', '/api/v1/admin/assets/POINTS/register?chain=celo', {
    contract: process.env.CONTRACT_OR_ISSUER, decimals: 18, name: 'FusionPoints', type: 'utility', backing: 'none',
  });
  console.log('POINTS registered on celo');

  const reward = await comet('POST', '/api/v1/assets/points/mint', { userId: 24, amountBase: '1000000000000000000000', externalId: `reward-${Date.now()}` });
  console.log('rewarded 1000 points:', reward.txHash);

  const redeem = await comet('POST', '/api/v1/assets/points/burn-by-holder', { userId: 24, amountBase: '500000000000000000000', externalId: `redeem-${Date.now()}` });
  console.log('redeemed 500 points:', redeem.txHash);
}

main().catch((e) => { console.error(e); process.exit(1); });
bash
node points.js

What you built ​

  • A brand-new token type, registered without touching engine code.
  • A working reward/redeem cycle any checkout or purchase flow can call directly.

Next steps: wire Step 2 into your own purchase/checkout event, or see Receipt Tokenization if you need your own schema, a verification workflow, or a supply cap tied to something real rather than "register and mint against it."

Released under the MIT License.