OP_DROPProtocol

API reference, contract version 1.0.0

Indexer API

The OP_DROP indexer exposes a small read-only HTTP contract over the confirmed ledger. This page documents that contract: paths, parameters, and response shapes.

No base URL is published here. The origin is supplied by whoever operates a deployment, and it is not a browser-facing endpoint. Browsers must never call an OP_DROP indexer directly; a first-party application backend holds the origin and proxies what it needs. The indexer's database is private service state and must not be read or written by other services.

Service boundary

The indexer owns confirmed-chain scanning, leaf validation, token state, balances, events, and launch metadata. It is the source of truth for OP_DROP protocol state within a deployment. It does not create transactions, hold keys, or broadcast: those belong to the application that builds an order.

Conventions

Rules that apply to every response
AmountsAlways decimal strings, never JSON numbers, so full 64-bit and 128-bit precision survives. Never parse them as floating point.
NetworkOne of mainnet, testnet, signet, regtest, fixed per deployment. A response never mixes networks.
Confirmed onlyEvery figure reflects confirmed state at the deployment's confirmation depth. Mempool activity is never included.
Pagingstart is an offset from 0 to 10000000, default 0. limit is 1 to 100, default 20.
FiltersExact match after trimming and case normalisation, not patterns. A malformed value matches nothing rather than erroring.

Endpoints

The read surface
Method and pathPurposeParameters
GET /op-drop/health Liveness. Returns {"status":"ok","protocol":"op-drop"} while the process is up. none
GET /op-drop/launch/drop The launch manifest for $DROP: the fixed anchor convention and the exact deploy payload. none
GET /op-drop/tokens Paginated list of deployments. tick, sort (deploy, holders, minted; default deploy), start, limit
GET /op-drop/tokens/{tick} One deployment plus up to its 100 most recent events. 404 when the ticker has no valid deployment. tick in the path, case-insensitive and trimmed
GET /op-drop/balances/{address} Confirmed balances for one address. Only tickers with a non-zero available or reserved balance are included. address in the path
GET /op-drop/events Paginated event ledger, including invalid events. tick, address, txid, start, limit
GET /op-drop/indexer/status Scanner cursor and configuration: network, start height, confirmation depth, poll interval, batch size, and last processed block. none

Response schemas

Launch manifest

GET /op-drop/launch/drop

{
  "protocol": "op-drop",
  "anchor": {
    "revealOutput": 0,
    "transferSettlement": "first confirmed spend credits spender transaction output 0"
  },
  "launch": {
    "display": "$DROP",
    "tick": "drop",
    "max": "21000000",
    "lim": "1000",
    "fullLimitMintCount": "21000",
    "deploymentJson": "{\"p\":\"op-drop\",\"op\":\"deploy\",\"tick\":\"drop\",\"max\":\"21000000\",\"lim\":\"1000\"}"
  }
}

Compare deploymentJson byte for byte against what you intend to sign. It is the only field on this endpoint that is worth verifying.

Deployment

Fields of a deployment object
FieldTypeMeaning
tickstringThe wire ticker.
maxdecimal stringMaximum supply.
limdecimal stringLimit per mint.
fullLimitMintsdecimal stringNumber of full-limit mints that would exhaust the supply.
finalLimitMintRemainderdecimal stringWhat a final partial mint would receive.
minteddecimal stringMinted supply so far.
remainingdecimal stringmax - minted.
progressnumberPercent minted, 0 to 100, rounded to two decimals. The only floating-point field in the contract, and it is presentational.
mintsintegerCount of valid mint events.
holdersintegerAddresses with a non-zero available or reserved balance.
deployobjecteventId, txid, height, owner of the winning deploy.

Balances

GET /op-drop/balances/{address}

{
  "address": "bc1p…",
  "balances": [
    { "tick": "drop", "available": "750", "transferable": "250", "total": "1000" }
  ]
}

transferable is the field name for what the interfaces call "reserved": units held by an unsettled transfer. total is always available + transferable, so never add them yourself on top of total.

Event

Fields of an event object
FieldTypeMeaning
eventIdstring{txid}:i{vin}:w1 or {txid}:s{vin}:{transferEventId}.
height, blockHash, txidinteger, string, stringWhere the event was found.
actionenumdeploy, mint, transfer, transfer_settle.
tickstring or nullThe ticker.
requestedAmountdecimal string or nullWhat the payload asked for. Null on a deploy.
amountdecimal string or nullWhat was actually credited. Null until the event is finalized. Differs from requestedAmount on a partial final mint.
ownerstring or nullThe anchor address, or on a settlement the destination address.
anchorstring or null{txid}:{vout}.
sourceTransferEventIdstring or nullOn a settlement, the transfer it settles.
statusenumvalid, invalid, transfer_pending, settled.
reasonenum or nullOne of the codes in section 11.

Comparing requestedAmount with amount is the cleanest way to spot a partial final mint: they differ only in that case.

Indexer status

{
  "enabled": true,
  "configured": true,
  "network": "mainnet",
  "startHeight": 0,
  "confirmations": 6,
  "pollSeconds": 15,
  "batchBlocks": 10,
  "nextHeight": 0,
  "lastProcessedHeight": 0,
  "lastBlockHash": null
}

The values shown are the shape, not any deployment's real cursor. Use lastProcessedHeight against your own node's tip to judge freshness, and confirmations to know how deep an event must be before it counts.

Errors

Errors use the framework's default HTTP exception body.

{ "statusCode": 404, "error": "Not Found", "message": "OP-DROP token drop not found" }
Status codes you will see
CodeWhen
200Success, including an empty list.
400Invalid parameters, for example start outside 0 to 10000000 or limit outside 1 to 100, or a missing address.
404No deployment for the requested ticker.

message is usually a single string and may be an array when several validation errors are aggregated. Treat it as human-readable text, not as a stable machine code. The stable machine codes are the reason values on events.

Related: the raw artifact surface

The same service also indexes every confirmed reveal as a raw artifact, whether or not it carries an OP_DROP token operation. That surface belongs to the DROPS protocol rather than to OP_DROP, and it is documented separately. Two facts are worth knowing here because they cross the boundary:

Do not read artifact presence as an OP_DROP token event. A reveal can be indexed as an artifact and still be an invalid OP_DROP event, or carry no token payload at all.

Consuming safely

  1. Keep the origin server-side. Proxy through your own backend. Do not put an indexer origin in a browser bundle.
  2. Treat amounts as strings. Every balance, supply, and amount field is a decimal string precisely so it does not lose precision. Parsing to a JavaScript number silently corrupts values above 253.
  3. Check freshness before you trust totals. Compare lastProcessedHeight with your node's tip.
  4. An empty result is not proof. It can mean the scanner is behind, or that a valid deploy has not reached the confirmation depth yet.
  5. Handle reversal. A recent event can disappear after a reorg. Do not treat a shallow event as final.
  6. Do not mix protocols. An Ordinals or BRC-20 balance is not an OP_DROP balance, and an artifact is not a token event.
  7. Verify what matters yourself. For anything valuable, re-derive the result from block data using the specification instead of trusting a single indexer.