@expunct/sdk
v0.1.1
Published
Node.js SDK for the Expunct PII redaction API
Downloads
28
Readme
@expunct/sdk
Privacy infrastructure for modern applications. Detect and redact PII, secrets, and sensitive data before it reaches AI, logs, or external APIs.
Installation
npm install @expunct/sdk
# or
yarn add @expunct/sdkGet your API key at expunct.ai — free tier includes 1M tokens/month, no credit card required.
Quick Start
import { Expunct } from "@expunct/sdk";
const client = new Expunct({ apiKey: "your-api-key" });
const redacted = await client.sanitizeText(
"Hi, I'm Jane Doe. Reach me at [email protected] or (555) 867-5309."
);
console.log(redacted);
// Output: Hi, I'm PERSON_1. Reach me at EMAIL_ADDRESS_1 or PHONE_NUMBER_1.Usage
Text redaction
sanitizeText is the simplest path: pass a string, get back a redacted string. It handles file upload, job polling, and result download automatically.
import { Expunct } from "@expunct/sdk";
const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });
const result = await client.sanitizeText(
"SSN: 123-45-6789, card: 4111 1111 1111 1111"
);
console.log(result);
// SSN: US_SSN_1, card: CREDIT_CARD_1File redaction
sanitizeFile accepts a Blob or Node.js Buffer and returns the redacted content as raw bytes. Useful for PDFs, DOCX files, or any binary format supported by the API.
import { Expunct } from "@expunct/sdk";
import { readFileSync, writeFileSync } from "fs";
const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });
const inputBuffer = readFileSync("./document.pdf");
const redactedBytes = await client.sanitizeFile(inputBuffer, {
filename: "document.pdf",
});
writeFileSync("./document-redacted.pdf", redactedBytes);URI redaction
sanitizeUri submits a remote file by URI (e.g. a signed S3 URL), polls until the job completes, and returns the full JobDetailResponse including all detected findings.
import { Expunct } from "@expunct/sdk";
const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });
const job = await client.sanitizeUri(
"https://my-bucket.s3.amazonaws.com/sensitive-report.txt?..."
);
console.log(`Found ${job.findings_count} PII entities`);
console.log(job.findings);
// [{ entity_type: "EMAIL_ADDRESS", entity_value: "[email protected]", confidence: 0.99 }, ...]Batch URI redaction
Submit multiple URIs in one call. Returns a BatchJobResponse with individual job IDs you can track separately.
import { Expunct } from "@expunct/sdk";
const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });
const batch = await client.redact.batch([
"s3://bucket/file1.txt",
"s3://bucket/file2.txt",
"s3://bucket/file3.txt",
]);
console.log(`Batch ${batch.id}: ${batch.total_jobs} jobs submitted`);
// Poll individual jobs via batch.job_idsEnvironment variable
If EXPUNCT_API_KEY is set in your environment, you can pass it directly:
const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });Custom redaction config
Pass a config object to any sanitize* method to control which entity types to detect and how to redact them:
const result = await client.sanitizeText(
"Dr. Smith at UCSF called: (415) 555-0100",
{
config: {
pii_types: ["PERSON", "PHONE_NUMBER"],
redaction_method: "replace", // "replace" | "mask" | "hash"
confidence_threshold: 0.7,
preserve_labels: true,
},
}
);Custom policy
Policies let you save and reuse redaction configurations. Create a policy once and reference it by ID:
// Create a policy
const policy = await client.policies.create({
name: "strict-hipaa",
pii_types: ["PERSON", "EMAIL_ADDRESS", "PHONE_NUMBER", "US_SSN", "DATE_TIME"],
redaction_method: "replace",
confidence_threshold: 0.6,
is_default: false,
});
// Use the policy by ID in redaction calls
const result = await client.sanitizeText(
"Patient John Doe, DOB 01/15/1980, SSN 123-45-6789",
{ policy_id: policy.id }
);Manual job control
For fine-grained control, use the redact and jobs resources directly:
import { Expunct } from "@expunct/sdk";
const client = new Expunct({ apiKey: process.env.EXPUNCT_API_KEY! });
// Submit a file upload job
const job = await client.redact.file(fileBlob, {
filename: "report.txt",
language: "en",
});
console.log(`Job ${job.id} submitted, status: ${job.status}`);
// Poll until complete
const completed = await client.waitForJob(job.id, {
interval: 1000, // poll every 1s
timeout: 60_000, // give up after 60s
});
// Download the redacted bytes
const bytes = await client.jobs.download(completed.id);
// Or get the full redaction report
const report = await client.jobs.report(completed.id);List and inspect jobs
// List recent jobs (paginated)
const { jobs, total } = await client.jobs.list({
page: 1,
page_size: 20,
status: "completed",
});
// Get a specific job
const job = await client.jobs.get("job-uuid-here");
console.log(job.findings);Audit logs
const logs = await client.audit.list({
event_type: "redact",
page: 1,
page_size: 50,
});API key management
// List all keys
const keys = await client.apiKeys.list();
// Create a new key
const newKey = await client.apiKeys.create({ name: "ci-pipeline" });
console.log(newKey.key); // plaintext — only shown once
// Revoke a key
await client.apiKeys.revoke(newKey.id);Error handling
All errors extend ApiError. Import the specific classes you need:
import {
Expunct,
AuthenticationError,
RateLimitError,
ValidationError,
NotFoundError,
PollingTimeoutError,
} from "@expunct/sdk";
try {
const result = await client.sanitizeText("...");
} catch (err) {
if (err instanceof AuthenticationError) {
console.error("Invalid API key");
} else if (err instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${err.retryAfter}s`);
} else if (err instanceof PollingTimeoutError) {
console.error(`Job ${err.jobId} timed out after ${err.timeout}ms`);
} else if (err instanceof ValidationError) {
console.error("Bad request:", err.message);
}
}Client configuration
const client = new Expunct({
apiKey: "your-api-key", // required
baseUrl: "https://api.expunct.ai", // optional, default shown
tenantId: "your-tenant-id", // optional, for multi-tenant setups
timeout: 30_000, // optional, request timeout in ms (default 30s)
maxRetries: 3, // optional, retries on network errors + 429s (default 3)
});Detected Entity Types
The following entity types are detected by default (and can be targeted individually via pii_types):
| Type | Description |
|------|-------------|
| PERSON | Full names |
| EMAIL_ADDRESS | Email addresses |
| PHONE_NUMBER | Phone numbers |
| LOCATION | Physical addresses, cities, countries |
| DATE_TIME | Dates and times |
| US_SSN | US Social Security numbers |
| CREDIT_CARD | Credit/debit card numbers |
| IP_ADDRESS | IPv4 and IPv6 addresses |
| URL | Web URLs |
| ORGANIZATION | Company and organization names |
| IBAN_CODE | International bank account numbers |
| US_PASSPORT | US passport numbers |
| US_DRIVER_LICENSE | US driver's license numbers |
| CRYPTO | Cryptocurrency wallet addresses |
| MEDICAL_LICENSE | Medical license numbers |
| NRP | Nationality, religion, political affiliation |
Redaction Methods
| Method | Description | Example |
|--------|-------------|---------|
| replace | Replace with labeled placeholder (default) | PERSON_1 |
| mask | Replace characters with * | **** |
| hash | Replace with a SHA-256 hash | a3f2c1... |
Requirements
- Node.js 18+
- Zero runtime dependencies
Links
License
MIT
