NewDash Dots are hereMini apps in Dash, with payments built inLearn more

Developer Resources · AI Development Tools

Rules for coding agents

A rules file that teaches AI coding agents, such as Claude Code, Cursor and Copilot, how to integrate with the Monime API safely.

AI coding agents write better Monime integrations when they know the rules up front: which headers every request needs, how money is written, how to retry safely and how to verify webhooks. The rules below put those in one short file. Add it to your project and your agent follows them in every session.

The same file is published at https://docs.monime.io/agents.md, so you can download it or point an agent at it.

Add the rules to your project

Download the file into your project with the name your agent reads:

AgentWhere the rules go
Codex, Cursor, Jules, Zed, AmpAGENTS.md in the project root
Claude CodeCLAUDE.md in the project root, or AGENTS.md imported from it with a line @AGENTS.md
GitHub Copilot.github/copilot-instructions.md

For example, for an AGENTS.md:

Terminal
curl -fsSL https://docs.monime.io/agents.md -o AGENTS.md

If your project already has a rules file, add the Monime rules to the end of it instead:

Terminal
curl -fsSL https://docs.monime.io/agents.md >> AGENTS.md

Pair the rules with the Monime MCP server, so your agent can look up endpoints and guides while it works.

The rules

AGENTS.md
# Monime API integration rules

These rules apply to any code in this project that calls the Monime API,
receives Monime webhooks or builds a Dash Dot. Docs: https://docs.monime.io
(add `.md` to any page URL for Markdown; the index is
https://docs.monime.io/llms.txt, and every Dash Dots page is in
https://docs.monime.io/llms-dots.txt). OpenAPI specification:
https://docs.monime.io/apis/openapi.json

## Requests

- Base URL: `https://api.monime.io`. Paths start with `/v1/`, for example
  `POST /v1/checkout-sessions`.
- Send these headers on every request:
  - `Authorization: Bearer <access token>`
  - `Monime-Space-Id: <space id>` (IDs start with `spc-`)
  - `Content-Type: application/json` when there is a body
  - `Monime-Version: caph.2025-08-23` to pin the API release
- Read the token and Space ID from configuration or a secrets manager. Never
  hard-code them, commit them, log them or send them to a browser or mobile
  app: call Monime only from a server.
- Use a test token (it starts with `mon_test_`) in development, CI and
  staging. Live tokens start with `mon_` without `test_`. Test and live are
  fully separate: objects, webhooks and limits do not cross over.
- Successful responses are `{ "success": true, "messages": [], "result": ... }`.
  Errors are `{ "success": false, "error": { "code", "reason", "message",
  "details" } }`. Branch on `error.reason`, not on `message`.
- Log the `Monime-Request-Id` response header with every failure.

## Money

- Amounts are `{ "currency": "SLE", "value": <integer> }` and `value` is in
  minor units: SLE 250.00 is `{ "currency": "SLE", "value": 25000 }`. Never
  use floating point for money. Supported currencies: `SLE`, `USD`.
- Timestamps are RFC 3339 in UTC, such as `2025-08-24T06:00:00Z`.

## Creating things safely

- Send an `Idempotency-Key` header on every POST that creates something or
  moves money (checkout sessions, payouts, payment codes, internal transfers,
  financial accounts, webhooks, receipt redemptions, USSD OTPs).
- Use a UUID v4, or a UUID v5 derived from your own reference (such as
  `payout:order-123`) so a retry after a crash reuses the same key. Store the
  key with your record before calling Monime. Never put personal data in it.
- Retry with the same key and the identical method, URL and body. Keys are
  remembered for 24 hours; a replayed response has `Monime-Cache: irc`.
- A `409` with reason `idempotency_key_in_use` means the key was reused for a
  different request: fix the code that chose the key, don't retry.
- If you don't know whether a create succeeded, GET the object before trying
  again.

## Retries and rate limits

- Retry network errors and `5xx` responses with exponential backoff and
  jitter. Don't retry other `4xx` errors without changing the request.
- On `429`, wait the number of seconds in `Retry-After`, then retry. The
  `Monime-Rate-Limit` header says which limit was hit (`token-limit`,
  `space-limit` or `endpoint-limit`). A throttled request had no effect.
- Use webhooks to learn about changes instead of polling.

## Lists

- Lists are paginated with `limit` (1 to 50) and `after`. Pass the response's
  `pagination.next` as `after`, and stop when `next` is missing or null.
  Cursors are opaque: never build or edit them.

## Metadata

- `metadata` is a flat map of up to 64 string values of 100 characters or
  less. Keys use letters, digits, `_` and `-`, and can't start with `_`, `-`
  or `monime`. Don't store secrets or personal data in it.

## Webhooks

- Verify every delivery before acting on it, using the raw request body
  exactly as received (not re-serialised JSON):
  - The `Monime-Signature` header looks like `t=<unix seconds>,v1=<signature>`.
  - For HMAC webhooks, the signature is base64 of
    HMAC-SHA256(webhook secret, `<t>` + `_` + raw body). The separator is an
    underscore, and the output is base64, not hex.
  - Compare signatures in constant time.
  - Reject deliveries where `t` is more than 300 seconds old or more than 60
    seconds in the future.
  - On failure, respond `401` without processing or explaining why.
- The webhook secret is not the API token. Keep it in configuration.
- Store the event, respond `2xx` within 5 seconds, then process it in the
  background. Anything else is retried.
- Deliveries can repeat and arrive out of order: deduplicate on `event.id`
  (it starts with `wke-`) for at least 24 hours, and read the object's current
  state rather than assuming the order of events.
- Webhook URLs must be public HTTPS. For local development, expose your server
  through a tunnel.
- Don't poll to find out when a checkout is paid: handle
  `checkout_session.completed`.

## Dash Dots

A dot is a mini app that runs inside Dash, built with the Dot framework and
the Monime CLI (`monime dot dev`, `build`, `publish`). Check the
components and calls you use in the reference:
https://docs.monime.io/docs/products/dash-dots/reference

- `dot.json` has `package` (a reverse domain name that never changes once
  published), `name`, `version` (semver, raised every release), and the `id`
  `monime dot register` writes. Nothing else but `$schema`, `permissions`,
  `network` and `dash.minApiVersion` (the Dash API version the dot needs,
  `1.0` by default).
- A dot belongs to a Space, not to the developer. Register, publish and
  release it in the business's Space (`monime space use`, or `--space`),
  which the developer must be a member of.
- List every host the dot calls in `network.hosts`; other requests fail as
  `denied`. List pages in `dot.ts` with `defineDot({ pages })`; the first is
  the entry page.
- Each page is `view.dml`, `state.ts` (a default export of JSON-only data)
  and `controller.ts` (`export default definePage({ ... })`).
- A `view.dml` has exactly one root `<View>`, and loose text only inside
  `<Text>`, `<Button>` and similar. Use only the documented components and
  props; there are no stylesheets and no `class`.
- `{{ }}` bindings read state with operators and `?:` only: they can't call
  functions or change values. Compute values in mutations.
- Event attributes (`onTap="choose"`) name a mutation or action in the
  page's controller. Mutations are pure: `(state, event) => changes`.
  Actions may be async; only actions get `this.navigation`.
- In pages, call Dash through `this.dash`, never the global `dash`. Every
  call can fail with a `DashError` (`unsupported`, `denied`, `cancelled`,
  `timeout`, `invalid`, `missing`, `failed`): check it with
  `isDashError(error, 'denied')` from `@monimesl/dot-runtime`, and carry on.
- Dash API 1.0 is stable. Before a call newer than the dot's
  `minApiVersion`, check `this.dash.supports('feature.name')`.
- Navigation options are strings, and at most 16 pages are open at once.
- A dot's code and `.env` are public. Keep secrets and prices on your server,
  and check every request there.
- `AmountInput` counts minor units unless `unit="major"`: 150 is SLE 1.50.
- Style with props, not CSS: `View` takes `background`, `border`, `radius`,
  `width`, `height` and `aspect`; `Text` takes `tone="onPrimary"` on a
  `primary` background. Name the dot's own colors in `theme.colors.custom`
  and use them by name. A page sets its own colors with `configs.colors`
  or `this.setColors()`.
- `dash.media.pickPhoto`, `dash.media.scanCode`, `dash.media.pickFile`
  and `dash.contacts.pickPhone` need the `photoLibrary` or `camera`,
  `camera`, `files` and `contacts` permissions. Wrap pickers in
  `unlessCancelled` (from `@monimesl/dot-runtime`): closing one isn't an
  error. Show `errorMessage(error)` for anything else, and `save` a picked
  file to keep it.
- Type handlers with `ValueEvent`, `CheckedEvent`, `IndexEvent` and
  `DataEvent<{ ... }>`. Use `this.navigation.pushForResult` and
  `backWithResult` to get a choice back from a page, and an `onRefresh`
  hook for pull to refresh. Let a share link open a page with
  `definePage({ share: { options: [...] } })`, and check those options in
  `onLoad`: anyone can write a link.
- `dash.account.signIn({ mode: 'simple' })` names the person, but a server
  can't verify its token. Don't treat it as proof for moving money.
- `statics/` holds only PNG, JPEG, GIF or WebP images of 1 MB or less; no
  SVG.
- Give every `<For>` a `key`. Test pages with `testPage` from
  `@monimesl/dot-runtime/testing`, faking Dash calls with its `host` option.

What the rules cover

  • Requests: the base URL, the headers every request needs, and keeping tokens on your server.
  • Money: amounts in minor units, so an agent never sends SLE 1.00 when you meant SLE 100.
  • Creating things safely: idempotency keys, so retries never charge or pay twice.
  • Retries and rate limits: what to retry, and how to back off from rate limits.
  • Lists and metadata: pagination and metadata limits.
  • Webhooks: signature verification and safe, repeatable handling.

Review what your agent writes as you would any code, especially anything that moves money. Test it end to end in test mode before you switch to a live token.

Keep reading