Colter

Agent instructions · colter.agent_buyer.v1

Buy a work check for your customer.

Exact steps for an agent that can send HTTP requests or use MCP: register, request a check, pay, follow the job, read the report, review the delivery, and recover after any interruption. What the check does, and its terms, are on colter.ai/check.

$5.00 per check. Not available to buy right now: no payment method is ready.

Prompt for your coding agent

Buy your first work check

Your coding agent registers for you, buys one check from a small script in your project, and reads the report with you. Credentials stay in .env, never in the chat.

Paste it into Claude Code, Codex, Cursor, or any agent that can read files and run commands.

View as Markdown
Read the full prompt
# Buy your first Colter work check

**Colter's work check** checks work an AI agent produced against the original request, stated criteria, and the evidence you name, and returns findings, citations, the checks performed, limitations, and a verdict. This prompt walks you through registering me with Colter, buying one check from a small script in my project, and reading the report with me.

**Price:** $5.00 per check, fixed.
**Right now:** Not available to buy right now: no payment method is ready. Do the first setup step, tell me, and stop.
**Docs:** https://colter.ai/docs/agents (exact steps) and https://colter.ai/check (terms, remedy, sample report)
**Contract:** https://api.colter.ai/api/agent/v1/services/colter_work_check needs no credential. It is the source of truth for schemas, price, and live availability, so read it before writing code. Index for agents: https://colter.ai/llms.txt

## Ground rules

- Credentials and the registration poll secret never go in this chat, in prompts, in job input, or in URLs. Scripts write them to `.env` and never print them. Do not print or display `.env`.
- Ask me before anything that commits me: accepting Colter's terms, buying, paying, accepting, or disputing.
- Retry with the same idempotency key and the same body. A timeout never cancels a job and never permits buying again; read the job to recover.
- Do only what the job's `next_actions` allows.

## Setup

Check each item IN ORDER. Stop at the first missing one, fix it, then resume after I confirm.

1. **Availability.** `GET https://api.colter.ai/api/agent/v1/services/colter_work_check`. Continue only if `service.availability.state` is `available` or `sandbox`, and pay only with a rail in `service.availability.purchasable_rails`. If it is `unavailable`, tell me the `reasons` and stop.
2. **Node.js 22+.** `node --version`. The scripts use built-in `fetch` and `--env-file`; no packages are needed.
3. **A project folder.** Ask me where my project lives. If I don't have one: `mkdir colter-check && cd colter-check && npm init -y && npm pkg set type=module`.
4. **Secrets stay out of git.** Add `.env` and `.colter/` to `.gitignore` before anything writes to them.
5. **Colter's terms.** Show me https://colter.ai/legal and ask whether I accept terms version `2026-07-21`. Send `accept_terms_version` only after I say yes.
6. **A Colter credential.** If `.env` already has `COLTER_TOKEN`, check it with `GET https://api.colter.ai/api/agent/v1/me` without printing it, and skip this step. Otherwise ask me which applies:
   - **I'm new to Colter:** ask for my email (an email is not a secret). Run `register.mjs` below with it. Colter emails me; I confirm on the linked page. If I read you the code instead, POST `{"code": "<code>"}` to `https://api.colter.ai/api/agent/v1/registrations/<key>/verify` with the `X-Colter-Registration-Secret` header read from `.env`, without printing it.
   - **I already have a Colter account:** run `register.mjs` with no email. It prints a link and a `user_code`; I approve the connection while signed in.

   The default grant lets the credential buy work checks of up to $10.00 each and review what they deliver. I can change or revoke it in Colter at any time.

## Register (writes the credential to .env, prints no secrets)

Reference shape. Verify field names against https://colter.ai/docs/agents#authenticate.

```js
// register.mjs: node register.mjs [email]. Rerun to resume; it never starts a second registration.
import { appendFileSync, existsSync, readFileSync } from "node:fs"

const API = "https://api.colter.ai/api/agent/v1"
const env = existsSync(".env") ? readFileSync(".env", "utf8") : ""
const saved = (name) => env.match(new RegExp(`^${name}=(.*)$`, "m"))?.[1]
const save = (name, value) => appendFileSync(".env", `${name}=${value}\n`, { mode: 0o600 })
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

async function call(method, path, { body, headers = {} } = {}) {
  const res = await fetch(API + path, {
    method,
    headers: { "content-type": "application/json", ...headers },
    body: body && JSON.stringify(body)
  })
  const json = await res.json().catch(() => ({}))
  if (!res.ok) throw new Error(`${method} ${path}: ${res.status} ${json.error?.details?.reason ?? json.error?.code}`)
  return json
}

if (saved("COLTER_TOKEN")) {
  console.log("COLTER_TOKEN is already in .env.")
  process.exit(0)
}

let key = saved("COLTER_REGISTRATION_KEY")
let secret = saved("COLTER_POLL_SECRET")

if (!key) {
  const email = process.argv[2]
  const started = await call("POST", "/registrations", {
    body: {
      mode: email ? "new_customer" : "link_existing",
      ...(email && { email }),
      agent_name: "My coding agent",
      agent_client: { name: "colter-prompt", version: "1" },
      accept_terms_version: "2026-07-21" // only after I accept https://colter.ai/legal
    }
  })
  key = started.registration.registration_key
  secret = started.poll_secret // shown once
  save("COLTER_REGISTRATION_KEY", key)
  save("COLTER_POLL_SECRET", secret)
}

const headers = { "x-colter-registration-secret": secret }
let announced = false

for (;;) {
  const { registration } = await call("GET", `/registrations/${key}`, { headers })
  if (registration.status === "approved") break
  if (["denied", "expired", "completed"].includes(registration.status))
    throw new Error(`Registration ${registration.status}. Remove COLTER_REGISTRATION_KEY and COLTER_POLL_SECRET from .env to start again.`)
  if (!announced) console.log("Waiting for you:", JSON.stringify(registration.pending_action))
  announced = true
  await sleep(5000)
}

// The credential is released exactly once.
const { credential } = await call("POST", `/registrations/${key}/token`, { headers })
save("COLTER_TOKEN", credential.token)
console.log("Credential saved to .env. Expires", credential.expires_at, "Scopes:", credential.scopes.join(", "))
```

## Buy one check

Ask me for the work to check: what my agent produced (`work_product`), the original `request` or the `criteria`, and the `evidence` behind it, each item with a `source` name. Write it to `work.json` in the shape of `example_request` in the contract (without its `idempotency_key` and `max_price_microcents`). If I have nothing ready, offer the contract's example. Then ask me to confirm the purchase at $5.00 before running `node --env-file=.env check.mjs`.

```js
// check.mjs: node --env-file=.env check.mjs. Rerun after any crash; it resumes the same purchase.
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
import { randomUUID } from "node:crypto"

const API = "https://api.colter.ai/api/agent/v1"
const auth = { authorization: `Bearer ${process.env.COLTER_TOKEN}` }
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

async function call(method, path, body) {
  const res = await fetch(API + path, {
    method,
    headers: { ...auth, "content-type": "application/json" },
    body: body && JSON.stringify(body)
  })
  const json = await res.json().catch(() => ({}))
  if (res.status >= 400) throw new Error(`${method} ${path}: ${res.status} ${json.error?.details?.reason ?? json.error?.code}`)
  return json
}

// Save the exact body and key before sending; a rerun resends them unchanged.
mkdirSync(".colter", { recursive: true })
const file = ".colter/purchase.json"
const purchase = existsSync(file)
  ? JSON.parse(readFileSync(file, "utf8"))
  : {
      ...JSON.parse(readFileSync("work.json", "utf8")),
      idempotency_key: `check-${randomUUID()}`,
      max_price_microcents: 500000000, // your ceiling; 100,000,000 microcents = $1
      authorize: true,
      payment: { rail: "card", method: "auto" }
    }
writeFileSync(file, JSON.stringify(purchase, null, 2))

const { purchase: bought } = await call("POST", "/checks", purchase)
const jobKey = bought.job_key
if (!jobKey) {
  console.log("The quote needs authorizing:", JSON.stringify(bought.next_actions))
  process.exit(0)
}
writeFileSync(".colter/job_key", jobKey)

// A person pays by card on Colter's page unless a saved card covers it.
let job = (await call("GET", `/jobs/${jobKey}`)).purchase
if (["awaiting_payment", "awaiting_payer"].includes(job.stage)) {
  const { payment } = await call("POST", `/jobs/${jobKey}/payments`, { rail: "card", method: "auto" })
  if (payment.continuation_url) console.log("Open this link to pay:", payment.continuation_url)
}

const settled = ["delivered_awaiting_review", "accepted", "rejected", "inconclusive", "completed", "failed", "canceled"]
while (!settled.includes(job.stage)) {
  await sleep(5000)
  job = (await call("GET", `/jobs/${jobKey}`)).purchase
  console.log("stage:", job.stage)
}

const report = await fetch(`${API}/jobs/${jobKey}/report?format=markdown`, { headers: auth })
if (report.ok) writeFileSync(".colter/report.md", await report.text())
console.log(`Job ${jobKey} is ${job.stage}.`, report.ok ? "Report: .colter/report.md" : "")
```

When a payment link prints, give it to me. I pay on Colter's page; the script continues on its own once payment is collected.

## Review it with me

1. Summarize `.colter/report.md` for me: the verdict (`supported`, `revise`, `escalate`, or `insufficient_evidence`), the findings, and whether a person must review the work before it is used. An adverse verdict is a delivered check, not a failure.
2. Ask me to accept or dispute. Accept when the report evaluated every criterion and cited only supplied or retrieved sources, whatever its verdict. Dispute when it did not do what the contract promised; `reason_code` is one of check_not_performed, criteria_not_evaluated, citation_invalid, report_incomplete, wrong_input_assessed, other.
3. Send my decision with `POST https://api.colter.ai/api/agent/v1/jobs/<job_key>/review`: `{"decision": "accept"}`, or `{"decision": "dispute", "reason_code": "...", "rationale": "...", "idempotency_key": "..."}`. Review within 72 hours; silence is never acceptance.
4. Fetch `GET https://api.colter.ai/api/agent/v1/jobs/<job_key>/receipt` and save it to `.colter/receipt.json`. A receipt records payment; it does not certify the work.

## Common stuck points

| Symptom | Fix |
|---|---|
| `service_unavailable` | The check is paused or has no payment rail. Tell me the `availability_reasons`; don't retry in a loop. |
| `registrations_paused`, `registration_not_admitted`, or `registration_cohort_full` | Registration is limited right now. Stop and point me to https://colter.ai/contact. |
| Registration waits on `verify_email` | I haven't confirmed yet. Keep polling the same registration; don't start another. |
| `registration_expired` or `credential_already_issued` | Remove the registration lines from `.env` and run `register.mjs` again. |
| 401 on any call | The credential is missing, expired, or revoked. Check the script ran with `--env-file=.env`; otherwise register again. Never ask me to paste it. |
| `work_check_input_invalid` | Fix `work.json` against `input_schema` in the contract, delete `.colter/purchase.json`, and rerun. Nothing was collected. |
| `idempotency_conflict` | The key was reused with a different body. Resend `.colter/purchase.json` unchanged. A new purchase needs a new key and my OK. |
| `purchase_price_limit_exceeded` or a `grant_*_limit_exceeded` | The price is above my ceiling or grant. Tell me; don't raise limits yourself. |
| `payment.state` is `uncertain` | Resend the identical payment request. Never start a new purchase. |
| `payment_attempt_closed` or the link expired | POST the payment again for a fresh link. |
| `grant_review_not_permitted` or `customer_reviewer_required` | I review it in Colter myself. Give me the job key. |
| The script crashed or timed out mid-purchase | Rerun `check.mjs`. It resends the saved body and key, and Colter returns the same job. |

## Done

You registered me with Colter, bought one check, and reviewed its report with me.

Next, if I want it:
- Call the same `POST /checks` from my agent's code before it acts on or sends an answer, keeping one saved body and idempotency key per purchase.
- Use MCP instead of REST: add a remote HTTP MCP server at `https://api.colter.ai/mcp?profile=buyer` with `Authorization: Bearer <credential>` in the client's protected connection settings. Tools: `colter.whoami`, `colter.check_work`, `colter.purchase_status`, `colter.authorize_purchase`, `colter.pay`, `colter.cancel_payment`, `colter.get_report`, `colter.review_delivery`, `colter.get_receipt`, `colter.cancel_job`.
- Pay from a wallet with x402 (USDC) where offered: follow https://colter.ai/docs/agents#pay and sign with the wallet's own tooling. Never paste a private key here.

00 · no credential needed

Read the contract and its live availability.

GET https://api.colter.ai/api/agent/v1/services/colter_work_check

The response carries the input and output schemas, terms, price, the sample report, and availability. Buy only when availability.state is available or sandbox, and pay only with a rail listed in availability.purchasable_rails. sandbox means test money: Stripe test mode, Radius Testnet, or Base Sepolia. Tell your customer so; nothing real is charged.

Right now: state is unavailable and purchasable_rails is [].

Index of every buyer endpoint: https://api.colter.ai/api/agent/v1. Agent manifest: colter.ai/.well-known/colter.

01 · authenticate

Register for your customer, link an account, or prove a wallet.

Credentials never go in prompts, job input, or URLs. Store credentials in protected client storage. Never put them in prompts, job input, or URLs.

New customer, by email

Register for your customer by email. They confirm by link or by reading you a code; Colter then creates their prepaid account and releases your credential once. accept_terms_version must be 2026-07-21, the current Colter terms. No account is created until your customer confirms.

POST https://api.colter.ai/api/agent/v1/registrations
Content-Type: application/json

{
  "accept_terms_version": "2026-07-21",
  "agent_client": {
    "harness": "your-harness",
    "name": "your-agent",
    "version": "1.0"
  },
  "agent_name": "Avery's research assistant",
  "customer_name": "Avery Example",
  "email": "[email protected]",
  "mode": "new_customer"
}

The 201 response returns registration.registration_key, registration.pending_action, and a poll_secret shown once. Keep the poll secret with the credential. Omit requested_authority to request the default grant:

{
  "daily_limit_microcents": 5000000000,
  "governed_refs": false,
  "payment_methods": [
    "card_checkout",
    "card_saved",
    "x402"
  ],
  "per_job_limit_microcents": 1000000000,
  "review_authority": true,
  "service_keys": [
    "colter_work_check"
  ],
  "total_limit_microcents": null
}

Poll the registration until pending_action.action is exchange_credential:

GET https://api.colter.ai/api/agent/v1/registrations/{registration_key}
X-Colter-Registration-Secret: <poll_secret>

While it is verify_email, ask your customer to open Colter's email and either confirm on the linked page or read you the code. Submit the code:

POST https://api.colter.ai/api/agent/v1/registrations/{registration_key}/verify
X-Colter-Registration-Secret: <poll_secret>
Content-Type: application/json

{
  "code": "ABCD-EFGH"
}

Then exchange once for the credential. It is released exactly once:

POST https://api.colter.ai/api/agent/v1/registrations/{registration_key}/token
X-Colter-Registration-Secret: <poll_secret>

The 201 response carries credential.token (a Bearer token), expires_at, and scopes. Send it on every call as Authorization: Bearer <credential>.

Existing Colter account

Start with mode link_existing; a signed-in member of the account approves the connection and its limits. Send "mode": "link_existing" (no email). pending_action is then approve_connection with a url and user_code for your customer; poll and exchange as above.

Wallet

Prove control of an EVM wallet by signing a Sign-In with Ethereum message (EIP-191 personal_sign); no email or password. Wallet buyers pay per job with a stablecoin over x402: SBC on Radius, or USDC on Base. Signing in authorizes no payment.

POST https://api.colter.ai/api/x402/v1/wallets/challenge
Content-Type: application/json

{
  "address": "0xYOUR_WALLET_ADDRESS"
}

Sign challenge.message with the wallet (EIP-191 personal message), then verify:

POST https://api.colter.ai/api/x402/v1/wallets/verify
Content-Type: application/json

{
  "nonce": "<challenge.nonce>",
  "signature": "0x<signature>"
}

Use session.token as the Bearer credential and send X-Colter-Workspace: <session.workspace>. Wallet buyers pay with x402.

Check, rotate, or revoke the credential

GET https://api.colter.ai/api/agent/v1/me
Authorization: Bearer <credential>

/me returns your identity, grant, spend so far, payment options, and availability. POST https://api.colter.ai/api/agent/v1/credentials/rotate issues a new credential; the old one stops working 10 minutes later. DELETE https://api.colter.ai/api/agent/v1/credentials/current revokes the credential you are using.

02 · request

Submit the work, with a key and a ceiling.

Save the exact body before you send it. Reuse the same idempotency_key (or an Idempotency-Key header) for every retry of this purchase.

POST https://api.colter.ai/api/agent/v1/checks
Authorization: Bearer <credential>
Content-Type: application/json

{
  "authorize": true,
  "criteria": [
    "States the policy window",
    "Uses the order's actual age"
  ],
  "evidence": [
    {
      "source": "refund_policy_v3",
      "text": "Refunds are available within 30 days of purchase."
    },
    {
      "source": "order_1042",
      "text": "Order 1042 was placed 45 days ago."
    }
  ],
  "idempotency_key": "check-order-1042-refund",
  "max_price_microcents": 500000000,
  "payment": {
    "method": "auto",
    "rail": "card"
  },
  "request": "Is the refund for order 1042 within the 30-day policy?",
  "work_kind": "answer",
  "work_product": "Yes. Order 1042 was placed 45 days ago, which is within the 30-day policy."
}
  • work_product, evidence, and request or criteria are required. Limits are on the service page.
  • max_price_microcents is your ceiling. One US dollar is 100,000,000 microcents; the current price is 500000000 ($5.00).
  • authorize: true accepts the frozen quote immediately when it is within your grant. Otherwise the response is a quote to authorize.
  • payment is optional. When present, Colter also attempts collection in the same call.

The response has purchase (with quote_key, job_key, stage, and next_actions), plus payment when you sent one. Invalid or unsupported work is refused with error.details.reason work_check_input_invalid and collected: false.

To authorize a quote later, or inspect it:

POST https://api.colter.ai/api/agent/v1/purchases/{quote_key}/authorize
Authorization: Bearer <credential>
Content-Type: application/json

{
  "payment": {
    "method": "auto",
    "rail": "card"
  }
}
GET https://api.colter.ai/api/agent/v1/purchases/{quote_key}
Authorization: Bearer <credential>

03 · pay

Payment is collected before work starts.

Card:

POST https://api.colter.ai/api/agent/v1/jobs/{job_key}/payments
Authorization: Bearer <credential>
Content-Type: application/json

{
  "method": "auto",
  "rail": "card"
}

method is card_saved (charge the customer's saved card), card_checkout (return a payment link for a person), or auto (the saved card when there is one and your grant permits it, otherwise a link). Add "save_method": true to ask the payer to save the card; the payer decides.

x402 (USDC):

POST https://api.colter.ai/api/agent/v1/jobs/{job_key}/payments
Authorization: Bearer <credential>
Content-Type: application/json

{
  "rail": "x402"
}

The response is HTTP 402 with a base64 JSON payment-required header and the same requirements in the x402 field. Sign an exact payment for that amount, asset, network, and recipient, then resend the same request with PAYMENT-SIGNATURE: <base64 payment payload>. A settled payment returns a payment-response header.

payment.stateWhat to do
collected (200)Work starts. Follow the job.
requires_payer (202)Give your customer continuation_url; they pay on Colter's page before continuation_expires_at. Then follow the job.
pending (202)The provider is still processing. Follow the job.
uncertain (202)Resend the identical payment request. Do not start a new purchase.
payment_required (402)Sign the x402 payment and resend with PAYMENT-SIGNATURE.

Stop an unfinished payment with POST https://api.colter.ai/api/agent/v1/jobs/{job_key}/payments/cancel.

04 · status

Follow the job. Do only what next_actions allows.

GET https://api.colter.ai/api/agent/v1/jobs/{job_key}
Authorization: Bearer <credential>

purchase reports identity, authority, payment, execution, delivery, charge, and remedy separately, and lists next_actions as {action, actor, method, path}. purchase.stage is one of quoted, awaiting_payment, awaiting_payer, payment_pending, executing, waiting_for_input, correction_in_progress, delivered_awaiting_review, accepted, rejected, inconclusive, completed, failed, or canceled.

05 · result

Read the report.

GET https://api.colter.ai/api/agent/v1/jobs/{job_key}/report
Authorization: Bearer <credential>

Add ?format=markdown for the readable report as text/markdown. The verdict is supported, revise, escalate, or insufficient_evidence. An adverse verdict is a delivered check, not a failure. requires_human_review says whether a person must approve the assessed work before it is used. See the sample report.

06 · review

Accept the delivery or dispute it.

Review within 72 hours. Accept when the report evaluated every criterion and cited only supplied or retrieved sources, whatever its verdict:

POST https://api.colter.ai/api/agent/v1/jobs/{job_key}/review
Authorization: Bearer <credential>
Content-Type: application/json

{
  "decision": "accept"
}

Dispute a delivery that did not do what the contract promised. The first dispute gets 1 correction re-check at no charge; a dispute after the correction waives the charge and refunds it.

POST https://api.colter.ai/api/agent/v1/jobs/{job_key}/review
Authorization: Bearer <credential>
Content-Type: application/json

{
  "decision": "dispute",
  "idempotency_key": "dispute-order-1042-refund",
  "rationale": "The report did not evaluate the second criterion.",
  "reason_code": "criteria_not_evaluated"
}

reason_code is one of check_not_performed, criteria_not_evaluated, citation_invalid, report_incomplete, wrong_input_assessed, other. An overdue review stays pending; silence is never acceptance.

07 · receipt

Keep the receipt. Cancel only on purpose.

GET https://api.colter.ai/api/agent/v1/jobs/{job_key}/receipt
Authorization: Bearer <credential>

The receipt records collection, the final charge, and any remedy separately. A receipt records payment; it does not certify the work.

POST https://api.colter.ai/api/agent/v1/jobs/{job_key}/cancel
Authorization: Bearer <credential>
Content-Type: application/json

{
  "reason": "Customer withdrew the request."
}

A job canceled before delivery receives the failed-delivery remedy on the service page.

Recovery

Resume the same purchase. Never buy twice.

  • Retry any request with the same idempotency key and body; a changed body under the same key is a conflict.
  • A client timeout never cancels the job and never permits buying again; read the job to recover.
  • An uncertain card payment is retried with the identical payment request.
  • After re-authenticating, the same principal sees the same quotes, jobs, reports, and receipts.
  • An overdue review stays pending; silence is never acceptance.

Errors return error.code, error.message, and a stable error.details.reason.

MCP

The same steps as MCP tools.

Add a remote HTTP MCP server at https://api.colter.ai/mcp?profile=buyer and configure Authorization: Bearer <credential> in the client's protected connection settings. Register with REST first; MCP needs the credential.

  • colter.whoami
  • colter.check_work
  • colter.purchase_status
  • colter.authorize_purchase
  • colter.pay
  • colter.cancel_payment
  • colter.get_report
  • colter.review_delivery
  • colter.get_receipt
  • colter.cancel_job

Browsing-only assistants

Cannot send requests? Return a continuation.

Reading this page does not give you API or payment access. Do not tell your customer you bought a check. Return to them instead:

  1. The link https://colter.ai/check and these instructions, https://colter.ai/docs/agents.
  2. The exact request you prepared: the work, the original request or criteria, and each piece of evidence with its source name, in the shape of the example above.
  3. What happens next: an execution-capable agent submits it unchanged, the customer confirms the registration email, and, if a card payment needs them, opens the continuation_url Colter returns. They never share a password or card number with an agent.

Custom or unsupported work? Contact Colter.