Chromia Pay

AI agents

A skill file and an MCP server, so an agent can wire up the integration and then verify its own work.

The integration is entirely scriptable, which makes it delegable. Two ways in, depending on what your agent can load.

The skill

One Markdown file describing the whole integration — the flows, the invariants, the failure modes, and the order to do things in. It is the same material as this site, written for a model rather than a reader.

mkdir -p .claude/skills/chromia-pay
curl -o .claude/skills/chromia-pay/SKILL.md https://pay-docs.chromia.com/skill.md

# then: "integrate Chromia Pay into this app"

Reading these docs as Markdown

Every page here has a Markdown representation at the same URL, so an agent never has to parse HTML:

URLWhat you get
/docs/webhooks.mdThat one page as Markdown
/llms.txtAn index of every page, for deciding what to read
/llms-full.txtThe entire guide in one response
/skill.mdThe skill file above

An Accept: text/markdown header on any /docs/* URL gets the same thing without the suffix.

The MCP server

Tools rather than prose. An agent can create a payment, register an endpoint, force a confirmation and read the event back — which means it can check its own integration end to end instead of asking you to.

.mcp.json
{
  "mcpServers": {
    "chromia-pay": {
      "command": "bunx",
      "args": ["@chromia-pay/mcp"],
      "env": {
        "CPAY_SECRET_KEY": "cpay_sk_test_...",
        "CPAY_API_URL": "https://pay-api.chromia.com"
      }
    }
  }
}

Tools

ToolDoes
create_paymentCreate one and get its checkout_url
get_paymentStatus and attributed deposits
cancel_paymentCancel an unpaid one
list_webhook_endpointsWith what each is subscribed to
create_webhook_endpointRegister a URL; returns the signing secret once
set_webhook_eventsChange a subscription without rotating the secret
delete_webhook_endpointStop delivering
simulate_paymentForce confirmed / overpaid / underpaid / expired. Test keys only
get_eventRe-read a canonical event

Every tool above is a call to the same public API with the same key, so with a secret key this grants an agent nothing your own code could not do.

Give an agent a test key

Not because the tools are unsafe — they are the same API you are already exposing — but because an agent iterating on an integration will create payments, and those should be payments that cannot move real CHR. The server refuses simulate_payment outright with a live key, and says so.

Letting an agent run the store

Everything above is the integration. If you want an agent to operate the account — mint keys, set the payout address, change branding, manage who has access, work the reconciliation queue — that needs a different credential, and it is a genuinely different level of trust.

An agent token carries every action a dashboard admin can take. Mint one under Developers → Agent tokens, in the environment you want it to act in.

.mcp.json
{
  "mcpServers": {
    "chromia-pay": {
      "command": "bunx",
      "args": ["@chromia-pay/mcp"],
      "env": {
        "CPAY_SECRET_KEY": "cpay_at_test_...",
        "CPAY_API_URL": "https://pay-api.chromia.com"
      }
    }
  }
}

Same server, same variable. The prefix is what changes what it can reach: cpay_sk_ gets the tools above, cpay_at_ gets those and the account tools below.

Account tools

ToolDoes
whoamiWhich merchant, environment and mode, and whose behalf. Call it first
list_api_keys / create_api_key / revoke_api_keySecrets are returned once, at creation
list_payout_wallets / set_payout_wallet / retire_payout_walletWhere your CHR lands
get_store_preferences / set_store_preferencesUnderpayment tolerance, logo, accent colour
list_team / grant_team_access / revoke_team_accessWho can open the dashboard
list_environments / create_sandbox_environment
list_unattributed_deposits / attach_deposit_to_paymentThe reconciliation queue
read_audit_logEvery manual action, and whether a human or an agent took it
list_agent_tokens / revoke_agent_tokenIncluding revoking the one in use

Minting a token is deliberately not one of them. A credential that can mint its own successors cannot be revoked — you revoke it, and the one it made keeps working — so the chain has to start with a person in the dashboard.

What an agent token can do that a key cannot

This is full CRUD over your account, and Chromia Pay is non-custodial, so none of it is reversible by us. Specifically:

  • API keys it creates outlive it. Revoking the token does not revoke the keys.
  • It can change your payout address without the ownership signature the dashboard asks for, which redirects every payment made after that point.
  • It can grant dashboard access, and that grant also survives revocation.

Revoking stops it acting. It does not undo what it did — read_audit_log, filtered to the token, is how you find what needs unwinding by hand. Every token expires, at most 90 days out; prefer the shortest span that covers the work, and prefer a sandbox environment.

Attribution

Every action an agent takes is written to the audit log against the person who minted the token, marked as an agent, with the token's id:

{
  "action": "wallet.set",
  "actor": "you@yourstore.com",
  "actor_kind": "agent",
  "actor_token_id": "e67e6d5b-…",
  "detail": "bsc payout address set by agent, ownership asserted"
}

actor_email alone could not say this. "You revoked the live key" and "an agent you authorised revoked the live key" are different events, and only one of them means you knew at the time.

Payout addresses an agent sets

set_payout_wallet requires unverified: true, because an agent cannot produce an ownership signature. That is not a formality — it is the flag that makes the agent state what it is doing, and the address is recorded as asserted rather than proved.

The same path exists for you in the dashboard, under "Add an address I can't sign with", and it exists because the proof is impossible for the address merchants most often want: you hold no key for an exchange deposit address and you cannot send from it.

Not an exchange address on Chromia

On the native rail, a payer's transfer carries Chromia Pay's own cpay:<REF> memo. An exchange that needs its memo to credit your deposit receives ours instead, and the funds are lost inside the exchange with no way for anyone to recover them. Use an address you control on Chromia; exchange deposit addresses are fine on BNB Smart Chain and Base.

On this page