Developer Quick Start

Last Updated: 2026-02-16


Get started with the cloak.business API in 5 minutes. This guide covers authentication, basic operations, and code examples in multiple languages.

Recommended: Use our official SDKs for JavaScript/TypeScript or Python instead of raw API calls. The SDKs provide type safety, automatic retry logic, error handling, and client-side encryption.

# JavaScript/TypeScript
npm install @cloak-business/sdk

# Python
pip install cloak-business

See the SDK Reference for complete documentation.


Table of Contents#

  1. Get Your API Key
  2. First API Call
  3. Complete Workflow
  4. Code Examples
  5. Common Patterns
  6. Next Steps

Get Your API Key#

  1. Sign in at cloak.business
  2. Go to Dashboard > API Keys
  3. Click Create API Key
  4. Copy the key (starts with cb_)

Important: Store your API key securely. Never commit it to version control or expose it in client-side code.


First API Call#

Test your API key with a simple analysis request:

curl -X POST https://cloak.business/api/presidio/analyze \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "Contact John Doe at john@example.com"}'

Expected Response:

{
  "results": [
    {"entity_type": "PERSON", "start": 8, "end": 16, "score": 0.85, "text": "John Doe"},
    {"entity_type": "EMAIL_ADDRESS", "start": 20, "end": 36, "score": 1.0, "text": "john@example.com"}
  ],
  "tokens_charged": 2
}

If you see this response, your API key is working.


Complete Workflow#

A typical PII anonymization workflow has two steps:

Step 1: Analyze#

Detect PII entities in your text:

curl -X POST https://cloak.business/api/presidio/analyze \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Call John at 555-123-4567 or email john@test.com",
    "language": "en"
  }'

Step 2: Anonymize#

Apply anonymization using the analysis results:

curl -X POST https://cloak.business/api/presidio/anonymize \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Call John at 555-123-4567 or email john@test.com",
    "analyzer_results": [
      {"entity_type": "PERSON", "start": 5, "end": 9, "score": 0.85},
      {"entity_type": "PHONE_NUMBER", "start": 13, "end": 25, "score": 0.95},
      {"entity_type": "EMAIL_ADDRESS", "start": 35, "end": 48, "score": 1.0}
    ],
    "operators": {
      "PERSON": {"type": "replace"},
      "PHONE_NUMBER": {"type": "mask", "masking_char": "*", "chars_to_mask": 7},
      "EMAIL_ADDRESS": {"type": "hash"}
    }
  }'

Result:

{
  "text": "Call <PERSON> at ***-***-4567 or email 5d41402abc4b2a76b9719d911017c592",
  "items": [...]
}

Code Examples#

Python#

import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://cloak.business/api"

def analyze(text: str, language: str = "en") -> dict:
    """Detect PII entities in text."""
    response = requests.post(
        f"{BASE_URL}/presidio/analyze",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"text": text, "language": language}
    )
    response.raise_for_status()
    return response.json()

def anonymize(text: str, analyzer_results: list, operators: dict = None) -> dict:
    """Anonymize text based on analysis results."""
    payload = {
        "text": text,
        "analyzer_results": analyzer_results
    }
    if operators:
        payload["operators"] = operators

    response = requests.post(
        f"{BASE_URL}/presidio/anonymize",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json=payload
    )
    response.raise_for_status()
    return response.json()

def protect_text(text: str, method: str = "replace") -> str:
    """Full workflow: analyze and anonymize text."""
    # Step 1: Analyze
    analysis = analyze(text)

    if not analysis.get("results"):
        return text  # No PII found

    # Step 2: Anonymize
    operators = {
        result["entity_type"]: {"type": method}
        for result in analysis["results"]
    }

    result = anonymize(text, analysis["results"], operators)
    return result["text"]

# Usage
if __name__ == "__main__":
    original = "Contact John Doe at john@example.com"
    protected = protect_text(original)
    print(f"Original: {original}")
    print(f"Protected: {protected}")

JavaScript/TypeScript#

const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://cloak.business/api";

interface AnalyzerResult {
  entity_type: string;
  start: number;
  end: number;
  score: number;
  text?: string;
}

interface AnalyzeResponse {
  results: AnalyzerResult[];
  tokens_charged: number;
}

interface AnonymizeResponse {
  text: string;
  items: any[];
  tokens_charged: number;
}

async function analyze(text: string, language = "en"): Promise<AnalyzeResponse> {
  const response = await fetch(`${BASE_URL}/presidio/analyze`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ text, language })
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  return response.json();
}

async function anonymize(
  text: string,
  analyzerResults: AnalyzerResult[],
  operators?: Record<string, { type: string; [key: string]: any }>
): Promise<AnonymizeResponse> {
  const response = await fetch(`${BASE_URL}/presidio/anonymize`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      text,
      analyzer_results: analyzerResults,
      operators
    })
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  return response.json();
}

async function protectText(text: string, method = "replace"): Promise<string> {
  // Step 1: Analyze
  const analysis = await analyze(text);

  if (!analysis.results.length) {
    return text; // No PII found
  }

  // Step 2: Build operators
  const operators: Record<string, { type: string }> = {};
  for (const result of analysis.results) {
    operators[result.entity_type] = { type: method };
  }

  // Step 3: Anonymize
  const result = await anonymize(text, analysis.results, operators);
  return result.text;
}

// Usage
(async () => {
  const original = "Contact John Doe at john@example.com";
  const protected_text = await protectText(original);
  console.log(`Original: ${original}`);
  console.log(`Protected: ${protected_text}`);
})();

Go#

package main

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

const (
    apiKey  = "YOUR_API_KEY"
    baseURL = "https://cloak.business/api"
)

type AnalyzerResult struct {
    EntityType string  `json:"entity_type"`
    Start      int     `json:"start"`
    End        int     `json:"end"`
    Score      float64 `json:"score"`
    Text       string  `json:"text,omitempty"`
}

type AnalyzeResponse struct {
    Results       []AnalyzerResult `json:"results"`
    TokensCharged int              `json:"tokens_charged"`
}

type AnonymizeResponse struct {
    Text          string `json:"text"`
    TokensCharged int    `json:"tokens_charged"`
}

func analyze(text, language string) (*AnalyzeResponse, error) {
    payload := map[string]string{"text": text, "language": language}
    body, _ := json.Marshal(payload)

    req, _ := http.NewRequest("POST", baseURL+"/presidio/analyze", bytes.NewBuffer(body))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var result AnalyzeResponse
    json.NewDecoder(resp.Body).Decode(&result)
    return &result, nil
}

func anonymize(text string, results []AnalyzerResult) (*AnonymizeResponse, error) {
    operators := make(map[string]map[string]string)
    for _, r := range results {
        operators[r.EntityType] = map[string]string{"type": "replace"}
    }

    payload := map[string]interface{}{
        "text":             text,
        "analyzer_results": results,
        "operators":        operators,
    }
    body, _ := json.Marshal(payload)

    req, _ := http.NewRequest("POST", baseURL+"/presidio/anonymize", bytes.NewBuffer(body))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var result AnonymizeResponse
    json.NewDecoder(resp.Body).Decode(&result)
    return &result, nil
}

func main() {
    text := "Contact John Doe at john@example.com"

    analysis, _ := analyze(text, "en")
    fmt.Printf("Found %d entities\n", len(analysis.Results))

    result, _ := anonymize(text, analysis.Results)
    fmt.Printf("Protected: %s\n", result.Text)
}

PHP#

<?php

$apiKey = "YOUR_API_KEY";
$baseUrl = "https://cloak.business/api";

function analyze(string $text, string $language = "en"): array {
    global $apiKey, $baseUrl;

    $ch = curl_init("$baseUrl/presidio/analyze");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            "Authorization: Bearer $apiKey",
            "Content-Type: application/json"
        ],
        CURLOPT_POSTFIELDS => json_encode([
            "text" => $text,
            "language" => $language
        ])
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

function anonymize(string $text, array $analyzerResults, array $operators = []): array {
    global $apiKey, $baseUrl;

    $payload = [
        "text" => $text,
        "analyzer_results" => $analyzerResults
    ];

    if (!empty($operators)) {
        $payload["operators"] = $operators;
    }

    $ch = curl_init("$baseUrl/presidio/anonymize");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            "Authorization: Bearer $apiKey",
            "Content-Type: application/json"
        ],
        CURLOPT_POSTFIELDS => json_encode($payload)
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

function protectText(string $text, string $method = "replace"): string {
    $analysis = analyze($text);

    if (empty($analysis["results"])) {
        return $text;
    }

    $operators = [];
    foreach ($analysis["results"] as $result) {
        $operators[$result["entity_type"]] = ["type" => $method];
    }

    $result = anonymize($text, $analysis["results"], $operators);
    return $result["text"];
}

// Usage
$original = "Contact John Doe at john@example.com";
$protected = protectText($original);
echo "Original: $original\n";
echo "Protected: $protected\n";

Common Patterns#

Pattern 1: Batch Processing#

Process multiple texts efficiently:

def batch_analyze(texts: list[str]) -> dict:
    response = requests.post(
        f"{BASE_URL}/presidio/batch",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"texts": texts, "language": "en"}
    )
    return response.json()

# Process 100 texts in one request
texts = ["Text 1...", "Text 2...", ...]
results = batch_analyze(texts)

Pattern 2: Encryption with Deanonymization#

Use encryption for reversible anonymization:

# Anonymize with encryption
result = anonymize(
    text="Contact John at john@test.com",
    analyzer_results=[...],
    operators={
        "PERSON": {"type": "encrypt", "key": "your-encryption-key"},
        "EMAIL_ADDRESS": {"type": "encrypt", "key": "your-encryption-key"}
    }
)

# Later: Deanonymize
original = requests.post(
    f"{BASE_URL}/presidio/deanonymize",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "text": result["text"],
        "anonymizer_results": result["items"],
        "deanonymizers": {
            "PERSON": {"type": "decrypt", "key": "your-encryption-key"},
            "EMAIL_ADDRESS": {"type": "decrypt", "key": "your-encryption-key"}
        }
    }
).json()

Pattern 3: Custom Entity Detection#

Add domain-specific patterns:

result = requests.post(
    f"{BASE_URL}/presidio/analyze",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "text": "Order #ORD-123456 for customer CUS-789012",
        "ad_hoc_recognizers": [
            {
                "entity_type": "ORDER_ID",
                "patterns": [{"name": "order", "regex": "ORD-\\d{6}", "score": 0.9}]
            },
            {
                "entity_type": "CUSTOMER_ID",
                "patterns": [{"name": "customer", "regex": "CUS-\\d{6}", "score": 0.9}]
            }
        ]
    }
).json()

Pattern 4: Error Handling#

Robust error handling:

def safe_analyze(text: str) -> dict | None:
    try:
        response = requests.post(
            f"{BASE_URL}/presidio/analyze",
            headers={"Authorization": f"Bearer {API_KEY}"},
            json={"text": text},
            timeout=30
        )

        if response.status_code == 401:
            raise ValueError("Invalid API key")
        elif response.status_code == 402:
            raise ValueError("Insufficient tokens")
        elif response.status_code == 429:
            retry_after = response.headers.get("Retry-After", 60)
            raise ValueError(f"Rate limited. Retry after {retry_after}s")

        response.raise_for_status()
        return response.json()

    except requests.exceptions.Timeout:
        print("Request timed out")
        return None
    except requests.exceptions.RequestException as e:
        print(f"Request failed: {e}")
        return None

Next Steps#

Now that you have the basics working:

  1. SDK Reference - Official JavaScript & Python SDKs with client-side encryption
  2. API Reference - Complete endpoint documentation
  3. Entity Inventory - Browse 390+ entity types
  4. Presets - Use regional presets
  5. MCP Integration - Integrate with AI tools
  6. Structured Data - Process CSV/JSON files

Environment Variables#

For production, use environment variables:

# .env
CLOAK_API_KEY=cb_your_api_key_here
CLOAK_API_URL=https://cloak.business/api
import os

API_KEY = os.environ.get("CLOAK_API_KEY")
BASE_URL = os.environ.get("CLOAK_API_URL", "https://cloak.business/api")

Document maintained by cloak.business