Moat CI API
Read stored results, submit evidence and request a confirmed re-read through the versioned API contract.
Availability
The integration source is available for review. Account API access still needs deployment, migration and a verified account connection before use. These examples describe the source contract; they do not establish a live service.
Endpoints and permissions
GET /api/v1/moat returns your latest stored reading; optional dossierId selects an owned dossier. GET /api/v1/readings/{id} retrieves an owned reading. Both require read scope. POST /api/v1/evidence requires evidence:write. POST /api/v1/readings requires reading:run. Every account request uses an API key bearer. IDs must be UUIDs. A reading is an opinion on the supplied evidence, not a valuation or a prediction of returns.
Read the latest result
Provide MOATDEFENDER_API_KEY privately in the process environment. This Node 20+ example prints the response without printing the key. The example response is a successful account lookup with no stored reading; it is illustrative, not a production result. Omit the query string to request the latest reading across your account.
const response = await fetch(
"https://moatdefender.com/api/v1/moat?dossierId=11111111-1111-4111-8111-111111111111",
{
headers: { Authorization: `Bearer ${process.env.MOATDEFENDER_API_KEY}` },
redirect: "error",
},
);
console.log(response.status, await response.json());{
"ok": true,
"reading": null
}Append evidence
Use an owned dossier ID in place of the example UUID. Text is trimmed and must contain 8–20,000 characters, including at least eight letters or numbers. Identical normalized evidence is deduplicated. Evidence remains an unverified claim: this request does not run a reading or spend MoatTokens. The request body below is the complete accepted shape.
{
"dossierId": "11111111-1111-4111-8111-111111111111",
"text": "Example release evidence reviewed by the owner."
}Quote before a re-read
Send this JSON to POST /api/v1/readings with Content-Type: application/json and your bearer. The example assumes new evidence exists and no reusable reading exists. The source contract currently quotes 150 MoatTokens; always use the cost returned by the server. HTTP 402 with confirmation_required is a quote and spends no tokens. The UUIDs and response below are examples.
{
"dossierId": "11111111-1111-4111-8111-111111111111",
"confirm": false
}{
"ok": false,
"code": "confirmation_required",
"error": "This re-read costs 150 MoatTokens. Confirm to continue.",
"cost": 150,
"dossierId": "11111111-1111-4111-8111-111111111111",
"evidenceId": "22222222-2222-4222-8222-222222222222"
}Confirm an accepted cost
Only after the owner approves the returned quote, send confirm:true with maxTokens set to the accepted integer cost. Include the returned evidenceId to detect newer evidence before running. A cost above that cap is rejected before a new charge or reading. Wallet balance, key permissions and monthly key budget must also permit the run. The example cap below matches the illustrative quote above; it is not a standing authorization to spend. Identical evidence under the same method version reuses the stored reading for zero tokens. A new index can rise, fall or stay the same.
{
"dossierId": "11111111-1111-4111-8111-111111111111",
"evidenceId": "22222222-2222-4222-8222-222222222222",
"confirm": true,
"maxTokens": 150
}Errors and interrupted requests
Errors use ok:false, code and error, with extra context where available. Common cases are 401 unauthorized, 403 insufficient_scope, 404 not_found, 409 evidence_changed or reading_in_progress, and 429 rate_limited. A cost above maxTokens returns 402 cost_limit_exceeded. If a response is lost, inspect the stored result before trying again. A failed reading can report refunded:true or refunded:false; do not assume a refund unless it is confirmed. Contact support with sanitized error details and never include a key or private evidence.
{
"ok": false,
"code": "unauthorized",
"error": "A valid API key is required."
}