Skip to main content
← All resources

How to sign Claude outputs with cryptographic provenance in 5 minutes

If your app generates content with Claude, you eventually face a question: "can you prove this came from your system, at this time, from this model?" This post walks through adding cryptographic provenance to any Anthropic API call.

The situation

Your app calls the Anthropic API. Claude generates marketing copy, legal summaries, research notes, product descriptions, whatever. You store the output in your database alongside the user's data.

Then one of these happens:

  • A customer disputes that the content they received was generated legitimately. "You must have edited it." "You outsourced this." "This wasn't AI-generated, it was plagiarized."
  • A regulator asks for EU AI Act Article 50 compliance proof.
  • Legal asks you to prove the generation timestamp for a discovery request.
  • A partner needs to verify that content came from your pipeline and hasn't been tampered with downstream.

Your database timestamp isn't proof. Database logs can be modified. Your own systems can't independently attest to their own outputs. You need a third-party cryptographic record.

The 5-minute fix

Install @certnode/sdk, get an API key, add one call after every Claude invocation.

terminal
npm install @certnode/sdk
generate-and-sign.ts
import Anthropic from '@anthropic-ai/sdk'
import { CertNode } from '@certnode/sdk'
import crypto from 'crypto'

const claude = new Anthropic()
const cert = new CertNode({ apiKey: process.env.CERTNODE_API_KEY! })

async function generateAndSign(prompt: string, userId: string) {
  const response = await claude.messages.create({
    model: 'claude-opus-4-7',
    max_tokens: 2000,
    messages: [{ role: 'user', content: prompt }],
  })

  const output = response.content[0].type === 'text'
    ? response.content[0].text
    : ''

  // Hash the prompt for privacy-preserving audit. We don't log
  // the raw prompt; we store a hash that proves what was requested
  // without leaking it.
  const promptHash = crypto.createHash('sha256').update(prompt).digest('hex')

  const signed = await cert.signAIOutput({
    output,
    model: 'claude-opus-4-7',
    provider: 'anthropic',
    promptHash,
  })

  return {
    output,
    signature: signed.signature,
    receiptId: signed.receiptId,
    verifyUrl: signed.verifyUrl,
    signedAt: signed.signedAt,
  }
}

Store receiptId and signature with your content in the database. Return verifyUrl to the user if you want them to be able to verify independently.

What gets signed

Every call produces a receipt containing:

  • sha256 hash of the AI output
  • JWS signature (ES256) over the hash plus metadata, signed with CertNode's private key
  • RFC 3161 timestamp token from an independent Time Stamping Authority (FreeTSA) — same standard used for legally signed documents
  • Bitcoin anchor via OpenTimestamps (queued, confirmed in a Bitcoin block within 1-2 hours)
  • Model + provider metadata — claude-opus-4-7, anthropic
  • Optional prompt hash — proves what was requested without logging the raw prompt

Verifying later

When a dispute happens, verification is free and public. Anyone can verify without an account:

const verification = await cert.verify({
  receiptId: 'uuid-from-earlier',
  content: originalContent,  // re-hashes and compares
})

if (verification.valid) {
  console.log('Content signed at:', verification.receipt.signedAt)
  console.log('By model:', verification.receipt.model)
  console.log('Timestamp proof:', verification.receipt.timestamps.rfc3161)
}

Or send your customer to certnode.io/verify/[receiptId] — a public page anyone can use to verify independently, without trusting you or us.

EU AI Act Article 50 compliance

Article 50 of Regulation (EU) 2024/1689 — the EU AI Act — requires providers of AI systems that generate content to label outputs as machine-generated. Enforcement begins August 2026.

The regulation doesn't specify an exact technical standard, but cryptographic provenance metadata (model identifier, timestamp, independent verification) clearly satisfies the transparency obligations. A CertNode signature includes all three: provider, model, and RFC 3161 timestamp from an independent authority.

OpenAI, Mistral, and other providers

CertNode is provider-agnostic. Same SDK call, different metadata:

// OpenAI
await cert.signAIOutput({
  output: completion.choices[0].message.content!,
  model: 'gpt-4o',
  provider: 'openai',
})

// Mistral
await cert.signAIOutput({
  output: response.choices[0].message.content,
  model: 'mistral-large-2',
  provider: 'mistral',
})

Pricing

100 signings per month free — no card required. Beyond that, pay as you go at $0.01 per signing, dropping to $0.007 at 10K/month, $0.004 at 100K, $0.002 at 1M+. Volume discounts apply automatically. Verifications are always free, at any volume.

Get an API key →

Published April 24, 2026.