Skip to main content
← Back to Docs

SDKs & Libraries

Code examples and helper patterns for your preferred language

📦 SDK Status

Official SDKs are coming Q1 2025. Until then, use our REST API directly with these helper patterns. The API is simple enough that you don't need an SDK to get started.

Why no SDKs yet? We're focused on stability and API design. Once the API is stable, we'll release official SDKs for all major languages.
🟢

Node.js / TypeScript

Use fetch + crypto for a simple, dependency-free client

Complete CertNode Client

Create a reusable client class:

// lib/certnode.ts
import crypto from 'crypto'

export interface ReceiptData {
  type: 'transaction' | 'content' | 'operations'
  data: Record<string, any>
  metadata?: Record<string, any>
  parent_id?: string
}

export interface Receipt {
  id: string
  type: string
  created_at: string
  data: Record<string, any>
  metadata?: Record<string, any>
  signature: string
  timestamp_token: string
  verified: boolean
  verification_url: string
}

export class CertNodeClient {
  private apiKey: string
  private baseURL: string

  constructor(apiKey: string, baseURL = 'https://certnode.io/api/v1') {
    this.apiKey = apiKey
    this.baseURL = baseURL
  }

  // Hash PII before sending
  private hashPII(value: string): string {
    return crypto.createHash('sha256').update(value).digest('hex')
  }

  // Create receipt
  async createReceipt(params: ReceiptData): Promise<Receipt> {
    const response = await fetch(`${this.baseURL}/receipts`, {
      method: 'POST',
      headers: {
        'X-API-Key': this.apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(params),
    })

    if (!response.ok) {
      throw new Error(`Failed to create receipt: ${response.statusText}`)
    }

    return response.json()
  }

  // Get receipt by ID
  async getReceipt(id: string): Promise<Receipt> {
    const response = await fetch(`${this.baseURL}/receipts/${id}`, {
      headers: {
        'X-API-Key': this.apiKey,
      },
    })

    if (!response.ok) {
      throw new Error(`Failed to get receipt: ${response.statusText}`)
    }

    return response.json()
  }

  // Verify receipt
  async verifyReceipt(id: string) {
    const response = await fetch(`${this.baseURL}/verify/${id}`)

    if (!response.ok) {
      throw new Error(`Failed to verify receipt: ${response.statusText}`)
    }

    return response.json()
  }

  // Helper: Hash email before including in receipt
  hashEmail(email: string): string {
    return this.hashPII(email)
  }
}

// Usage
export const certnode = new CertNodeClient(process.env.CERTNODE_API_KEY!)

// Example: Create transaction receipt
const receipt = await certnode.createReceipt({
  type: 'transaction',
  data: {
    amount: 299.99,
    currency: 'USD',
    product: 'Annual Subscription',
    customer_email_hash: certnode.hashEmail('user@example.com'),
  },
  metadata: {
    platform: 'stripe',
    environment: 'production',
  },
})

console.log('Receipt created:', receipt.verification_url)
🐍

Python

Use requests + hashlib for a simple client

Complete CertNode Client

# certnode.py
import os
import hashlib
import requests
from typing import Dict, Any, Optional

class CertNodeClient:
    def __init__(self, api_key: str, base_url: str = "https://certnode.io/api/v1"):
        self.api_key = api_key
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            "X-API-Key": api_key,
            "Content-Type": "application/json"
        })

    def hash_pii(self, value: str) -> str:
        """Hash PII using SHA-256"""
        return hashlib.sha256(value.encode()).hexdigest()

    def create_receipt(
        self,
        receipt_type: str,
        data: Dict[str, Any],
        metadata: Optional[Dict[str, Any]] = None,
        parent_id: Optional[str] = None
    ) -> Dict[str, Any]:
        """Create a cryptographic receipt"""
        payload = {
            "type": receipt_type,
            "data": data,
            "metadata": metadata or {},
        }

        if parent_id:
            payload["parent_id"] = parent_id

        response = self.session.post(
            f"{self.base_url}/receipts",
            json=payload
        )
        response.raise_for_status()
        return response.json()

    def get_receipt(self, receipt_id: str) -> Dict[str, Any]:
        """Get receipt by ID"""
        response = self.session.get(f"{self.base_url}/receipts/{receipt_id}")
        response.raise_for_status()
        return response.json()

    def verify_receipt(self, receipt_id: str) -> Dict[str, Any]:
        """Verify receipt cryptographic signature"""
        response = requests.get(f"{self.base_url}/verify/{receipt_id}")
        response.raise_for_status()
        return response.json()

    def hash_email(self, email: str) -> str:
        """Helper: Hash email before including in receipt"""
        return self.hash_pii(email)

# Usage
certnode = CertNodeClient(os.getenv("CERTNODE_API_KEY"))

# Example: Create transaction receipt
receipt = certnode.create_receipt(
    receipt_type="transaction",
    data={
        "amount": 299.99,
        "currency": "USD",
        "product": "Annual Subscription",
        "customer_email_hash": certnode.hash_email("user@example.com"),
    },
    metadata={
        "platform": "stripe",
        "environment": "production"
    }
)

print(f"Receipt created: {receipt['verification_url']}")
🔷

Go

Use net/http + crypto for a type-safe client

Complete CertNode Client

// certnode.go
package certnode

import (
    "bytes"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type Client struct {
    APIKey  string
    BaseURL string
    client  *http.Client
}

type Receipt struct {
    ID              string                 `json:"id"`
    Type            string                 `json:"type"`
    CreatedAt       string                 `json:"created_at"`
    Data            map[string]interface{} `json:"data"`
    Metadata        map[string]interface{} `json:"metadata"`
    Signature       string                 `json:"signature"`
    TimestampToken  string                 `json:"timestamp_token"`
    Verified        bool                   `json:"verified"`
    VerificationURL string                 `json:"verification_url"`
}

func NewClient(apiKey string) *Client {
    return &Client{
        APIKey:  apiKey,
        BaseURL: "https://certnode.io/api/v1",
        client:  &http.Client{},
    }
}

func (c *Client) HashPII(value string) string {
    hash := sha256.Sum256([]byte(value))
    return hex.EncodeToString(hash[:])
}

func (c *Client) CreateReceipt(
    receiptType string,
    data map[string]interface{},
    metadata map[string]interface{},
    parentID string,
) (*Receipt, error) {
    payload := map[string]interface{}{
        "type":     receiptType,
        "data":     data,
        "metadata": metadata,
    }

    if parentID != "" {
        payload["parent_id"] = parentID
    }

    body, err := json.Marshal(payload)
    if err != nil {
        return nil, fmt.Errorf("failed to marshal request: %w", err)
    }

    req, err := http.NewRequest("POST", c.BaseURL+"/receipts", bytes.NewBuffer(body))
    if err != nil {
        return nil, fmt.Errorf("failed to create request: %w", err)
    }

    req.Header.Set("X-API-Key", c.APIKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := c.client.Do(req)
    if err != nil {
        return nil, fmt.Errorf("request failed: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        bodyBytes, _ := io.ReadAll(resp.Body)
        return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(bodyBytes))
    }

    var receipt Receipt
    if err := json.NewDecoder(resp.Body).Decode(&receipt); err != nil {
        return nil, fmt.Errorf("failed to decode response: %w", err)
    }

    return &receipt, nil
}

// Usage example
func main() {
    client := certnode.NewClient(os.Getenv("CERTNODE_API_KEY"))

    receipt, err := client.CreateReceipt(
        "transaction",
        map[string]interface{}{
            "amount":              299.99,
            "currency":            "USD",
            "product":             "Annual Subscription",
            "customer_email_hash": client.HashPII("user@example.com"),
        },
        map[string]interface{}{
            "platform":    "stripe",
            "environment": "production",
        },
        "",
    )

    if err != nil {
        log.Fatalf("Failed to create receipt: %v", err)
    }

    fmt.Printf("Receipt created: %s\n", receipt.VerificationURL)
}
💎

Ruby

Use net/http + digest for a simple client

Complete CertNode Client

# certnode.rb
require 'net/http'
require 'json'
require 'digest'

class CertNodeClient
  attr_reader :api_key, :base_url

  def initialize(api_key, base_url = 'https://certnode.io/api/v1')
    @api_key = api_key
    @base_url = base_url
  end

  def hash_pii(value)
    Digest::SHA256.hexdigest(value)
  end

  def create_receipt(type:, data:, metadata: {}, parent_id: nil)
    uri = URI("#{base_url}/receipts")

    payload = {
      type: type,
      data: data,
      metadata: metadata
    }
    payload[:parent_id] = parent_id if parent_id

    request = Net::HTTP::Post.new(uri)
    request['X-API-Key'] = api_key
    request['Content-Type'] = 'application/json'
    request.body = payload.to_json

    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end

    raise "Failed to create receipt: #{response.code}" unless response.code == '200'

    JSON.parse(response.body)
  end

  def get_receipt(receipt_id)
    uri = URI("#{base_url}/receipts/#{receipt_id}")

    request = Net::HTTP::Get.new(uri)
    request['X-API-Key'] = api_key

    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end

    raise "Failed to get receipt: #{response.code}" unless response.code == '200'

    JSON.parse(response.body)
  end

  def verify_receipt(receipt_id)
    uri = URI("#{base_url}/verify/#{receipt_id}")

    response = Net::HTTP.get_response(uri)
    raise "Failed to verify receipt: #{response.code}" unless response.code == '200'

    JSON.parse(response.body)
  end

  def hash_email(email)
    hash_pii(email)
  end
end

# Usage
certnode = CertNodeClient.new(ENV['CERTNODE_API_KEY'])

receipt = certnode.create_receipt(
  type: 'transaction',
  data: {
    amount: 299.99,
    currency: 'USD',
    product: 'Annual Subscription',
    customer_email_hash: certnode.hash_email('user@example.com')
  },
  metadata: {
    platform: 'stripe',
    environment: 'production'
  }
)

puts "Receipt created: #{receipt['verification_url']}"
🐘

PHP

Use curl + hash for a simple client

Complete CertNode Client

<?php
// CertNodeClient.php

class CertNodeClient {
    private $apiKey;
    private $baseURL;

    public function __construct($apiKey, $baseURL = 'https://certnode.io/api/v1') {
        $this->apiKey = $apiKey;
        $this->baseURL = $baseURL;
    }

    private function hashPII($value) {
        return hash('sha256', $value);
    }

    public function createReceipt($type, $data, $metadata = [], $parentId = null) {
        $payload = [
            'type' => $type,
            'data' => $data,
            'metadata' => $metadata
        ];

        if ($parentId) {
            $payload['parent_id'] = $parentId;
        }

        $ch = curl_init($this->baseURL . '/receipts');
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'X-API-Key: ' . $this->apiKey,
            'Content-Type: application/json'
        ]);

        $response = curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($statusCode !== 200) {
            throw new Exception("Failed to create receipt: " . $response);
        }

        return json_decode($response, true);
    }

    public function getReceipt($receiptId) {
        $ch = curl_init($this->baseURL . '/receipts/' . $receiptId);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'X-API-Key: ' . $this->apiKey
        ]);

        $response = curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($statusCode !== 200) {
            throw new Exception("Failed to get receipt: " . $response);
        }

        return json_decode($response, true);
    }

    public function verifyReceipt($receiptId) {
        $ch = curl_init($this->baseURL . '/verify/' . $receiptId);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);
        $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($statusCode !== 200) {
            throw new Exception("Failed to verify receipt: " . $response);
        }

        return json_decode($response, true);
    }

    public function hashEmail($email) {
        return $this->hashPII($email);
    }
}

// Usage
$certnode = new CertNodeClient(getenv('CERTNODE_API_KEY'));

$receipt = $certnode->createReceipt(
    'transaction',
    [
        'amount' => 299.99,
        'currency' => 'USD',
        'product' => 'Annual Subscription',
        'customer_email_hash' => $certnode->hashEmail('user@example.com')
    ],
    [
        'platform' => 'stripe',
        'environment' => 'production'
    ]
);

echo "Receipt created: " . $receipt['verification_url'] . "\n";
?>
💻

cURL (Command Line)

Quick testing and scripting

Create Receipt

curl -X POST https://certnode.io/api/v1/receipts \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "transaction",
    "data": {
      "amount": 299.99,
      "currency": "USD",
      "product": "Annual Subscription"
    },
    "metadata": {
      "platform": "stripe"
    }
  }'

Get Receipt

curl https://certnode.io/api/v1/receipts/rcpt_abc123xyz789 \
  -H "X-API-Key: YOUR_API_KEY"

Verify Receipt

curl https://certnode.io/api/v1/verify/rcpt_abc123xyz789

📦 Official SDKs Coming Soon

We're building official SDKs for all major languages with these features:

✨ Type-safe APIs
Full TypeScript/type support
🔄 Automatic retries
With exponential backoff
📊 Built-in monitoring
Request logging and metrics
🔐 Automatic PII hashing
Helper functions for privacy

Want to be notified when SDKs are released? Email sdks@certnode.io with your preferred language.