Developers
API quickstart
In about 15 minutes you will create a sandbox key, register a product and batch, generate codes, download them and verify one, with curl or the TypeScript SDK.
Before you start
You need a CredChek company account that CredChek has approved. Code generation and API key creation open after approval. The manufacturer onboarding guide covers signup and approval.
1. Create a sandbox API key
The sandbox is a separate environment with its own accounts and data. Sign in to the sandbox company portal ([[SANDBOX PORTAL URL]]), go to Settings → API keys and select Create API key. Give it a name, select the Packaging line (codes) preset, also tick products:write (this guide creates a product), then select Create key. Sandbox keys start with cc_test_. Copy the key now: it is shown only once.
Keep it in an environment variable on your server, never in source code:
export CREDCHECK_API_KEY="cc_test_..."2. Register a product
curl -X POST https://api.sandbox.credchek.com/v1/products \
-H "X-Api-Key: $CREDCHECK_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Paracetamol 500mg", "sku": "PARA-500", "category": "pharmaceuticals" }'The response is the created product. Keep its id.
3. Add a batch
Codes are always generated for a batch (a production run).
curl -X POST https://api.sandbox.credchek.com/v1/products/PRODUCT_ID/batches \
-H "X-Api-Key: $CREDCHECK_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "batchNumber": "B2026-001", "quantity": 1000, "expiryDate": "2028-12-31" }'Use a future expiry date
A batch whose expiry date has passed verifies as expired, not authentic.
4. Generate codes
Generation runs as a background job. Always send an idempotencyKey so a retried request can never create a second job (see Idempotency).
curl -X POST https://api.sandbox.credchek.com/v1/codes/generate \
-H "X-Api-Key: $CREDCHECK_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "batchId": "BATCH_ID", "quantity": 1000, "codeType": "qr", "idempotencyKey": "B2026-001-run-1" }'The API answers 202 with { "jobId": "…", "status": "queued" }. Poll the job until status is completed:
curl https://api.sandbox.credchek.com/v1/codes/jobs/JOB_ID -H "X-Api-Key: $CREDCHECK_API_KEY"5. Download the codes
The deliverable is a CSV with serial and qr_url columns. It can be downloaded once, needs the codes:export scope, and expires after 30 days. Save it straight to secure storage for your printer.
curl https://api.sandbox.credchek.com/v1/codes/jobs/JOB_ID/download \
-H "X-Api-Key: $CREDCHECK_API_KEY" -o codes.csv6. Verify a code
Verification is public and needs no key. Use a serial from the CSV, or the full qr_url:
curl -X POST https://api.sandbox.credchek.com/v1/verify \
-H "Content-Type: application/json" \
-d '{ "code": "SERIAL_FROM_CSV", "channel": "api" }'A new code for an approved company returns "outcome": "verified" with a referenceId. Verification always answers 200 for a well-formed request: an unknown code is suspected_counterfeit, not an error.
The same flow with the SDK
import { writeFile } from 'node:fs/promises';
import { CredCheck } from '@credcheck/sdk';
const cc = new CredCheck({
apiKey: process.env.CREDCHECK_API_KEY,
baseUrl: 'https://api.sandbox.credchek.com',
});
const product = await cc.products.create({
name: 'Paracetamol 500mg',
sku: 'PARA-500',
category: 'pharmaceuticals',
});
const batch = await cc.products.createBatch(product.id, {
batchNumber: 'B2026-001',
quantity: 1000,
expiryDate: '2028-12-31',
});
const { jobId } = await cc.codes.generate({
batchId: batch.id,
quantity: 1000,
codeType: 'qr',
idempotencyKey: 'B2026-001-run-1',
});
await cc.codes.jobs.waitForCompletion(jobId);
const csv = await cc.codes.jobs.download(jobId); // one-time download
await writeFile('codes.csv', csv, { mode: 0o600 });
const serial = csv.split('\n')[1]?.split(',')[0] ?? '';
const result = await cc.verify.check({ code: serial });
console.log(result.outcome, result.referenceId);