Documentation▾
API Integration Reference
The Merlonix API is a REST API over HTTPS. It enables agencies to automate asset provisioning, trigger checks, create attestations, and pull monitoring data into external tools — project management systems, reporting dashboards, client portals.
Base URL
https://api.merlonix.com/v1
All endpoints require authentication.
Authentication
The API uses Bearer token authentication. Include your JWT in every request:
Authorization: Bearer <your-token>
Obtaining a token: Navigate to Settings → API in the Merlonix app to generate an API token. Tokens are scoped to your tenant and inherit the permissions of the user who created them.
Token expiry: API tokens are long-lived by default. Rotate them from Settings → API if you suspect a token has been compromised.
Request and response format
- All request bodies are JSON (
Content-Type: application/json) - All responses are JSON
- Timestamps are ISO 8601 UTC:
2026-04-30T09:14:00Z
Error format
{
"error": "bad_request",
"message": "hostname is required",
"issues": [
{ "path": "hostname", "issue": "Required" }
]
}
Common status codes:
| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
400 | Validation error (see issues) |
401 | Missing or invalid token |
403 | Authenticated but not authorised |
404 | Resource not found or not in your tenant |
429 | Rate limit exceeded |
Pagination
List endpoints return paginated results.
Request parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Max records per page (1–100) |
offset | integer | 0 | Records to skip |
Response shape:
{
"data": [...],
"total": 142,
"limit": 50,
"offset": 0
}
Assets
Assets are the core monitoring unit: a hostname or IP address that Merlonix monitors for SSL and DNS health.
List assets
GET /v1/assets
Query parameters: limit, offset
Response:
{
"data": [
{
"id": "uuid",
"label": "Client A — main site",
"hostname": "clienta.com",
"check_interval_minutes": 60,
"ssl_monitoring": true,
"dns_monitoring": true,
"created_at": "2026-01-15T10:00:00Z"
}
],
"total": 12,
"limit": 50,
"offset": 0
}
Create an asset
POST /v1/assets
Request body:
{
"label": "Client A — main site",
"hostname": "clienta.com",
"check_interval_minutes": 60,
"ssl_monitoring": true,
"dns_monitoring": true
}
| Field | Type | Required | Notes |
|---|---|---|---|
label | string | Yes | Human-readable name |
hostname | string | Yes | Domain or IP to monitor |
check_interval_minutes | integer | No | 5, 15, 30, or 60 (default: 60) |
ssl_monitoring | boolean | No | Default: true |
dns_monitoring | boolean | No | Default: true |
Response: 201 Created with the created asset object.
Asset limits: Asset creation fails if your plan's asset limit is reached. Check GET /v1/customers/me for asset_limit and current usage.
Get an asset
GET /v1/assets/:id
Returns a single asset with the same shape as the list response, plus the latest check summary.
Update an asset
PATCH /v1/assets/:id
All fields are optional. Omitted fields are unchanged.
{
"label": "Client A — shop (updated)",
"check_interval_minutes": 5
}
Delete an asset
DELETE /v1/assets/:id
Deletes the asset and all associated check history. This is irreversible.
Response: 200 OK with { "deleted": true }.
Trigger an immediate check
POST /v1/assets/:id/check-now
Enqueues an out-of-cycle check for the asset. The check runs within 60 seconds.
Response: 200 OK with a trace ID you can use to correlate the check result in GET /v1/checks.
Attestations
Attestations are tamper-evident certificates tied to an asset. See Attestation Deep Dive for a full explanation of verification methods and certificate contents.
List attestations
GET /v1/attestations
Query parameters: limit, offset, asset_id (optional filter)
Create an attestation
POST /v1/attestations
{
"asset_id": "uuid",
"statement": "Logo pack v3 — approved by client on 2026-04-29",
"method": "inline"
}
| Field | Type | Required | Notes |
|---|---|---|---|
asset_id | uuid | Yes | Asset to attest |
statement | string | Yes | Description of what is being certified |
method | string | Yes | inline, dns_txt, or http_file |
For dns_txt and http_file methods, the response includes a challenge object:
{
"id": "uuid",
"status": "pending",
"challenge": {
"method": "dns_txt",
"hostname": "_merlonix-verify.clienta.com",
"record_type": "TXT",
"token": "merlonix-verify=abc123xyz"
}
}
Place the challenge in DNS or serve the file, then call POST /v1/attestations/:id/verify to complete verification (or wait — Merlonix polls automatically every 30 seconds for up to 10 minutes).
Get an attestation
GET /v1/attestations/:id
Returns the full certificate including verification status, state hash, and the public verification URL.
Revoke an attestation
POST /v1/attestations/:id/revoke
{
"reason": "Superseded by v4 delivery"
}
The reason is optional but displayed on the public verification URL and logged in the audit trail.
Checks
Checks are the time-series record of SSL and DNS monitoring results for each asset.
List check history
GET /v1/checks?asset_id=<uuid>
Query parameters:
| Parameter | Type | Notes |
|---|---|---|
asset_id | uuid | Required |
check_type | string | ssl or dns (optional filter) |
limit | integer | Default 50, max 100 |
offset | integer | Default 0 |
Response:
{
"data": [
{
"id": "uuid",
"asset_id": "uuid",
"check_type": "ssl",
"classifier": "expiring_soon",
"severity": "warning",
"detail": { "days_remaining": 22, "issuer": "Let's Encrypt" },
"checked_at": "2026-04-30T09:00:00Z"
}
]
}
Get latest check per asset
GET /v1/checks/latest?asset_id=<uuid>
Returns the most recent SSL check result and the most recent DNS check result for the asset. Useful for dashboard-style status polling.
Alert channels
Channels define where Merlonix sends notifications. See Alert Channels for the full reference on severity filters and routing.
List channels
GET /v1/channels
Create a channel
POST /v1/channels
Direct channels receive severity-matching alerts across the workspace, not just one client's assets. Use internal agency recipients. A channel name or critical-only filter does not restrict client scope.
{
"kind": "slack_webhook",
"name": "Internal monitoring",
"target": "https://hooks.slack.com/services/REPLACE_WITH_YOUR_WEBHOOK",
"severity_filter": ["warning", "critical"]
}
| Field | Type | Notes |
|---|---|---|
kind | string | Channel kind; examples include email, slack_webhook, and generic_webhook (custom webhook) |
name | string | Internal display name, 1–100 characters; does not filter clients |
target | string | Recipient email for email, or an HTTPS webhook URL for slack_webhook/generic_webhook |
severity_filter | string array | Explicit levels to deliver: info, warning, critical; defaults to all three |
Channel kinds and counts remain subject to plan entitlements. For custom webhook delivery, use kind: "generic_webhook". Store the generated signing secret securely when it is returned.
For client-specific forwarding, follow Client-specific delivery: verify signatures, allowlist stable asset IDs and their approved recipients, and drop unknown or missing IDs. This is receiver logic you maintain, not native client isolation.
Update a channel
PATCH /v1/channels/:id
Accepts name, target, is_active, and severity_filter. Omitted fields are unchanged; kind cannot be changed.
Delete a channel
DELETE /v1/channels/:id
Account
Get account details
GET /v1/customers/me
Returns tenant details including plan, asset count, asset limit, and current stack tags.
{
"id": "uuid",
"name": "Your Agency",
"billing_email": "billing@youragency.com",
"plan": "starter",
"asset_count": 12,
"asset_limit": 25,
"stack_tags": ["payments.checkout", "network.cdn"],
"trial_ends_at": null,
"created_at": "2026-01-01T00:00:00Z"
}
Update account details
PATCH /v1/customers/me
{
"name": "Your Agency",
"billing_email": "new-billing@youragency.com",
"timezone": "America/New_York",
"stack_tags": ["payments.checkout", "payments.webhooks", "network.cdn"]
}
All fields are optional. stack_tags is a full replacement — send the complete list you want active. See Vendor Stack Tags for the full tag catalog.
Automation patterns
Prefer no code? See Automate with Zapier, Make & n8n to send monitoring events to 6,000+ apps in real time with signed webhooks — no scripts required.
Provisioning a client on signup
This example assumes api.post returns the parsed JSON response and clientId identifies an existing client in your workspace. Provision assets per client, but configure direct alert recipients for your internal team. Reuse an existing internal channel when possible instead of creating duplicates for each client.
// 1. Create an asset for an existing client
const { asset } = await api.post('/v1/assets', {
label: `${clientName} — main site`,
hostname: clientDomain,
asset_type: 'domain',
client_id: clientId,
check_interval_sec: 3600,
});
// 2. Trigger the first check immediately
await api.post(`/v1/assets/${asset.id}/check-now`);
// 3. If needed, create a workspace-wide channel for the internal agency team
// Critical severity filters urgency, not which client's alerts are delivered.
await api.post('/v1/channels', {
kind: 'email',
name: 'Internal critical alerts',
target: agencyAlertsEmail,
severity_filter: ['critical'],
});
Recipient scope: Creating the asset above does not scope this channel to that client. Do not use a client contact as the direct recipient in a multi-client workspace. For external forwarding, use the signature-verified asset-ID allowlist described in Client-specific delivery. Reject unknown and missing asset IDs.
Pulling check data into a report
// Get the latest check for every asset
const assets = await api.get('/v1/assets?limit=100');
const statuses = await Promise.all(
assets.data.map(a => api.get(`/v1/checks/latest?asset_id=${a.id}`))
);
// statuses[i] has ssl and dns check results for assets.data[i]
Creating an attestation on deliverable approval
const cert = await api.post('/v1/attestations', {
asset_id: assetId,
statement: `${deliverableName} — approved by ${clientName} on ${date}`,
method: 'inline',
});
// cert.verification_url is the shareable public link
await sendDeliverableEmail({ ...deliverable, certificateUrl: cert.verification_url });
Rate limits
The API applies per-tenant rate limits:
| Tier | Requests per minute |
|---|---|
| Starter | 60 |
| Agency | 300 |
When a limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating when the limit resets.
Next: return to Getting Started or read Vendor Stack Tags to configure which vendor incidents appear in your monitoring data.