Multi-Chain Anchoring

Anchor records to Polygon (public), Hyperledger Fabric (private), or both at once. One API, three chains — your choice.

Overview

Anchora supports four anchoring strategies. The strategy you pick determines which chain(s) your record's Merkle root gets written to. All strategies share the same POST /v1/anchor API — switching strategy is a Settings change, not a code change.

TL;DR: Pick Public for cheap public verifiability. Pick Private for data residency on your own Fabric network. Pick Hybrid if your auditors want both. Pick Custom if you have bespoke chain requirements.

The four strategies

1. Public — Polygon (default)

Anchors to Polygon Amoy (testnet) or Polygon Mainnet. Records can be independently verified on Polygonscan. Cost ~$0.000007 per record thanks to Merkle tree batching (256 records per on-chain transaction).

Best for: B2C apps, AI-content provenance, public attestations, anything where third parties need to verify without your help.

2. Private — Hyperledger Fabric (BYO mode)

Anchors to your own Hyperledger Fabric network. You run the peers, orderer, and CA. Anchora deploys the anchora-anchor chaincode on your channel and authenticates via your X.509 identity. No gas fees, data never leaves your network.

Best for: Banking, healthcare, defense, regulated consortiums. Any workflow where data sovereignty is non-negotiable.

3. Hybrid — Both at once

Anchors the same Merkle root to BOTH your private Fabric network AND a public EVM chain (Polygon by default) in a single batch. Internal compliance team sees the Fabric anchor; regulators or external auditors see the Polygon anchor. Same hash. Two independent attestations.

Best for: Regulated workflows that need internal control AND external verifiability. Banks, pharma, gov.

4. Custom — Any EVM RPC, any Fabric profile

Manual configuration. Point at Ethereum Mainnet, Sepolia, Besu, Quorum, or any custom EVM RPC. Or any Fabric channel + MSP combination. For advanced deployments.

Webhook delivery

Webhooks now carry chain provenance so receivers can branch on the chain type without re-querying the API.

New headers

HTTP Headers
X-Anchora-Event: ANCHORED
X-Anchora-Hash: <full hash>
X-Anchora-Package: SEPARATED | IN_PLACE | MANAGED
X-Anchora-Chain: evm | fabric        ← NEW
X-Anchora-Network: polygon-amoy | fabric-byo | ...   ← NEW
X-Anchora-Retry-Attempt: 0..5

EVM body example

JSON
{
  "type": "ANCHORED",
  "hash": "6e35efbd84a333a63e4155abdea2b8ed7e373144efb0ea52a057aa88dca2caa7",
  "recordId": "507f1f77bcf86cd799439011",
  "chainType": "evm",
  "networkId": "polygon-amoy",
  "blockNumber": 38235356,
  "transactionHash": "0xd8f21871c197f1942e105ab304e2930db2c18baeb1e26a897f5d48dcaaa1597b",
  "batchId": 116,
  "anchoredAt": "2026-05-12T11:00:44.940Z",
  "merkleProof": [],
  "metadata": {}
}

Fabric body example

Note the differences: blockNumber is explicit null (Fabric has no block heights via fabric-gateway), transactionHash is the raw Fabric txID (no 0x), and batchId is a string.

JSON
{
  "type": "ANCHORED",
  "hash": "63e33ef9eb4b58c8f2ecd54e9ea3d1e15b8f488c3d22df8447f8951f0e2706e2",
  "recordId": "507f1f77bcf86cd799439012",
  "chainType": "fabric",
  "networkId": "fabric-byo",
  "blockNumber": null,
  "transactionHash": "95cfed3ad9d5c49af57f4045cbf119e1308cb5217c11f929ed3475c7904c48d4",
  "batchId": "7",
  "anchoredAt": "2026-05-12T11:21:10.736Z",
  "merkleProof": ["0x70bdd5472143f6773e2c0c194b75cf03307f72236d1dfdfc2ebf0a49ce0930be"],
  "metadata": {}
}

Hybrid body example

A Hybrid record's webhook carries BOTH chain anchors in a single delivery — primary fields at top level, secondary inside dualAnchor.

JSON
{
  "type": "ANCHORED",
  "hash": "e90e818fbf...",
  "chainType": "fabric",
  "networkId": "fabric-byo",
  "batchId": "4",
  "transactionHash": "aea1e2167553e7e3...",
  "blockNumber": null,
  "merkleProof": [],
  "dualAnchor": {
    "chainType": "evm",
    "networkId": "polygon-amoy",
    "batchId": 114,
    "blockNumber": 38228377,
    "transactionHash": "0x6bc51454f711b1348e49ad...",
    "merkleProof": [],
    "anchoredAt": "..."
  }
  // ... + standard fields
}

Verification response /v1/verify

For Hybrid records, /v1/verify returns independent verification verdicts for both chains.

JSON
{
  "success": true,
  "verified": true,
  "status": "VERIFIED",
  "blockchainVerified": true,
  "chainType": "fabric",
  "networkId": "fabric-byo",
  "batchId": "4",
  "onChainMerkleRoot": "0xe90e818...",
  "dualAnchor": {
    "verified": true,
    "chainType": "evm",
    "networkId": "polygon-amoy",
    "batchId": 114,
    "onChainMerkleRoot": "0xe90e818..."
  }
}

Reason codes inside dualAnchor: reader-unavailable (chain reader not configured) or batch-not-found (secondary anchor never completed). Use these to distinguish “couldn't check” from “actively tampered” — verified: null means unknown, verified: false means tampered.

Reliability features

Dual-anchor retry

If the secondary chain fails to anchor at batch time (RPC blip, timeout), the worker retries hourly up to 5 attempts. Primary chain anchor stands; record remains valid; secondary back-fills on success. Once filled, a webhook with the complete shape is delivered.

Cert expiry monitoring

Fabric X.509 certs eventually expire. Anchora monitors certExpiresAt on every project and emails the organization owner at 30 / 7 / 1 days before expiry. Re-import a fresh cert in Project Settings → Blockchain to re-arm the warnings.

Backward compatibility

Pre-existing EVM customers see no breaking changes. All old API fields are preserved. New fields (chainType, networkId, dualAnchor, X-Anchora-Chain, X-Anchora-Network) are additive only — old webhook receivers that ignore them keep working.

Next Steps