Skip to main contentCertyo Developer Portal
Tutorial · 5 min read

Quickstart

Go from zero to a verified, blockchain-anchored record in about 5 minutes.

Prerequisites
You'll need curl (or any HTTP client) and a Unix-style terminal. No SDK installation required.

Step 0 · Get your credentials

The Certyo team provisions your organization — a tenant (your company), a client (an app or integration under the tenant), and an API key. You receive three values:

  • tenantId — e.g. acme-corp
  • clientId — e.g. acme-orders-ingest
  • X-API-Key — e.g. certyo_sk_live_abc123...
One-time reveal
The API key is shown only once at creation. Store it in a secrets vault immediately. If you lose it, you'll need to revoke and regenerate.

Export it in your shell for this tutorial:

export CERTYO_API_KEY="certyo_sk_live_abc123..."
export CERTYO_TENANT="acme-corp"
export CERTYO_API="https://www.certyos.com"

Step 1 · Ingest your first record

Send a record to the ingestion endpoint. A record is any JSON payload you want proven authentic later — a database row, an audit event, a transaction, whatever. The required fields:

  • tenantId — your tenant identifier
  • database — logical grouping (e.g. "production")
  • collection — logical sub-grouping (e.g. "orders")
  • recordId — your unique identifier for this record
  • recordPayload — the actual data, as a JSON object
Requestbash
curl -X POST "${CERTYO_API}/api/v1/records" \
  -H "X-API-Key: ${CERTYO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "'"$CERTYO_TENANT"'",
    "database": "production",
    "collection": "orders",
    "recordId": "order-12345",
    "recordPayload": {
      "orderId": "order-12345",
      "customerId": "cust-789",
      "amount": 299.99,
      "currency": "USD",
      "createdAt": "2026-04-12T10:00:00Z"
    }
  }'
Response · 202 Acceptedjson
{
  "recordId": "order-12345",
  "recordHash": "5f3c7d2e1a9b4c8f6e2d9a1b3c5f7e2d9a1b3c5f7e2d9a1b3c5f7e2d9a1b3c",
  "tenantId": "acme-corp",
  "acceptedAt": "2026-04-12T15:30:45.123Z",
  "idempotencyReplayed": false
}

The 202 Accepted status means your record is in the pipeline — it has been hashed and queued for batching. Save recordHash if you want to verify later without re-sending the payload.


Step 2 · Wait for the batch to anchor

Certyo accumulates records into batches and anchors each batch's Merkle root to Polygon in a single transaction. Batches close when either condition is met:

  • 1000 records have been collected, OR
  • 60 seconds have elapsed since the first record of the batch

For a single test record, you'll wait for the 60-second timer. After that, the batch is submitted to Polygon and confirmed in ~2 seconds.

Total latency
From POST /records to 'anchoredOnChain: true' is typically 60–90 seconds in production.

You can poll the snapshot status to check progress:

Check anchoring statusbash
curl "${CERTYO_API}/api/v1/snapshots?tenantId=${CERTYO_TENANT}&recordId=order-12345" \
  -H "X-API-Key: ${CERTYO_API_KEY}"

Look for status: "Anchored" and onChainConfirmed: true. See the polling guide for a production-ready poll loop.


Step 3 · Verify the record

Now the moment of truth. Send the original payload to the verification endpoint — Certyo will recompute the hash, walk the Merkle proof up to the batch root, and check the root against the on-chain Polygon contract.

Verifybash
curl -X POST "${CERTYO_API}/api/v1/verify/record" \
  -H "X-API-Key: ${CERTYO_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "'"$CERTYO_TENANT"'",
    "database": "production",
    "collection": "orders",
    "recordId": "order-12345",
    "payload": {
      "orderId": "order-12345",
      "customerId": "cust-789",
      "amount": 299.99,
      "currency": "USD",
      "createdAt": "2026-04-12T10:00:00Z"
    }
  }'
Response · 200 OK (trimmed)json
{
  "verified": true,
  "verificationStatus": "pass",
  "reasonCategory": "verified_anchored",
  "snapshotId": "snap_xyz789...",
  "recordId": "order-12345",
  "snapshotHash": "5f3c7d2e1a9b4c8f6e2d9a1b3c5f7e2d9a1b3c5f7e2d9a1b3c5f7e2d9a1b3c",
  "computedPayloadHash": "5f3c7d2e1a9b4c8f6e2d9a1b3c5f7e2d9a1b3c5f7e2d9a1b3c5f7e2d9a1b3c",
  "batchId": "batch_abc123...",
  "merkleRoot": "0x7e2d9a1b3c5f7e2d9a1b...",
  "anchoredOnChain": true,
  "chainId": 137,
  "onChainProof": {
    "polygonScanContractUrl": "https://polygonscan.com/address/0xeeCD2FAD7841E113BCeEB39c704c78B91E35D6f2",
    "polygonScanEventUrl": "https://polygonscan.com/tx/0x9a8f7e6d..."
  },
  "ipfsEvidence": {
    "ipfsCid": "QmAbc123XyZ789...",
    "ipfsGatewayUrl": "https://gateway.pinata.cloud/ipfs/QmAbc123XyZ789.../manifest.json"
  },
  "message": "Record verified: hash matches and batch anchored on Polygon mainnet."
}

verified: true means three things are simultaneously true:

  1. The hash of the payload you sent matches the hash stored at ingestion time.
  2. The record is in a Merkle batch whose root is committed on Polygon.
  3. The on-chain root matches the root computed from the current batch.

What just happened?

You just proved that a piece of data existed at a specific point in time and has not been tampered with — without trusting Certyo. The evidence trail lives in three places:

  • Certyo (hot storage) — searchable MongoDB index for fast verification
  • IPFS (cold evidence) — full manifest with all record hashes, content-addressed by CID
  • Polygon (immutable anchor) — the Merkle root and timestamp, anchored in a smart contract

If Certyo disappeared tomorrow, you could still fetch the IPFS manifest, reconstruct the Merkle tree, and verify against the on-chain root. Your audit trail outlives us.


Next steps