Overview
The CanaryGuard REST API v1 lets you programmatically create and manage canary tokens, retrieve alerts, and integrate with your security tooling. All endpoints are served over HTTPS at:
https://canaryguard.app/api/v1Responses use JSON. All timestamps are in ISO 8601 format (UTC). Pagination is available on list endpoints.
Authentication
All API requests (except the health check) require a Bearer token in the Authorization header. Generate API keys in your dashboard at /settings/api-keys.
Key Format
API keys use the prefix cg_live_ followed by 40 hexadecimal characters:
cg_live_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2Usage
Authorization: Bearer cg_live_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2Error Responses
Authentication failures return 401 Unauthorized:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing, invalid, or expired API key."
}
}Pagination
List endpoints support pagination via page and limit query parameters. The maximum value for limit is 100. Defaults are page=1 and limit=50.
GET /api/v1/tokens?page=2&limit=25Paginated responses include a meta object:
{
"data": [...],
"meta": {
"page": 2,
"limit": 25,
"total": 73
}
}Endpoints
/api/v1/healthNo authHealth check endpoint. Returns the current status and API version. No authentication required.
{
"data": {
"status": "ok",
"version": "1.0.0"
}
}/api/v1/tokensList all tokens for the authenticated account. Supports pagination and filtering.
Query Parameters
| Param | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Items per page (max: 100, default: 50) |
type | string | Filter by token type: http, dns, image, email, document_docx, document_pdf, qr_code |
status | string | Filter by status: active, expired |
curl -H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/tokens?page=1&limit=50&type=http"{
"data": [
{
"id": "tok_8f3a1b2c",
"type": "http",
"name": "prod-server-config",
"memo": "Monitors access to production config file",
"status": "active",
"token_url": "https://svccdns.com/t/tok_8f3a1b2c",
"created_at": "2026-03-15T10:30:00Z",
"updated_at": "2026-03-15T10:30:00Z"
}
],
"meta": {
"page": 1,
"limit": 50,
"total": 12
}
}/api/v1/tokensCreate a new canary token. Returns the created token object with its unique URL.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | One of: http, dns, image, email, document_docx, document_pdf, qr_code, env_config, crypto_eth, crypto_sol, crypto_seed |
name | string | Yes | Human-readable name for the token (max 100 chars) |
memo | string | No | Optional note about the token's purpose (max 500 chars) |
curl -X POST \
-H "Authorization: Bearer cg_live_xxx" \
-H "Content-Type: application/json" \
-d '{"type":"http","name":"my-token","memo":"Monitoring staging DB credentials"}' \
"https://canaryguard.app/api/v1/tokens"{
"data": {
"id": "tok_9d4e2f3a",
"type": "http",
"name": "my-token",
"memo": "Monitoring staging DB credentials",
"status": "active",
"token_url": "https://svccdns.com/t/tok_9d4e2f3a",
"created_at": "2026-03-28T14:00:00Z",
"updated_at": "2026-03-28T14:00:00Z"
}
}Crypto Wallet Tokens (crypto_eth, crypto_sol, crypto_seed)
Crypto tokens generate real key material on-chain. The response includes a one-time private_key field that is returned only on creation — it is never persisted and cannot be retrieved again. For crypto_seed, the private_key field carries a 12-word BIP39 mnemonic instead of a hex / base58 private key. Store it exactly like a real secret.
For crypto_eth and crypto_sol, the config.address field contains the single decoy wallet address. For crypto_seed, the config.addresses array contains the 5 derived wallets (3 ETH at the MetaMask default path, 2 SOL at the Phantom default path) — every one of them is monitored, and an on-chain tx on any of them triggers a single alert tagged with the matched address and BIP32/SLIP-10 path. Crypto tokens require the Team plan or higher.
curl -X POST \
-H "Authorization: Bearer cg_live_xxx" \
-H "Content-Type: application/json" \
-d '{"type":"crypto_eth","name":"eth-decoy-wallet-1","memo":"planted in dev seed backup"}' \
"https://canaryguard.app/api/v1/tokens"{
"data": {
"id": "tok_a1b2c3d4",
"type": "crypto_eth",
"name": "eth-decoy-wallet-1",
"status": "active",
"token_url": "0xabc1234567890abcdef1234567890abcdef12345",
"private_key": "0xfeed...beef",
"created_at": "2026-04-24T12:00:00Z",
"updated_at": "2026-04-24T12:00:00Z"
}
}{
"data": {
"id": "tok_e5f6g7h8",
"type": "crypto_sol",
"name": "sol-decoy-wallet-1",
"status": "active",
"token_url": "9xT3kP2mN4rV5qL6aB7cD8eF9gH1iJ2kL3mN4oP5qR6s",
"private_key": "5K...base58EncodedSecretKey...",
"created_at": "2026-04-24T12:00:00Z",
"updated_at": "2026-04-24T12:00:00Z"
}
}curl -X POST \
-H "Authorization: Bearer cg_live_xxx" \
-H "Content-Type: application/json" \
-d '{"type":"crypto_seed","name":"treasury-recovery-2026"}' \
"https://canaryguard.app/api/v1/tokens"{
"data": {
"id": "tok_seed1234",
"type": "crypto_seed",
"name": "treasury-recovery-2026",
"status": "active",
"private_key": "abandon abandon abandon ... about",
"config": {
"addresses": [
{ "chain": "eth", "path": "m/44'/60'/0'/0/0", "address": "0x9858..." },
{ "chain": "eth", "path": "m/44'/60'/0'/0/1", "address": "0x6Fac..." },
{ "chain": "eth", "path": "m/44'/60'/0'/0/2", "address": "0x1A9b..." },
{ "chain": "sol", "path": "m/44'/501'/0'/0'", "address": "5jH3..." },
{ "chain": "sol", "path": "m/44'/501'/1'/0'", "address": "DRoo..." }
]
},
"created_at": "2026-04-30T12:00:00Z",
"updated_at": "2026-04-30T12:00:00Z"
}
}crypto_seed, the private_key field carries the 12-word BIP39 mnemonic. The 5 addresses in config.addresses are derived using the standard MetaMask (ETH) and Phantom (SOL) default paths — any wallet importing the same mnemonic will derive the same 5 addresses, so an attacker who finds the phrase and imports it will trigger an alert on the first transaction from any of them. Alerts include matched_address and derivation_path in their metadata so you can tell which of the 5 wallets fired.private_key field is present only in the POST response. Subsequent GET/list calls never return it. If you lose the key, delete the token and create a new one./api/v1/tokens/:idRetrieve a single token by its ID. Returns the full token object.
curl -H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/tokens/tok_9d4e2f3a"{
"data": {
"id": "tok_9d4e2f3a",
"type": "http",
"name": "my-token",
"memo": "Monitoring staging DB credentials",
"status": "active",
"token_url": "https://svccdns.com/t/tok_9d4e2f3a",
"alert_count": 3,
"last_triggered_at": "2026-03-27T08:15:42Z",
"created_at": "2026-03-28T14:00:00Z",
"updated_at": "2026-03-28T14:00:00Z"
}
}/api/v1/tokens/:idSoft-delete a token. Sets the token status to expired and deactivates it. The token and its alert history are retained for your records.
curl -X DELETE \
-H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/tokens/tok_9d4e2f3a"{
"data": {
"id": "tok_9d4e2f3a",
"status": "expired",
"deleted_at": "2026-03-28T16:00:00Z"
}
}/api/v1/tokens/:idUpdate a token's status. Currently supports toggling between active and paused.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | New status: active or paused |
curl -X PATCH \
-H "Authorization: Bearer cg_live_xxx" \
-H "Content-Type: application/json" \
-d '{"status":"paused"}' \
"https://canaryguard.app/api/v1/tokens/tok_9d4e2f3a"{
"data": {
"id": "tok_9d4e2f3a",
"type": "http",
"name": "my-token",
"memo": "Monitoring staging DB credentials",
"status": "paused",
"token_url": "https://svccdns.com/t/tok_9d4e2f3a",
"created_at": "2026-03-28T14:00:00Z",
"updated_at": "2026-04-10T09:30:00Z"
}
}/api/v1/tokens/:id/cloneClone an existing token. Creates a new token of the same type with a fresh callback ID. Optionally override the name and memo.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name for the cloned token |
memo | string | No | Optional memo (defaults to the original token's memo) |
curl -X POST \
-H "Authorization: Bearer cg_live_xxx" \
-H "Content-Type: application/json" \
-d '{"name":"prod-server-config-v2"}' \
"https://canaryguard.app/api/v1/tokens/tok_8f3a1b2c/clone"{
"data": {
"id": "tok_5e7f8a9b",
"type": "http",
"name": "prod-server-config-v2",
"memo": "Monitors access to production config file",
"status": "active",
"token_url": "https://svccdns.com/t/tok_5e7f8a9b",
"created_at": "2026-04-10T09:30:00Z",
"updated_at": "2026-04-10T09:30:00Z"
}
}/api/v1/tokens/batchBulk create up to 50 tokens in a single request. Each token in the array is created independently; partial failures are reported per-item.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
tokens | array | Yes | Array of token objects, each with type (required), name (required), and memo (optional). Maximum 50 items. |
curl -X POST \
-H "Authorization: Bearer cg_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"tokens": [
{"type": "http", "name": "honeypot-1"},
{"type": "dns", "name": "honeypot-2", "memo": "DNS decoy"},
{"type": "http", "name": "honeypot-3"}
]
}' \
"https://canaryguard.app/api/v1/tokens/batch"{
"data": [
{
"id": "tok_a1b2c3d4",
"type": "http",
"name": "honeypot-1",
"status": "active",
"token_url": "https://svccdns.com/t/tok_a1b2c3d4",
"created_at": "2026-04-10T09:30:00Z",
"updated_at": "2026-04-10T09:30:00Z"
},
{
"id": "tok_e5f6a7b8",
"type": "dns",
"name": "honeypot-2",
"memo": "DNS decoy",
"status": "active",
"created_at": "2026-04-10T09:30:00Z",
"updated_at": "2026-04-10T09:30:00Z"
},
{
"id": "tok_c9d0e1f2",
"type": "http",
"name": "honeypot-3",
"status": "active",
"token_url": "https://svccdns.com/t/tok_c9d0e1f2",
"created_at": "2026-04-10T09:30:00Z",
"updated_at": "2026-04-10T09:30:00Z"
}
],
"meta": {
"created": 3,
"failed": 0
}
}/api/v1/tokens/:id/alertsList alerts for a specific token. Supports pagination and date range filtering.
Query Parameters
| Param | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Items per page (max: 100, default: 50) |
after | string | ISO 8601 date. Only return alerts after this timestamp. |
before | string | ISO 8601 date. Only return alerts before this timestamp. |
curl -H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/tokens/tok_8f3a1b2c/alerts?page=1&limit=10&after=2026-03-01T00:00:00Z"{
"data": [
{
"id": "alt_7c2b1a9e",
"token_id": "tok_8f3a1b2c",
"triggered_at": "2026-03-27T08:15:42Z",
"source_ip": "203.0.113.42",
"geo": {
"city": "Berlin",
"region": "Berlin",
"country": "DE"
},
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
}
],
"meta": {
"page": 1,
"limit": 10,
"total": 3
}
}/api/v1/alertsList alerts across all tokens. Supports pagination and filtering by token, date range.
Query Parameters
| Param | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Items per page (max: 100, default: 50) |
token_id | string | Filter alerts by a specific token ID |
after | string | ISO 8601 date. Only return alerts after this timestamp. |
before | string | ISO 8601 date. Only return alerts before this timestamp. |
curl -H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/alerts?token_id=tok_8f3a1b2c&after=2026-03-01T00:00:00Z&limit=10"{
"data": [
{
"id": "alt_7c2b1a9e",
"token_id": "tok_8f3a1b2c",
"token_name": "prod-server-config",
"token_type": "http",
"triggered_at": "2026-03-27T08:15:42Z",
"source_ip": "203.0.113.42",
"geo": {
"city": "Berlin",
"region": "Berlin",
"country": "DE",
"lat": 52.52,
"lon": 13.405
},
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
"headers": {
"referer": "https://example.com/internal"
}
}
],
"meta": {
"page": 1,
"limit": 10,
"total": 3
}
}/api/v1/alerts/:id/reviewedMark an alert as reviewed. This is useful for triaging alerts and tracking which have been investigated.
curl -X POST \
-H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/alerts/alt_7c2b1a9e/reviewed"{
"data": {
"id": "alt_7c2b1a9e",
"reviewed": true
}
}/api/v1/billingGet the current plan, token usage, and credits balance for your account.
curl -H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/billing"{
"data": {
"plan": "pro",
"planName": "Pro",
"tokenLimit": 100,
"tokensUsed": 42,
"creditsBalance": 850,
"customDomain": "canary.example.com",
"customDomainVerified": true
}
}/api/v1/statsGet aggregated statistics for your account including token counts, alert counts, and top triggered tokens.
curl -H "Authorization: Bearer cg_live_xxx" \
"https://canaryguard.app/api/v1/stats"{
"data": {
"totalTokens": 42,
"activeTokens": 38,
"totalAlerts": 156,
"alertsToday": 3,
"topTriggeredTokens": [
{
"id": "tok_8f3a1b2c",
"name": "prod-server-config",
"type": "http",
"triggerCount": 47
},
{
"id": "tok_2d3e4f5a",
"name": "staging-env-decoy",
"type": "env_config",
"triggerCount": 31
}
]
}
}Error Codes
The API uses standard HTTP status codes. Error responses include a JSON body with error.code and error.message fields.
| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid request body or query parameters. |
| 401 | UNAUTHORIZED | Missing, invalid, or expired API key. |
| 403 | FORBIDDEN | API key does not have permission for this action. |
| 404 | NOT_FOUND | Resource not found or does not belong to your account. |
| 422 | VALIDATION_ERROR | Request body failed validation (details in response). |
| 429 | RATE_LIMITED | Too many requests. Check Retry-After header. |
| 500 | INTERNAL_ERROR | Unexpected server error. Contact support if persistent. |
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid token type. Must be one of: http, dns, image, email, document_docx, document_pdf, qr_code, env_config, crypto_eth, crypto_sol, crypto_seed."
}
}Quick Start
Get up and running in 3 steps with your free account (5 tokens included):
1. Create an API key
Go to Settings → API Keys and generate a new key. Copy it immediately — it's shown only once.
2. Create your first token
curl -X POST https://www.canaryguard.app/api/v1/tokens \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "http", "name": "test-api-token"}'3. Check your tokens
curl https://www.canaryguard.app/api/v1/tokens \
-H "Authorization: Bearer YOUR_API_KEY"Postman Collection
Import our pre-built Postman collection to explore all API endpoints with example requests and responses.
Setup
- Import the JSON file into Postman (File → Import)
- Go to the collection variables tab
- Set api_key to your actual API key (from /settings/api-keys)
- base_url is pre-configured to https://www.canaryguard.app
- Start sending requests — all 13 endpoints are ready to use
Need Help?
If you have questions or need assistance integrating with the CanaryGuard API, contact us at support@canaryguard.app.