Docs
Intel: claims, entities, sources
The Curated band: claims with their provenance and citation, entities and relations, sources, the change feed and the vocabularies. Absent is not empty.
Generated from openapi.yaml (Btcintel native API 0.1.0). Every hash is canonical display order; every answer carries the index and node heights; errors use one envelope — see Semantics.
- GET
/v1/address/{address}/annotations— Claims on an address - GET
/v1/entities— Entities (cursor or offset page) - GET
/v1/entities/{id}— Entity with identifiers, aliases, relations, events and subjects - GET
/v1/sources— Sources with licence, attribution and last fetch - GET
/v1/annotations— Search current claims (cursor page, newest first) - POST
/v1/annotations/lookup— Bulk lookup of claims by subject - GET
/v1/claims/{claim_id}— One claim by id, current version or a given one - GET
/v1/claims/{claim_id}.stix— One claim as a STIX 2.1 bundle - GET
/v1/claims/{claim_id}/versions— Every recorded version of a claim - GET
/v1/claims/{claim_id}/members.csv— The members of a campaign as CSV - GET
/v1/claims/{claim_id}/members— The members of a campaign, a page of claims - GET
/v1/claims/{claim_id}/disputes— The public dispute record of a claim - POST
/v1/claims/{claim_id}/disputes— Dispute a Curated claim - GET
/v1/sanctions/facts/{address}— Sanction listings of an address, with the fetch they are as of - GET
/v1/changes— Append-only feed of claim changes (cursor) - GET
/v1/taxonomy/concepts— The vocabulary (DW-VA, btcintel extensions, confidence classes, event and relation kinds) - GET
/v1/blocks/{id}/attribution— Attributions of a block (no stored winner) - GET
/v1/blocks/{id}/audit— Template diff of a block (evidence, never a verdict) - GET
/v1/tx/{txid}/classification— Structural observations of a transaction (tx-obs-v1) - GET
/v1/subjects/{subject_kind}/{subject_key}— The Curated siblings of a subject, without the chain facts - GET
/v1/community/labelers— The public labeler directory (Community) - GET
/v1/community/recent— The Community firehose — recent notes across subjects - GET
/v1/community/events/{id}— One Community event with its thread - GET
/v1/community/{subject_kind}/{subject_key}— Community notes about one subject — comments and labels, with a lens - POST
/v1/community/publish— Publish a signed Community event through the API - POST
/v1/community/delete— Delete own Community events through the API (NIP-09) - POST
/v1/annotations/propose— Propose a Curated claim (t2 agents, t3 humans; a human reviews it)
GET /v1/address/{address}/annotations
Claims on an address
Parameters
| Name | In | Type | Description |
|---|---|---|---|
address required | path | string | Mainnet address; other networks answer 400 with an explanation. |
include | query | string | Comma-separated: expired adds expired and retracted claims; provisional adds the provisional claims a human has not promoted yet (S1.11 FR-11). |
confidence_class | query | string · max length 100 | Only claims of this confidence class (e.g. authority_data; the confidence: prefix is optional). Levels are never combined (P6). |
source_kind | query | string · max length 100 | Only claims from sources of this kind (sanctions, crime-intel, osint-report, …). |
Response 200
Claims (may be empty).
schema
subjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
itemsarray of Claimrelationsarray of Relation — Relations of the entities the claims name; about entities, never the address (P17).claim_idstringkindstring required · one of "relation"aboutstring · one of "entity"versionintegercontent_sha256stringcitationstringfrom_entityobjectidstringnamestringkindstring — entity:… concept.
to_entityobjectidstringnamestringkindstring — entity:… concept.
typestring — relation:… concept.sourceobjectfetchobjectconfidenceobjectvalidityobjectevidencearray of object
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/address/bc1qz654h5qcqzalv6ltpxsk4ksdcc3e20wkedqntgnarv3a0t2e2p7scr48pl/annotations | jqGET /v1/entities
Entities (cursor or offset page)
Actors, services, families and pools the Curated band names. Never a score; counts are how many claims name each entity, and a count orders the list without ranking it (spec S2.4). The default is the id order with a keyset cursor; any other order pages by offset.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
kind | query | string | Concept id, e.g. entity:pool. |
q | query | string | Matches id, name or alias. |
nonempty | query | string · one of "1", "true", "0", "false" | Only entities a current claim, attribution, relation or event names. |
abuse | query | string · one of "any" | any: only entities a current claim names with an abuse category. |
sort | query | string · one of "id", "annotations", "attributions", "relations", "events" · default "id" | The id, or how many current claims (annotations), attributions, relations or events name the entity. |
order | query | string · one of "asc", "desc" | Ascending by default for the id, descending for a count; ties fall back to the id ascending. |
limit | query | integer · ≤ 200 · default 50 | — |
offset | query | integer · ≥ 0 · ≤ 100000 · default 0 | — |
cursor | query | string | Keyset cursor of the id order ascending; with another order or an offset it is a 400. |
Response 200
Entity summaries.
schema
itemsarray of EntitySummary requiredidstringnamestringkindstringstatusstring · one of "active", "defunct", "seized", "rebranded", "unknown"descriptionstringjurisdictionsarray of stringaliasesarray of stringidentifiersarray of objectschemestringvaluestringurlstring | nullsource_idstring
countsobjectannotationsintegerattributionsintegerrelationsintegereventsinteger
abusearray of object — What the current claims naming the entity say it is involved in, per abuse category, most claims first: how many claims and from how many sources. Side by side and unweighted, never a score (P1); empty when no current claim names an abuse category.abusestring required — abuse:… concept.claimsinteger requiredsourcesinteger required
next_cursorstring | null required — Set only in the id order ascending.totalinteger required — Every entity the filters match.
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/entities | jq '{next_cursor, total}'GET /v1/entities/{id}
Entity with identifiers, aliases, relations, events and subjects
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | — |
Response 200
The entity. Relations are about entities, never about a subject (P17).
schema
EntityDetail
Errors
404— Unknown to the index and, for transactions, to the node mempool.
Example
curl -s https://api.btcintel.io/v1/entities/storm-1567 | jqGET /v1/sources
Sources with licence, attribution and last fetch
- MCP tool
list_sources— see For agents
Response 200
Every registered source (no sign-off names).
schema
idstringnamestringkindstringurlstring | nulllicensestring | nulllicense_urlstring | nullattributionstring | null — Text rendered with every claim of the source (P38).redistributablebooleanpersonal_databooleanreliability_priorintegerdefault_confidencestringcadencestring | nullactivebooleancommunity_proposalsboolean — Spec S5.1 FR-10: proposals from t2/t3 may name this source.last_fetchobjectidintegerfetched_atstring (date-time)sha256stringrecord_countinteger | nullsize_bytesinteger
Example
curl -s https://api.btcintel.io/v1/sources | jqGET /v1/annotations
Search current claims (cursor page, newest first)
- MCP tool
search_annotations— see For agents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
q | query | string | Matches subject key or label. |
category | query | string | Concept id (entity:… or abuse:…); legacy words sanctions, ransomware, exchange, privacy are mapped. |
source | query | string | — |
entity | query | string | — |
subject_kind | query | string · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey" | — |
limit | query | integer · ≤ 200 · default 50 | — |
cursor | query | string | — |
include | query | string · one of "provisional" | provisional adds the provisional claims a human has not promoted yet (S1.11 FR-11). |
confidence_class | query | string · max length 100 | Only claims of this confidence class (e.g. authority_data; the confidence: prefix is optional). Levels are never combined (P6). |
source_kind | query | string · max length 100 | Only claims from sources of this kind (sanctions, crime-intel, osint-report, …). |
Response 200
Claims.
schema
itemsarray of Claimnext_cursorstring | null
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/annotations | jqPOST /v1/annotations/lookup
Bulk lookup of claims by subject
Up to 20 subjects per call at tier T0 (CC-8); keys are canonicalised and duplicates collapsed. A subject with nothing found is listed in not_found.
- MCP tool
lookup_subjects— see For agents
Request body
schema
subjectsarray of object requiredkindstring requiredkeystring required
includearray of string — What to return: annotations (the default), attributions, andprovisionalto add the provisional claims a human has not promoted yet (S1.11 FR-11).confidence_classstring — Only claims of this confidence class (e.g. authority_data; the confidence: prefix is optional). Levels are never combined. · max length 100source_kindstring — Only claims from sources of this kind (sanctions, crime-intel, osint-report, …). · max length 100
Response 200
Results per subject.
schema
resultsarray of objectsubjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
annotationsarray of Claimattributionsarray of Attributionclaim_idstringkindstring required · one of "attribution"versionintegercontent_sha256stringcitationstringsubjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
entityobjectidstringnamestring
methodstring · one of "coinbase_tag", "coinbase_address", "coinbase_script", "prev_template", "manual"signature_idintegermatcher_versionstringsourceobjectidstringnamestring
fetchobjectconfidenceobjectclassstringlevelinteger
validityobjectevidenceobjectcreated_atstring (date-time)
disputedboolean
not_foundarray of objectkindstringkeystringreasonstring
Errors
400— Malformed input (invalid_input).413— Over the subject limit (too_large).
Example
curl -s -X POST https://api.btcintel.io/v1/annotations/lookup \
-H 'Content-Type: application/json' \
-d '{"subjects":[{"kind":"address","key":"bc1qz654h5qcqzalv6ltpxsk4ksdcc3e20wkedqntgnarv3a0t2e2p7scr48pl"}],"include":["annotations"]}' | jqGET /v1/claims/{claim_id}
One claim by id, current version or a given one
ann_<n>, att_<n>, rel_<n> or evt_<n>. The version in force carries the full content; a superseded version is addressable by its hash and citation, its content is not retained. An annotation carries its status (S1.11): a provisional one is served with it and Cache-Control: no-store; a held or rejected one is a 404 except to an operator.
- MCP tool
get_claim— see For agents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | — |
version | query | integer · ≥ 1 | — |
Response 200
The claim object (CC-4) with citation and content hash; ETag = content hash.
Headers: ETag
schema
- Claim — An annotation (CC-4): what a named source says about a subject, with citation. Never a score. Its
fetchis the fetch that first stated the claim's current content, the onecontent_sha256covers (CC-5, P74); a later fetch that restates it moveslast_seen, never the version. - Attribution — Who built a block's template according to one method and one source; several per block, no stored winner (P7).
claim_idstringkindstring required · one of "attribution"versionintegercontent_sha256stringcitationstringsubjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
entityobjectidstringnamestring
methodstring · one of "coinbase_tag", "coinbase_address", "coinbase_script", "prev_template", "manual"signature_idintegermatcher_versionstringsourceobjectidstringnamestring
fetchobjectconfidenceobjectclassstringlevelinteger
validityobjectevidenceobjectcreated_atstring (date-time)
- Relation — A relation between two entities as one source states it; about entities, never about an address (P17).
claim_idstringkindstring required · one of "relation"aboutstring · one of "entity"versionintegercontent_sha256stringcitationstringfrom_entityobjectidstringnamestringkindstring — entity:… concept.
to_entityobjectidstringnamestringkindstring — entity:… concept.
typestring — relation:… concept.sourceobjectfetchobjectconfidenceobjectvalidityobjectevidencearray of object
- Event — A dated claim that cites other claims.
claim_idstringkindstring required · one of "event"versionintegercontent_sha256stringcitationstringevent_kindstringoccurred_atstring (date)occurred_precisionstring · one of "day", "month", "year"titlestringsummarystringsourceobjectfetchobjectcitesarray of objectrefsarray of objectsubjectsarray of object — The first 100 subjects the event links (the matcher's links), in kind and key order.subjects_totalinteger — How many subjects the event links in all.entitiesarray of objectmembersCampaignMemberCounts — The event's members (S1.11 FR-3):countis the current ones,by_rolehow many hold each role in each state, delisted and retracted members left out. Counts, never the list: the members page through /v1/claims/{claim_id}/members. An event with no members answers count 0 and an empty by_role.countinteger requiredby_roleobject required
retracted_atstring | null (date-time)created_atstring (date-time)
- SupersededVersion — A version that is no longer in force; addressable by hash, content not retained.
claim_idstringkindstring required · one of "superseded"claim_kindstring · one of "annotation", "attribution", "relation", "event"versionintegercontent_sha256stringcitationstringactorstringcreated_atstring (date-time)superseded_byintegercontent_retainedboolean · one of false
Errors
400— Malformed input (invalid_input).404— Unknown to the index and, for transactions, to the node mempool.
Example
curl -s https://api.btcintel.io/v1/claims/ann_33932 | jqGET /v1/claims/{claim_id}.stix
One claim as a STIX 2.1 bundle
Spec S6.1 FR-1 (ADR-0004 §Export). The claim's objects with their observable, entity and source; deterministic ids; x_btcintel_bundle_sha256 over the canonical objects. Attributions are not exported (404); neither is an annotation that is not current (404: provisional, held or rejected, S1.11); a claim from a non-redistributable source answers 403 (P38).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | — |
Response 200
The bundle.
schema
typestring required · one of "bundle"idstring requiredobjectsarray of object requiredtypestring requiredidstring required- any other property allowed
x_btcintel_bundle_sha256string required — SHA-256 of the RFC 8785 serialisation ofobjects.x_btcintel_omitted_sourcesarray of stringx_btcintel_next_cursorstring
Errors
400— Malformed input (invalid_input).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).404— Unknown to the index and, for transactions, to the node mempool.
Example
curl -s https://api.btcintel.io/v1/claims/ann_33932.stix | jq '{type, id, x_btcintel_bundle_sha256}'GET /v1/claims/{claim_id}/versions
Every recorded version of a claim
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | — |
Response 200
Versions, oldest first.
schema
claim_idstringitemsarray of ClaimVersionversionintegercontent_sha256stringactorstringcreated_atstring (date-time)citationstring
Errors
400— Malformed input (invalid_input).404— Unknown to the index and, for transactions, to the node mempool.
Example
curl -s https://api.btcintel.io/v1/claims/ann_33932/versions | jqGET /v1/claims/{claim_id}/members.csv
The members of a campaign as CSV
Spec S1.11 FR-4 (P73). The members read as a CSV file, with the members route's filters and access (held and rejected for operators only), one row per member with its role and its status, in id order. An empty cell is an absent field. A cell that a spreadsheet would read as a formula starts with an apostrophe. At most 10,000 rows a file: X-Next-Cursor continues it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | An event id, evt_<n>. |
role | query | string · one of "victim", "sweep", "vault", "cash_out" | — |
status | query | string · one of "current", "provisional", "held", "rejected" | One state; not with include=provisional. |
include | query | string · one of "provisional" | provisional adds the provisional members to the current ones. |
confidence_class | query | string · max length 100 | Only claims of this confidence class (e.g. authority_data; the confidence: prefix is optional). Levels are never combined (P6). |
source_kind | query | string · max length 100 | Only claims from sources of this kind (sanctions, crime-intel, osint-report, …). |
limit | query | integer · ≥ 1 · ≤ 10000 · default 10000 | — |
cursor | query | string | — |
Response 200
The CSV file, a header row first: claim_id, citation, campaign, role, status, status_reason, subject_kind, subject, label, abuse, category, entity_id, confidence_class, source_id, source_kind, valid_from, first_reported_at, chain_check, chain_checked_at.
Headers: X-Next-Cursor
schema
string
Errors
400— Malformed input (invalid_input).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).404— Unknown to the index and, for transactions, to the node mempool.
Example
curl -s https://api.btcintel.io/v1/claims/ann_33932/members.csv | jqGET /v1/claims/{claim_id}/members
The members of a campaign, a page of claims
Spec S1.11 FR-3 and FR-11 (P73). The members of an event (evt_<n>): annotations that name it, each a full claim with campaign, in id order, at most 500 a page. Current members by default; include=provisional adds the provisional ones a human has not promoted yet; status picks one state instead, held and rejected for operators only (403 otherwise). Delisted and retracted members are left out. campaign.members carries the counts by role and state.
- MCP tool
list_campaign_members— see For agents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | An event id, evt_<n>. |
role | query | string · one of "victim", "sweep", "vault", "cash_out" | — |
status | query | string · one of "current", "provisional", "held", "rejected" | One state; not with include=provisional. |
include | query | string · one of "provisional" | provisional adds the provisional members to the current ones. |
confidence_class | query | string · max length 100 | Only claims of this confidence class (e.g. authority_data; the confidence: prefix is optional). Levels are never combined (P6). |
source_kind | query | string · max length 100 | Only claims from sources of this kind (sanctions, crime-intel, osint-report, …). |
limit | query | integer · ≥ 1 · ≤ 500 · default 100 | — |
cursor | query | string | — |
Response 200
A page of members (may be empty).
schema
campaignobject requiredidstringtitlestringevent_kindstringmembersCampaignMemberCounts — The event's members (S1.11 FR-3):countis the current ones,by_rolehow many hold each role in each state, delisted and retracted members left out. Counts, never the list: the members page through /v1/claims/{claim_id}/members. An event with no members answers count 0 and an empty by_role.countinteger requiredby_roleobject required
itemsarray of Claim requirednext_cursorstring | null required
Errors
400— Malformed input (invalid_input).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).404— Unknown to the index and, for transactions, to the node mempool.
Example
curl -s https://api.btcintel.io/v1/claims/ann_33932/members | jqGET /v1/claims/{claim_id}/disputes
The public dispute record of a claim
Spec S5.3 FR-3 (P8). Every dispute on the claim, newest first: reason, status, outcome, the resolver's note, the version disputed — never the opener's identity; the opener's text, evidence and the Community note they cited (event_id, which names its author) only when they chose public. counts is what the claim object carries as disputes.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | ann_<n>, att_<n>, rel_<n> or evt_<n>. |
Response 200
The record.
schema
claim_idstring requiredcountsDisputeCounts requiredopeninteger requiredresolvedinteger required
itemsarray of PublicDispute requiredidinteger requiredopened_atstring (date-time) requiredreasonstring required · one of "wrong_subject", "wrong_entity", "outdated", "source_misread", "other"statusstring required · one of "open", "resolved", "withdrawn"claim_versionintegeroutcomestring | null · one of "upheld", "rejected", "partially_upheld", nullresolved_atstring | null (date-time)notestring | null — The resolver's public note.textstring — Only when the opener chose public.evidencearray of objectevent_idstring
Errors
400— Malformed input (invalid_input).404— Unknown to the index and, for transactions, to the node mempool.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s https://api.btcintel.io/v1/claims/ann_33932/disputes | jqPOST /v1/claims/{claim_id}/disputes
Dispute a Curated claim
Spec S5.3 FR-1 (P8, P43). Any caller above t0 — a minted btci_anon_ token, a btci_ key, or a signed-in npub — opens a dispute with a reason, a text (≤ 4,096) and up to ten evidence entries; event_id may cite the Community note that carries the dispute (P8: the note is the citable form; this call is how it reaches the Curated side); public: true shows the text and evidence in the public record (the identity never appears). One open dispute per caller and claim (409); quota disputes_per_day per caller (t1 2, t2/t3 10, t4 20). A human operator resolves it; the outcome is published next to the claim. The brand signs nothing.
- MCP tool
dispute_claim— see For agents- Auth
- An operator credential as the bearer; every call is audited.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
claim_id required | path | string | ann_<n>, att_<n>, rel_<n> or evt_<n>. |
Request body
schema
reasonstring required · one of "wrong_subject", "wrong_entity", "outdated", "source_misread", "other"textstring required · max length 4096evidencearray of objectkindstring required · one of "url", "nostr_event", "txid", "text"valuestring required · max length 2048notestring · max length 2048
publicboolean — Show the text and evidence in the public record (the identity never appears).event_idstring — The Community note (64 hex ornote1…) that carries the dispute; it must be held by this relay.
Response 201
Opened.
schema
idinteger requiredclaim_idstring requiredclaim_versionintegerstatusstring required · one of "open"reasonstring requiredopened_atstring (date-time) requiredpublicbooleannotestring
Errors
400— Malformed input (invalid_input).401— Missing or invalid bearer (unauthorized).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).404— Unknown to the index and, for transactions, to the node mempool.409— The state refuses the change (conflict): an open dispute by this caller exists already, or the dispute or claim is not open any more.422— The NIP-98 event was refused (nip98_invalid): wrong URL or method, stale, bad signature, wrong payload hash, or used before; the message names the reason.429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s -X POST https://api.btcintel.io/v1/claims/ann_33932/disputes \
-H 'Authorization: Bearer $BTCI_KEY' \
-H 'Content-Type: application/json' \
-d '{"reason":"wrong_subject","text":"…"}' | jqAn operator credential: the ops bearer or a btci_ key with the ops:agent scope.
GET /v1/sanctions/facts/{address}
Sanction listings of an address, with the fetch they are as of
Every abuse:sanction claim ever recorded for the address, current or expired (validity tells which). A valid, unlisted address is a computed answer: 200 with empty listings.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
address required | path | string | Mainnet address; other networks answer 400 with an explanation. |
Response 200
Listings and the latest fetch per sanctions source.
schema
subjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
listingsarray of Claimas_ofobjectfetchobject
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/sanctions/facts/bc1qz654h5qcqzalv6ltpxsk4ksdcc3e20wkedqntgnarv3a0t2e2p7scr48pl | jqGET /v1/changes
Append-only feed of claim changes (cursor)
Rows in seq order; store next_cursor and pass it as since to never miss a row. Without since, the last 100.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
since | query | integer · ≥ 0 | — |
limit | query | integer · ≤ 1000 · default 100 | — |
subject | query | string | kind:key, e.g. address:bc1q… |
Response 200
Changes.
schema
itemsarray of Changeseqintegeratstring (date-time)claim_idstringkindstring · one of "annotation", "attribution", "relation", "event"actionstring · one of "created", "updated", "expired", "retracted"subjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
next_cursorinteger
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/changes | jqGET /v1/taxonomy/concepts
The vocabulary (DW-VA, btcintel extensions, confidence classes, event and relation kinds)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
scheme | query | string · one of "dwva-entity", "dwva-abuse", "btcintel", "confidence", "event-kind", "relation-type" | — |
Response 200
Concepts.
schema
itemsarray of Conceptidstring — Qualified id, e.g. abuse:sanction.schemestringconceptstringlabelstringdescriptionstring | nulluristring | nullparentstring | nulllevelintegerstix_mapobjectoriginstring
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/taxonomy/concepts | jqGET /v1/blocks/{id}/attribution
Attributions of a block (no stored winner)
Every attribution the matcher recorded for the block (S1.7), in the order of read policy policy_version (method rank prev_template < coinbase_address < coinbase_tag < coinbase_script < manual, then confidence level, then source prior); disputed when the two best name different entities; pool is the first row, an answer and never a verdict (P7); observation is the coinbase extraction once it ran. Absent keys mean not computed yet (CC-6): observation and pool are absent before the extractor and matcher ran, the list is empty when they ran and no catalog matched.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Height (decimal) or canonical block hash (64 hex). |
Response 200
Attributions in policy order.
schema
attributionsarray of Attribution requiredclaim_idstringkindstring required · one of "attribution"versionintegercontent_sha256stringcitationstringsubjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
entityobjectidstringnamestring
methodstring · one of "coinbase_tag", "coinbase_address", "coinbase_script", "prev_template", "manual"signature_idintegermatcher_versionstringsourceobjectidstringnamestring
fetchobjectconfidenceobjectclassstringlevelinteger
validityobjectevidenceobjectcreated_atstring (date-time)
disputedboolean requiredpoolPool — The first attribution of the read policy; present only when the block has one. An answer with its method, never a stored winner (P7).entityobject requiredidstringnamestring
methodstring required · one of "prev_template", "coinbase_address", "coinbase_tag", "coinbase_script", "manual"disputedboolean required
observationObservation — derived.coinbase_observations — a pure function of the block by extractorcoinbase-v1, no author (ADR-0004 Chain band).block_hashstring — Canonical display byte order.heightinteger — The height the block claims; orphans keep their row.coinbase_txidstring — Canonical display byte order.tag_textstring — Printable ASCII runs of the coinbase scriptSig (after the BIP34 height push) joined by one space; empty is a fact.tag_runsarray of stringscript_sig_hexstringoutput_scriptsarray of objectnintegerscript_hashstring — sha256 of the scriptPubKey, hex.addressstring | null — Rendered address; null for OP_RETURN, P2PK and non-standard scripts.value_satinteger
reward_satintegerfees_satinteger — reward minus the subsidy at the claimed height; clamped at zero.extractorstring · one of "coinbase-v1"extracted_atstring (date-time)
policy_versionstring required · one of "v1"
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/blocks/968212/attribution | jq '{disputed, policy_version}'GET /v1/blocks/{id}/audit
Template diff of a block (evidence, never a verdict)
What the mempool engine's template held against what the block included, written once at block connect (spec S1.9): the txids the template had and the block omitted (missing, with fee rate and age), the ones the block added from our mempool (added, fresh when they arrived within 30 s), the ones our mempool never saw (never_seen), the full-RBF replacements (fullrbf), the match rate, the expected fees and weight, and the missing txids that spend a sanctioned address against the OFAC snapshot in force (sanctioned_missing, sanctions_fetch_id). There is no censored field: interpretation is a Curated claim from a named source (ADR-0004). audit is absent for blocks connected while the engine was down; no backfill (CC-6).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | Height (decimal) or canonical block hash (64 hex). |
Response 200
The audit, or the subject alone when the engine wrote none.
schema
subjectSubject requiredkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
auditAudit — derived.block_template_diffs (spec S1.9) — one bounded row per block written by the mempool engine at block connect; evidence without a verdict.block_hashstring required — Canonical display byte order.heightinteger requiredtemplate_atstring (date-time) required — The last projection recompute before the block.template_ntxinteger requiredtemplate_weightintegertemplate_fees_satintegertemplate_min_ratenumber — Lowest package fee rate the template included, sat/vB.block_min_ratenumber — Lowest base fee rate among the block's transactions our mempool knew, sat/vB.missingarray of object requiredtxidstring — Canonical display byte order.fee_ratenumberage_sinteger
addedarray of object requiredtxidstring — Canonical display byte order.fee_ratenumber
never_seenarray of string requiredfresharray of string requiredsigoparray of string required — Empty until the projection tracks sigop limits.fullrbfarray of string requiredmatch_ratenumber required — |template ∩ block| / |template| in %.expected_fees_satintegerexpected_weightintegersanctioned_missingarray of object requiredtxidstring — Canonical display byte order.addressstringclaim_idstring
sanctions_fetch_idinteger | null — The latest OFAC fetch when the row was written.extractorstring required · one of "template-diff-v1"extracted_atstring (date-time)
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/blocks/968212/audit | jqGET /v1/tx/{txid}/classification
Structural observations of a transaction (tx-obs-v1)
The observations of extractor tx-obs-v1 (spec S1.8): OP_RETURN protocol markers, meta-protocol envelopes, CoinJoin amount patterns, script features and the Patoshi pattern on early coinbases. Computed on demand from the raw transaction and cached; observations and extracted_at are absent when the extractor is off or the raw transaction is unavailable (CC-6), and observations is an empty list when it ran and no rule matched. Structural facts only; no rule names a wallet or an owner (P18).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
txid required | path | string | Canonical txid (64 hex, display byte order). |
Response 200
Observations, or the subject alone when not computed.
schema
subjectSubject requiredkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
observationsarray of TxObservationkindstring required · one of "op_return", "meta_protocol", "coinjoin", "feature", "pattern"valuestring required — The rule that matched: omni, opentimestamps, runes, counterparty, …, inscription, src20_stamp, atomicals, whirlpool, wasabi-1, wabisabi, joinmarket, locktime_recent, bip69, rbf_signal, patoshi.detailobject required — Rule evidence: prefix_hex / text / heuristic for OP_RETURN, content_type for inscriptions, inputs / outputs / equal_outputs / denomination for CoinJoin patterns, nonce_lsb / extranonce for Patoshi.extractorstring required · one of "tx-obs"extractor_versionstring required · one of "v1"
extracted_atstring (date-time)extractorstring · one of "tx-obs-v1"
Errors
400— Malformed input (invalid_input).
Example
curl -s https://api.btcintel.io/v1/tx/71e4dae29ed1bc9fe008bba7f3542fd5961b780c220ca8778100a7cb8bd4c81b/classification | jq '{extracted_at, extractor}'GET /v1/subjects/{subject_kind}/{subject_key}
The Curated siblings of a subject, without the chain facts
The intel siblings the subject page carries (spec S1.6), without the chain facts: for an address annotations and relations; for a transaction also exposure and classification; for a block also attributions, disputed, pool, observation and audit. Absent keys mean not computed; empty lists mean computed, nothing found (CC-6). The same answers as the page route, so a claim seen here is the claim seen there.
- MCP tool
get_annotations— see For agents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
subject_kind required | path | string · one of "address", "tx", "block" | address, tx or block. |
subject_key required | path | string | The address, the canonical txid, or the block height or canonical hash. |
include | query | string · one of "expired" | expired to include expired and retracted claims in annotations (attributions and hop-0 stay current-only). |
Response 200
The subject and its siblings.
schema
subjectSubject requiredkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
annotationsarray of Claimrelationsarray of Relationclaim_idstringkindstring required · one of "relation"aboutstring · one of "entity"versionintegercontent_sha256stringcitationstringfrom_entityobjectidstringnamestringkindstring — entity:… concept.
to_entityobjectidstringnamestringkindstring — entity:… concept.
typestring — relation:… concept.sourceobjectfetchobjectconfidenceobjectvalidityobjectevidencearray of object
exposureExposure — Read-time exposure from current annotations on the addresses the transaction touches; never walks further than the transaction itself.hop0array of Hop0 requireddirectionstring required —in: the claim is on an address the transaction spends from;out: on an address it pays to. · one of "in", "out"amount_satinteger required — Sats the address moved in that direction across every input or output of the transaction.claim_idstring requiredcitationstring — CC-5 citation of the claim's current version.labelstringsubjectSubject requiredkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
truncatedboolean — Present and true when the transaction touches more than 1000 distinct addresses and only the first 1000 were looked up.
classificationClassification — The tx-obs-v1 result (spec S1.8 FR-7); the same object asGET /v1/tx/{txid}/classification.observationsarray of TxObservation requiredkindstring required · one of "op_return", "meta_protocol", "coinjoin", "feature", "pattern"valuestring required — The rule that matched: omni, opentimestamps, runes, counterparty, …, inscription, src20_stamp, atomicals, whirlpool, wasabi-1, wabisabi, joinmarket, locktime_recent, bip69, rbf_signal, patoshi.detailobject required — Rule evidence: prefix_hex / text / heuristic for OP_RETURN, content_type for inscriptions, inputs / outputs / equal_outputs / denomination for CoinJoin patterns, nonce_lsb / extranonce for Patoshi.extractorstring required · one of "tx-obs"extractor_versionstring required · one of "v1"
extracted_atstring (date-time) requiredextractorstring · one of "tx-obs-v1"
attributionsarray of Attributionclaim_idstringkindstring required · one of "attribution"versionintegercontent_sha256stringcitationstringsubjectSubjectkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
entityobjectidstringnamestring
methodstring · one of "coinbase_tag", "coinbase_address", "coinbase_script", "prev_template", "manual"signature_idintegermatcher_versionstringsourceobjectidstringnamestring
fetchobjectconfidenceobjectclassstringlevelinteger
validityobjectevidenceobjectcreated_atstring (date-time)
disputedbooleanpoolPool — The first attribution of the read policy; present only when the block has one. An answer with its method, never a stored winner (P7).entityobject requiredidstringnamestring
methodstring required · one of "prev_template", "coinbase_address", "coinbase_tag", "coinbase_script", "manual"disputedboolean required
observationObservation — derived.coinbase_observations — a pure function of the block by extractorcoinbase-v1, no author (ADR-0004 Chain band).block_hashstring — Canonical display byte order.heightinteger — The height the block claims; orphans keep their row.coinbase_txidstring — Canonical display byte order.tag_textstring — Printable ASCII runs of the coinbase scriptSig (after the BIP34 height push) joined by one space; empty is a fact.tag_runsarray of stringscript_sig_hexstringoutput_scriptsarray of objectnintegerscript_hashstring — sha256 of the scriptPubKey, hex.addressstring | null — Rendered address; null for OP_RETURN, P2PK and non-standard scripts.value_satinteger
reward_satintegerfees_satinteger — reward minus the subsidy at the claimed height; clamped at zero.extractorstring · one of "coinbase-v1"extracted_atstring (date-time)
auditAudit — derived.block_template_diffs (spec S1.9) — one bounded row per block written by the mempool engine at block connect; evidence without a verdict.block_hashstring required — Canonical display byte order.heightinteger requiredtemplate_atstring (date-time) required — The last projection recompute before the block.template_ntxinteger requiredtemplate_weightintegertemplate_fees_satintegertemplate_min_ratenumber — Lowest package fee rate the template included, sat/vB.block_min_ratenumber — Lowest base fee rate among the block's transactions our mempool knew, sat/vB.missingarray of object requiredtxidstring — Canonical display byte order.fee_ratenumberage_sinteger
addedarray of object requiredtxidstring — Canonical display byte order.fee_ratenumber
never_seenarray of string requiredfresharray of string requiredsigoparray of string required — Empty until the projection tracks sigop limits.fullrbfarray of string requiredmatch_ratenumber required — |template ∩ block| / |template| in %.expected_fees_satintegerexpected_weightintegersanctioned_missingarray of object requiredtxidstring — Canonical display byte order.addressstringclaim_idstring
sanctions_fetch_idinteger | null — The latest OFAC fetch when the row was written.extractorstring required · one of "template-diff-v1"extracted_atstring (date-time)
communityobject — Spec S4.2 FR-1: the collapsed Community form (counts and up to three comments); absent until the ingester has ever run (CC-6). Indexed from Nostr, not endorsed.countsCommunityCounts requiredcommentsinteger required — Served comments.labelsinteger required — Served labels under the current lens.hiddeninteger required — Events held but kept from view (deleted by the author, hidden by moderation, or by a banned pubkey).
samplearray of CommunityEvent requiredidstring requiredpubkeystring requirednpubstring | nullkindinteger requiredcreated_atstring (date-time) requiredcontentstring required — Plain text as signed; never HTML or markdown.tagsarray of array of string required — The i/I/e/p/l/L/k/K/nonce tags.pow_bitsinteger required — Committed NIP-13 difficulty.low_powboolean requiredseen_onarray of string required — Public relays the event was seen on.relay_urlstring required — Where it came from first (our relay's URL for events accepted at our door).replies_countinteger requiredzap_countinteger required — Distinct zappers (community signal, not endorsement).zap_satsinteger — Present when zap_count > 0.
noticestring required
Errors
400— Malformed input (bad hex, wrong-network address, bad vout).404— Unknown to the index and, for transactions, to the node mempool.409— Confirmed on-chain but not indexed yet (not_indexed_yet).
Example
curl -s https://api.btcintel.io/v1/subjects/tx/71e4dae29ed1bc9fe008bba7f3542fd5961b780c220ca8778100a7cb8bd4c81b | jqGET /v1/community/labelers
The public labeler directory (Community)
Spec S4.2 FR-4 (P28): the listed labelers a reader may choose as a lens — pubkey, name, criteria, how many labels of theirs are served and since when. No labeler is a default; an empty list is a real empty (the directory is kept by ops). Community content is indexed from Nostr and not endorsed (the _meta.notice).
- MCP tool
list_labelers— see For agents
Response 200
The listed labelers.
schema
itemsarray of CommunityLabeler requiredpubkeystring requirednpubstring | nullnamestring requirednamespacestring requireddescriptionstring | nullurlstring | nullcriteria_urlstring | nulllistedboolean requiredsincestring (date-time) requiredlabels_countinteger — Served labels by this labeler.
_metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Errors
429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s https://api.btcintel.io/v1/community/labelers | jqGET /v1/community/recent
The Community firehose — recent notes across subjects
Spec S4.2 FR-4: served comments that carry a subject and labels from listed labelers, newest first, low-PoW excluded. 501 not_configured until the ingester has run once (CC-6). Indexed from Nostr, not endorsed.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
kinds | query | string | Comma-separated: 1111 (comments) and/or 1985 (labels); both by default. |
cursor | query | string | The next_cursor of the previous page. |
limit | query | integer · ≤ 200 · default 50 | — |
Response 200
A page of notes.
schema
itemsarray of CommunityEvent requiredidstring requiredpubkeystring requirednpubstring | nullkindinteger requiredcreated_atstring (date-time) requiredcontentstring required — Plain text as signed; never HTML or markdown.tagsarray of array of string required — The i/I/e/p/l/L/k/K/nonce tags.pow_bitsinteger required — Committed NIP-13 difficulty.low_powboolean requiredseen_onarray of string required — Public relays the event was seen on.relay_urlstring required — Where it came from first (our relay's URL for events accepted at our door).replies_countinteger requiredzap_countinteger required — Distinct zappers (community signal, not endorsement).zap_satsinteger — Present when zap_count > 0.
next_cursorstring | null required_metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Errors
400— Malformed input (invalid_input).429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s https://api.btcintel.io/v1/community/recent | jqGET /v1/community/events/{id}
One Community event with its thread
Spec S4.2 FR-4: a served comment or label by id (64 hex or note1…) with its replies two levels deep. 404 when unknown, deleted by its author, hidden by moderation or (without include_low_pow) under the proof-of-work floor. Indexed from Nostr, not endorsed.
- MCP tool
get_community_event— see For agents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id required | path | string | 64 hex characters or a note1… id. |
include_low_pow | query | boolean · default false | Also serve events under the proof-of-work floor (counts as two requests). |
Response 200
The event and its thread.
schema
CommunityThread
Errors
400— Malformed input (invalid_input).404— Unknown to the index and, for transactions, to the node mempool.429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s https://api.btcintel.io/v1/community/events/1 | jqGET /v1/community/{subject_kind}/{subject_key}
Community notes about one subject — comments and labels, with a lens
Spec S4.2 FR-1…FR-3: what people say on Nostr about an address, transaction or block — NIP-22 comments and NIP-32 labels indexed from our relay and the public relays, not endorsed by btcintel (the _meta.notice says so on every answer, P22). labelers= chooses whose labels to show (pubkeys, hex or npub); without it, labels come from listed labelers only; labelers=* shows every pubkey's labels with a warning and counts as two requests. order=recent (default) | discussed (replies) | zapped — by zaps, a community signal and not an endorsement (P26): never the default, self-zaps excluded, each zapper counted once with their largest zap, only receipts whose invoice commits to the zap request. include_low_pow=true also serves events under the proof-of-work floor and counts as two requests. Anonymous callers (t0) receive the collapsed form (counts and a sample of three comments, CC-8). A subject nobody has commented on answers counts: 0 and empty lists; before the ingester has ever run the route answers 501 not_configured (CC-6: absent, not empty).
- MCP tool
get_community— see For agents
Parameters
| Name | In | Type | Description |
|---|---|---|---|
subject_kind required | path | string · one of "address", "tx", "block" | — |
subject_key required | path | string | The canonical key (address as rendered; txid or block hash in display order). |
labelers | query | string | Comma-separated pubkeys (hex or npub1…), or * for all. |
order | query | string · one of "recent", "discussed", "zapped" · default "recent" | — |
include_low_pow | query | boolean · default false | — |
cursor | query | string | The next_cursor of the previous page. |
limit | query | integer · ≤ 200 · default 50 | — |
Response 200
The page (full form), or the collapsed form for anonymous callers.
schema
- CommunityPage
subjectCommunitySubject requiredkindstring required · one of "address", "tx", "block"keystring requirednip73string — The NIP-73 id, e.g. bitcoin:address:<address>.
commentsarray of CommunityEvent requiredidstring requiredpubkeystring requirednpubstring | nullkindinteger requiredcreated_atstring (date-time) requiredcontentstring required — Plain text as signed; never HTML or markdown.tagsarray of array of string required — The i/I/e/p/l/L/k/K/nonce tags.pow_bitsinteger required — Committed NIP-13 difficulty.low_powboolean requiredseen_onarray of string required — Public relays the event was seen on.relay_urlstring required — Where it came from first (our relay's URL for events accepted at our door).replies_countinteger requiredzap_countinteger required — Distinct zappers (community signal, not endorsement).zap_satsinteger — Present when zap_count > 0.
labelsarray of CommunityLabel requiredidstring requiredpubkeystring requirednpubstring | nulllabelerobject — Present when the pubkey is in the directory.namestringlistedboolean
namespacestring requiredvaluestring requiredtargetobject requiredsubjectCommunitySubject…
created_atstring (date-time) requiredpow_bitsinteger required
countsCommunityCounts requiredcommentsinteger required — Served comments.labelsinteger required — Served labels under the current lens.hiddeninteger required — Events held but kept from view (deleted by the author, hidden by moderation, or by a banned pubkey).
next_cursorstring | null requiredlensobject requiredallboolean requiredchosenintegerwarningstringlabelersarray of CommunityLabeler requiredpubkeystring requirednpubstring | nullnamestring requirednamespacestring requireddescriptionstring | nullurlstring | nullcriteria_urlstring | nulllistedboolean requiredsincestring (date-time) requiredlabels_countinteger — Served labels by this labeler.
orderstring required · one of "recent", "discussed", "zapped"_metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
- CommunityCollapsed — The anonymous (t0) form (CC-8) and the
communitysibling of a subject page.subjectCommunitySubject requiredkindstring required · one of "address", "tx", "block"keystring requirednip73string — The NIP-73 id, e.g. bitcoin:address:<address>.
countsCommunityCounts requiredcommentsinteger required — Served comments.labelsinteger required — Served labels under the current lens.hiddeninteger required — Events held but kept from view (deleted by the author, hidden by moderation, or by a banned pubkey).
samplearray of CommunityEvent requiredidstring requiredpubkeystring requirednpubstring | nullkindinteger requiredcreated_atstring (date-time) requiredcontentstring required — Plain text as signed; never HTML or markdown.tagsarray of array of string required — The i/I/e/p/l/L/k/K/nonce tags.pow_bitsinteger required — Committed NIP-13 difficulty.low_powboolean requiredseen_onarray of string required — Public relays the event was seen on.relay_urlstring required — Where it came from first (our relay's URL for events accepted at our door).replies_countinteger requiredzap_countinteger required — Distinct zappers (community signal, not endorsement).zap_satsinteger — Present when zap_count > 0.
_metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Errors
400— Malformed input (invalid_input).429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s https://api.btcintel.io/v1/community/tx/71e4dae29ed1bc9fe008bba7f3542fd5961b780c220ca8778100a7cb8bd4c81b | jqPOST /v1/community/publish
Publish a signed Community event through the API
Spec S5.1 FR-8 (P4, P12, P23). The body carries an event signed by its author: a comment (kind 1111), a label (kind 1985) or a deletion (kind 5) about a Bitcoin subject (NIP-73), with the proof of work the relay's floor asks for (NIP-13, mined by the client; the floor is /v1/status community.relay.min_pow, 24 bits while attack_mode is on). Who may send it: a signed-in human (session cookie with the CSRF proof, or NIP-98) as their own key, or a t2/t4 btci_ key holding the community:publish scope as one of its allowed_npubs; the event's pubkey must be that key, else 422 unbound:. The event then passes exactly the relay's door (kinds, subject tags, window, size, PoW, bans; blocked:, invalid:, pow: answer 422 event_rejected with the relay's message), is stored as accepted by this relay, is fanned out to the relay's subscribers and, best effort and asynchronously, to broadcast_to. Tier caps: event_max_bytes (t2 4,096; t3/t4 16,384) and publish_per_min / publish_per_day per author (CC-8). The API signs nothing: an account's custodied key is signed for by the signer service (POST /v1/auth/npub/sign, while features.signing is on), never here. 501 not_configured while WRITES_ENABLED is off (/v1/status features.writes; on since CP3, P60). Over MCP this is publish_community_event (S5.10, P70): the caller is the session's bearer, a t2 or t4 key bound to the event's pubkey (a minted t1 token cannot publish; POST /v1/keys/agent issues a t2 key to the npub that signs that request with NIP-98); the event is signed by the agent's own key, never by btcintel.
- MCP tool
publish_community_event— see For agents- Auth
- An operator credential as the bearer; every call is audited.
Request body
schema
eventobject required — A Nostr event exactly as signed (NIP-01); the server recomputes the id and verifies the signature.idstring requiredpubkeystring requiredcreated_atinteger requiredkindinteger requiredtagsarray of array of string requiredcontentstring requiredsigstring required
Response 200
Already held (duplicate: true), or a deletion that deleted nothing held here (stored: false, still broadcast).
schema
idstring requiredpubkeystring requiredkindinteger requiredpow_bitsinteger required — Committed NIP-13 difficulty.storedboolean required — The event row exists on this relay.accepted_byarray of string required —selfwhen this relay holds it.broadcast_toarray of string required — Outbound relays the event is being sent to (best effort, asynchronous).duplicateboolean requireddeletedinteger — Deletions only: events of the author marked deleted here._metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Response 201
Accepted and stored; broadcast_to lists the relays it is being sent to.
schema
idstring requiredpubkeystring requiredkindinteger requiredpow_bitsinteger required — Committed NIP-13 difficulty.storedboolean required — The event row exists on this relay.accepted_byarray of string required —selfwhen this relay holds it.broadcast_toarray of string required — Outbound relays the event is being sent to (best effort, asynchronous).duplicateboolean requireddeletedinteger — Deletions only: events of the author marked deleted here._metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Errors
400— Malformed input (invalid_input).401— Missing or invalid bearer (unauthorized).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).422— The event was refused at the door (event_rejected): the message carries the relay's NIP-01 prefix —unbound:(not this caller's key),invalid:(shape, subject, window, size, signature),pow:(below the floor),blocked:(kind, banned, read-only).429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s -X POST https://api.btcintel.io/v1/community/publish \
-H 'Authorization: Bearer $BTCI_KEY' \
-H 'Content-Type: application/json' \
-d '{"event":{"id":"…","pubkey":"…","created_at":10,"kind":10,"tags":[],"content":"…","sig":"…"}}' | jqAn operator credential: the ops bearer or a btci_ key with the ops:agent scope.
POST /v1/community/delete
Delete own Community events through the API (NIP-09)
Spec S5.1 FR-9. The body carries a kind 5 signed by the author naming the ids to delete in e tags; the same callers and binding as /v1/community/publish. Events held here by that author are marked deleted at once (the row stays for moderation; every read hides it), deleted counts them; the deletion is stored when it deleted something held and is broadcast outbound in any case, since a note that only public relays hold is the author's to delete there. A stranger's deletion deletes nothing. 501 not_configured while WRITES_ENABLED is off (on since CP3, P60). Over MCP this is delete_community_event, with the same bearer binding (S5.10).
- MCP tool
delete_community_event— see For agents- Auth
- An operator credential as the bearer; every call is audited.
Request body
schema
eventobject required — A Nostr event exactly as signed (NIP-01); the server recomputes the id and verifies the signature.idstring requiredpubkeystring requiredcreated_atinteger requiredkindinteger requiredtagsarray of array of string requiredcontentstring requiredsigstring required
Response 200
Nothing held was deleted (deleted: 0, stored: false) or the deletion was known already; broadcast still.
schema
idstring requiredpubkeystring requiredkindinteger requiredpow_bitsinteger required — Committed NIP-13 difficulty.storedboolean required — The event row exists on this relay.accepted_byarray of string required —selfwhen this relay holds it.broadcast_toarray of string required — Outbound relays the event is being sent to (best effort, asynchronous).duplicateboolean requireddeletedinteger — Deletions only: events of the author marked deleted here._metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Response 201
The deletion was stored (it deleted something held) and broadcast.
schema
idstring requiredpubkeystring requiredkindinteger requiredpow_bitsinteger required — Committed NIP-13 difficulty.storedboolean required — The event row exists on this relay.accepted_byarray of string required —selfwhen this relay holds it.broadcast_toarray of string required — Outbound relays the event is being sent to (best effort, asynchronous).duplicateboolean requireddeletedinteger — Deletions only: events of the author marked deleted here._metaCommunityMeta requirednoticestring required — Always: Community content is indexed from Nostr and not endorsed by btcintel.endorsementboolean required — Always false.
Errors
400— Malformed input (invalid_input).401— Missing or invalid bearer (unauthorized).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).422— The event was refused at the door (event_rejected): the message carries the relay's NIP-01 prefix —unbound:(not this caller's key),invalid:(shape, subject, window, size, signature),pow:(below the floor),blocked:(kind, banned, read-only).429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s -X POST https://api.btcintel.io/v1/community/delete \
-H 'Authorization: Bearer $BTCI_KEY' \
-H 'Content-Type: application/json' \
-d '{"event":{"id":"…","pubkey":"…","created_at":10,"kind":10,"tags":[],"content":"…","sig":"…"}}' | jqAn operator credential: the ops bearer or a btci_ key with the ops:agent scope.
POST /v1/annotations/propose
Propose a Curated claim (t2 agents, t3 humans; a human reviews it)
Spec S5.1 FR-10 (P42, P5). A proposal names a research source that accepts community proposals (GET /v1/sources, community_proposals: true), a canonical subject, a label and, optionally, category or abuse words from the vocabulary (GET /v1/taxonomy/concepts), concept ids, an entity, a role, evidence entries and the Community event that led to it. It becomes a draft filed under the proposer's npub (a human's own key; a t2/t4 key's pubkey, one of its allowed_npubs, or its only one) with method: manual and the source's default confidence; a human curator approves or rejects it (S3.3), and an approved claim is published under the source, cited to a fetch of this proposal, with {"kind": "nostr_event", "value": <id>} in its evidence when a lead event was cited — the row stands on its own; the brand never seals the event (P5). Quota proposals_per_day per caller (t2 and t3 20, t4 100). 501 not_configured while WRITES_ENABLED is off (on since CP3, P60).
- MCP tool
propose_annotation— see For agents- Auth
- An operator credential as the bearer; every call is audited.
Request body
schema
source_idstring required — A research source withcommunity_proposalstrue.subjectobject requiredkindstring required · one of "address", "tx", "block"keystring required — The address, txid or block hash; canonicalised (CC-3).
labelstring required · max length 200categorystring — A DW-VA entity category word (GET /v1/taxonomy/concepts?scheme=category). · max length 100abusestring — A DW-VA abuse word (scheme=abuse). · max length 100conceptsarray of stringentity_idstring · max length 100rolestring · max length 100evidencearray of objectkindstring required · one of "url", "nostr_event", "txid", "text"valuestring required · max length 2048notestring · max length 2048
lead_event_idstring — The Community event (64 hex ornote1…) that led to the proposal; added to the evidence asnostr_event.pubkeystring — t2/t4 keys only: which of the key'sallowed_npubsproposes (64 hex ornpub1…).
Response 201
The draft; a human reviews it.
schema
draft_idinteger requiredstatusstring required · one of "draft"proposed_bystring required —npub:<hex>, orkey:<id>for a key without allowed npubs.source_idstring requiredsubjectSubject requiredkindstring · one of "address", "script", "tx", "block", "outpoint", "pool", "descriptor", "pubkey"keystring — Canonical key (CC-3).
created_atstring (date-time) requirednotestring
Errors
400— Malformed input (invalid_input).401— Missing or invalid bearer (unauthorized).403— The operator lacks the role or kind the action needs, or is switched off (forbidden).422— The NIP-98 event was refused (nip98_invalid): wrong URL or method, stale, bad signature, wrong payload hash, or used before; the message names the reason.429—quota_exceeded(spec S3.1 FR-4): the caller's tier ran out of requests for the minute or the day.Retry-Aftersays when to try again; every rate-limited answer carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-RateLimit-Tier. While the deployment runs in log-only mode the decision is logged instead andX-RateLimit-Policy: log-onlyis set.501— The mempool engine is not enabled on this deployment (BITCOIN_ZMQ_SEQUENCEunset).
Example
curl -s -X POST https://api.btcintel.io/v1/annotations/propose \
-H 'Authorization: Bearer $BTCI_KEY' \
-H 'Content-Type: application/json' \
-d '{"source_id":"…","subject":{"kind":"address","key":"bc1qz654h5qcqzalv6ltpxsk4ksdcc3e20wkedqntgnarv3a0t2e2p7scr48pl"},"label":"…"}' | jqAn operator credential: the ops bearer or a btci_ key with the ops:agent scope.