API Reference

One endpoint.
Every credential operation.

Upload files, stamp them on-chain, verify hashes, stream events, and generate signed links — all through a single REST path with header-based routing. No blockchain libraries. No IPFS nodes. Just HTTP.

POST upload + stamp GET list + verify PATCH stamp collection HEAD status check SSE real-time events
POST
Upload & Stamp
File upload, group creation
GET
List & Verify
Groups, files, hash check
PATCH
Stamp Collection
Postmark all files
HEAD
Status Check
Credits, stats via headers
DELETE
Remove File
Delete by hash

All on /webhook/{apikey}

Upload & Stamp

File to blockchain in one request

POST a file with stamp-immediately: true and Chainletter handles IPFS pinning, CIDv0 computation, on-chain stamping, and ledger indexing. One round-trip.

No file? Send a JSON body with a CID to register a hash. Or send nothing to create a group.

POST /webhook/{apikey}
// Upload a file and stamp immediately
const res = await fetch("https://service-link.clstamp.com/webhook/YOUR_API_KEY", {
  method: "POST",
  headers: {
    "secret-key":        "YOUR_SECRET_KEY",
    "group-id":          "my-credentials",
    "stamp-immediately": "true"
  },
  body: formData  // FormData with 'file' field
});

// → 201
{ "success": true, "hash": "QmNPHR...", "files_stamped": 1 }
List & Verify

Three workflows, one GET

No group-id? Returns all groups. Include it? Files with fresh stamping status. Add a hash header? Full verification — contract, tx ID, every IPCM stamp for that CID.

GET /webhook/{apikey} — verify hash
const res = await fetch("https://service-link.clstamp.com/webhook/YOUR_API_KEY", {
  headers: {
    "secret-key": "YOUR_SECRET_KEY",
    "hash": "QmU4AvzpnrJRfKDe9KBvTUxCLJ..."
  }
});

// → 200
{
  "data": {
    "contract": "0x6019ab8cb194...8b2bdd",
    "created": 1748620068,
    "foreign_tx_id": "0x21c3e85c..."
  },
  "allResults": [ /* every IPCM stamp */ ]
}
Batch Stamping

Stamp an entire collection at once

Upload files into a group over time, then PATCH to stamp them all on-chain in one transaction. Efficient for diploma runs, compliance audits, bulk certifications.

PATCH /webhook/{apikey}
const res = await fetch("https://service-link.clstamp.com/webhook/YOUR_API_KEY", {
  method: "PATCH",
  headers: {
    "secret-key": "YOUR_SECRET_KEY",
    "group-id":   "spring-2025-diplomas"
  }
});

// → 200
{ "success": true, "files_stamped": 247, "network": "public" }
Real-Time Events

Server-Sent Events for every action

Open an SSE connection and receive events the moment they happen. Build reactive dashboards, audit logs, or integrations without polling.

file.uploadedfile.deleted collection.stampedcollection.stamp_failed group.createdwebhook.enabled
SSE /webhook/{apikey}/events/stream
const events = new EventSource(
  "https://service-link.clstamp.com/webhook/YOUR_API_KEY/events/stream",
  { headers: { "secret-key": "YOUR_SECRET_KEY" } }
);

events.onmessage = (e) => {
  const event = JSON.parse(e.data);
  console.log(event.type, event.data);
};
Direct Uploads

Client-side uploads without exposing keys

Generate time-limited signed upload URLs for your end users. No proxy needed, no keys exposed. Set expiration, size limits, and MIME types per link.

GET /webhook/{apikey}/upload-link
const res = await fetch(
  "https://service-link.clstamp.com/webhook/YOUR_API_KEY/upload-link"
  + "?expires=3600&max_file_size=5242880",
  { headers: { "secret-key": "YOUR_SECRET_KEY" } }
);

// → 200
{ "upload_url": "https://uploads.pinata.cloud/v3/...", "expires_in": 3600 }

Full endpoint reference

MethodPathDescription
POST/webhook/{apikey}Upload file, register hash, or create group. Optional immediate stamping.
GET/webhook/{apikey}List groups, list files (with bulk check), or verify a hash.
PATCH/webhook/{apikey}Stamp all files in a group on-chain.
HEAD/webhook/{apikey}Status — credits, group stats via response headers.
DELETE/webhook/{apikey}Remove a file by hash.
GET.../events/streamSSE — real-time stream of all events.
GET.../upload-linkSigned upload URL for client-side IPFS uploads.
GET.../download-linkSigned download URL with optional image resizing.
GET.../list-remoteList remote Pinata files by group.
POST.../jwtSingle-use JWT (30-day validity).

Authentication

Two values. Both in headers. That's it.

API Key

Path parameter. Identifies your tenant and routes to your IPCM contract.

secret-key

Request header. Authenticates you as the key owner. Use signed upload links for browser uploads.

HEAD Quick status check
const res = await fetch("https://service-link.clstamp.com/webhook/YOUR_API_KEY", {
  method: "HEAD",
  headers: { "secret-key": "YOUR_SECRET_KEY", "group-id": "my-credentials" }
});

// Response headers:
X-Credits: 847    X-Total-Files: 23    X-Total-Size: 48234567

Start stamping credentials today

Get your API key, make a POST, and your first credential is on-chain.