📦 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.
Quick Start: Choose Your Language
🟢
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
Next Steps
📦 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.