Documentation
Record agent output. Let anyone check it.
An agent records its final JSON output (or you record a file). The recipient gets the unchanged content, a record ID and a Verify link, and checks for themselves whether it matches what was recorded.
- What a check proves
- Record
- Keep the receipt
- Verify
- File or JSON event
- Arweave status
- When something goes wrong
- What leaves your device
- API reference
- For AI agents
- llms.txt
What a check proves — and what it doesn't
| Shown | Meaning |
|---|---|
| Content matches this record | The content you supplied produces exactly the hash recorded under this ID. |
| Recorded at | The time ClearedBadge's server accepted the record. Without an Arweave anchor this is ClearedBadge's own record of the time, not an independent timestamp. |
| Arweave status | What the ClearedBadge anchor service reports about publishing this record on Arweave. Separate from the content check. |
A match does not prove that the content is true or correct, which agent or organisation made it, that it was authorised, or that the other party received it. The record is created by the sender; it is not an acknowledgement of receipt.
Record
Agent output (JSON event) — through the connector
Save the agent's final output as one JSON object. Any fields are allowed; ClearedBadge does not interpret them.
The agent records it once with the ClearedBadge connector (tool register_event), after the user has
signed in: see For AI agents. Each account has a small registration quota.
The engine canonicalises the JSON with RFC 8785 and records the SHA-256.
POST /record-event is reserved for the ClearedBadge connector (a server credential). A direct request
without it is refused and records nothing; the earlier command-line agent recorder therefore no longer records on its own.
Do not retry a registration automatically. After a timeout the record may exist; a new registration creates a second, separate record.
A file — on the website
Use Record. Any file type up to 4 MB (4,000,000 bytes). No account is needed: to keep the registry open for everyone, the engine allows a few files per connection per hour and per day, and a total per day. The page shows the record ID, the Verify link and a downloadable receipt.
Keep the receipt
- The exact content — the unchanged file or
event.json. ClearedBadge keeps only the hash; the content cannot be recovered from the record. - The record ID and the Verify link:
https://clrbadge-web.vercel.app/verify?id=<record-id> - The receipt (
…clrbadge-receipt.json) with the engine's answer.
Hand the recipient the unchanged content together with the record ID or the Verify link.
Verify — for the recipient
- Open the Verify link (or go to Verify and enter the record ID).
- Drop the file you received, or choose Paste JSON instead and paste the JSON event.
- Press Verify. The comparison runs in your browser.
| Result | Meaning |
|---|---|
| ✓ Content matches this record | Your content produces the recorded hash. |
| ✕ Content does not match this record | Your content produces a different hash. Even one changed character or byte gives this result. |
| ! Unable to verify | The check could not run: for example invalid JSON, pasted text for a file record, or a record whose hashing method is not clear. This is not a mismatch. |
| ! Record not found / unreachable | No record for this ID, or the service could not be reached. Not a mismatch. |
Example from a real test: verify?id=baf74f78-5bc7-45e4-b55d-45f34d0f5d42 —
the original event.json matches; a copy with one value changed (900 → 901) does not.
File or JSON event
| Hash covers | Consequence | |
|---|---|---|
| File | SHA-256 of the exact bytes | Any change — also re-saving, reformatting or a changed PDF timestamp — gives no match. |
| JSON event | SHA-256 of the RFC 8785 canonical JSON | Whitespace and key order do not matter; every value does. Duplicate keys, NaN or Infinity cannot be checked. |
The record itself determines the method, never the file name. A .json file recorded through
Record is a file record: check it as a file, byte for byte. In the fields of
GET /verify/:id:
record_type: "file"— SHA-256 of the exact file bytes.record_type: "agent_commit"withcontent_type: "application/json",actor_type: "agent"andsource: null— RFC 8785 canonical JSON, then SHA-256.- Anything else — the method is not clear; do not guess.
For RFC 8785 use an existing implementation, for example canonicalize (npm, by RFC 8785 co-author Erdtman,
also served at /vendor/canonicalize.js) or rfc8785 (PyPI).
Sorting keys alone is not RFC 8785.
Arweave status: Submitted and Confirmed
| Submitted — confirmation pending | The anchor service has submitted a transaction. Not yet confirmed. |
| Confirmed on Arweave | The anchor service reports that its checks passed: at least 20 block confirmations and a matching hash of the published payload. |
| Not yet anchored | No anchoring attempt has been recorded yet. |
| Anchoring paused | New records are currently not anchored on Arweave. The record is stored in the ClearedBadge registry and can be verified; its recorded time is ClearedBadge's own record, without an independent external timestamp. |
| Anchoring not started | Anchoring was deliberately not started, with a reason: the daily limit or budget was reached, the anchoring wallet balance was too low, or anchoring was paused by configuration. The record itself is stored and can be verified; it is not anchored on Arweave, and it is not picked up again automatically. |
| Status temporarily unavailable | The status could not be retrieved. This does not mean the record is not anchored. |
The status is reported by the ClearedBadge anchor service; the Verify page does not itself read the chain.
To check independently: fetch the payload bytes from https://arweave.net/raw/<txid>, hash them with SHA-256,
compare with latest.payload_sha256 from /anchor-status, and check that the payload names this record ID and hash.
Block confirmations: https://arweave.net/tx/<txid>/status.
When something goes wrong
| Situation | What happened | What to do |
|---|---|---|
| HTTP 400 / 413 / 415 | Refused: invalid JSON, not a JSON object, too large, wrong content type. Nothing was recorded. | Fix the input and record again. |
| Timeout, dropped connection, HTTP 5xx | Outcome unknown. A record may exist. | Keep the attempt, do not send again blindly, and investigate first — see below. |
| File over 4 MB | Refused with 413 file_too_large. Nothing was recorded. | Use a smaller file. |
| Event over 1 MiB | Refused by the engine. Nothing was recorded. | Record a smaller event, e.g. with a hash of a large attachment inside it. |
HTTP 429 rate_limited | A registration limit was reached (per connection or in total). Nothing was recorded. | Try again after the time in Retry-After. |
HTTP 403 registration_paused, 503 registration_unavailable | Registration is switched off or cannot be checked right now. Nothing was recorded. | Try again later. |
After an unknown outcome
- Keep the attempt. Keep the unchanged content and what you know about the attempt. The connector reports an unknown outcome as such and never sends again on its own.
- Do not send again blindly. A second POST creates a second, separate record.
- Investigate first.
- File:
POST /verify-filewithout?id=(multipart, fieldfile) looks the file up by its hash and returnsresult: "match"with thebadge_idof the earliest record, ornot_found. This sends the file to the engine again; it is compared, not stored. - JSON event: there is no public lookup by content. Check whether a receipt was written or your own logs show a 201 with a
record_id.
- File:
- Only then decide. If no record can be found and you need a record ID, record again knowingly. If the first attempt did create a record, both records are valid; either ID verifies the same content.
What leaves your device
- Verify: the file or JSON you check stays in your browser. Only the record ID is sent, to fetch the recorded hash and the Arweave status.
- Record a file, Standard (the default): the file is sent over HTTPS to the ClearedBadge engine, which computes the SHA-256 of its exact bytes itself, in memory. ClearedBadge stores the hash and the time, not the file and not its name. The record says Server-calculated SHA-256.
- Record a file, Private: your browser computes the same SHA-256 of the exact bytes. Only that fingerprint is sent; the file, its name and its size stay on your device. The record says Device-calculated SHA-256: ClearedBadge registered the fingerprint it received and never saw the file.
- Record an event: the JSON is sent to the engine, which stores its hash, not the JSON. Do not put secrets in an event, and include personal data only if you may share it with a third-party service.
Both file methods give the same fingerprint for the same file and are verified the same way. Neither shows who made a file, that its content is true, or that anyone received it. The time on a record is when ClearedBadge registered the fingerprint (“Fingerprint registered by ClearedBadge at”); without external anchoring it is not an independently confirmed timestamp. Older records, made before the method was stored, show the fingerprint method as Not specified.
Recording is currently free. New records are kept in the ClearedBadge registry and are not anchored on Arweave for now. Record once per final output, not every step.
API reference
Using the API means you accept the Beta Terms; see the Privacy Policy for what the API receives and stores.
Engine: https://clrbadge-seven.vercel.app · Anchor service: https://clrbadge-anchor.vercel.app ·
Reading and verifying need no key. POST /upload and POST /record-file-hash are public with server-side limits, counted together; POST /record-event
is for the ClearedBadge connector only.
| Endpoint | Purpose |
|---|---|
POST /record-event | ClearedBadge connector only (server credential; otherwise 401 unauthorized or 403 record_event_disabled). Body: any JSON object (max 1 MiB). 201 → record_id, hash, canonicalization: "RFC8785", hash_algorithm: "SHA-256", recorded_at, status. 400 body_must_be_json_object / canonicalization_failed. |
POST /upload | multipart/form-data, field file, max 4,000,000 bytes. 201 → badge_id, hash, created_at, status, … 400 no_file, 413 file_too_large, 429 rate_limited (with scope, window, Retry-After), 403 registration_paused, 503 registration_unavailable. |
POST /record-file-hash | Private file registration: the body is exactly {"sha256":"<64 lowercase hex>"}, the SHA-256 of the exact file bytes, as text/plain or application/json (max 256 bytes; no file, no name, no size). 201 → the same fields as /upload, with fingerprint_method: "device_sha256" (/upload answers "server_sha256"). 400 invalid_fingerprint, 413 body_too_large; 429, 403 and 503 as for /upload, on the same limits. |
GET /verify/:id | The recorded facts: badge_id, hash, created_at, status, record_type, and metadata.fingerprint_method for newer file records. 400 invalid_id, 404 not_found. |
GET /anchor-status/:id | Anchor service. status: not_anchored, submitted, confirmed or failed, with latest.txid and latest.confirmed_at. When anchoring was not started: not_anchored plus not_started.reason and not_started.since; while new submissions are paused, not_started.reason is submission_paused (no since). |
POST /verify-event, POST /verify-file | Server-side comparison. These send your content to the engine; the Verify page does not use them. |
record_id and badge_id are the same identifier; recorded_at and created_at are the same time.
The same content may be recorded more than once; each record is separate.