API reference
Read accounts, campaigns and daily insights through a small, authenticated HTTPS API.
Authentication and organization scope
Base URL: https://webdesiz.com/api/v1/developer
An organization OWNER or ADMIN creates a key in Settings → Developer keys. Select only the scopes you need and an expiry of 1–90 days. Each organization can have at most 10 active, unexpired keys. The full key appears once; store it in your operating system or application secret manager.
Send the key only in the Authorization header as Bearer. Its organization and issuer are bound on the server; clients cannot choose another organization. Each request checks expiry, revocation, current issuer membership and the required scope.
// Node.js 22; inject WEBDESIZ_API_KEY from your secret manager.
const key = process.env.WEBDESIZ_API_KEY;
if (!key) throw new Error('Missing credential');
const response = await fetch(
'https://webdesiz.com/api/v1/developer/accounts?limit=20',
{headers: {Authorization: 'Bearer ' + key}, redirect: 'error'}
);
if (!response.ok) throw new Error('HTTP ' + response.status);
const snapshot = await response.json();Do not place a key in a URL, command argument, source file, shared MCP configuration or chat. A panel session JWT is not a developer API key.
What this interface supports
| Operation | Developer API / MCP / CLI | Panel |
|---|---|---|
| Read stored accounts, campaigns and daily insights | Available with the matching read scope | Existing authorized workspace |
| Create, list or revoke developer keys | No developer-key endpoint | Signed-in OWNER / ADMIN settings |
| Change campaigns or budgets, trigger a sync, generate content, send messages | Not exposed by these three read interfaces | Separate panel features and permissions apply |
The three key-management routes use the signed-in panel session. They are not part of the public developer-key contract.
Read endpoints
| GET | Required scope | Returned rows |
|---|---|---|
/accounts | accounts:read | Stored ad account snapshots |
/campaigns | campaigns:read | Stored campaign snapshots |
/insights | insights:read | Daily account-level or campaign-level insight rows |
All three routes return JSON with Cache-Control: no-store. They read existing Webdesiz records and do not call Meta to refresh them. OpenAPI 3.1 JSON
Query parameters
| Parameter | Rule | Default / use |
|---|---|---|
limit | 1–100 | 50; all endpoints |
offset | 0–10000 | 0; all endpoints |
accountId | 1–128 letters, digits, underscore or hyphen | Optional Webdesiz account id from /accounts; all endpoints |
from | YYYY-MM-DD | Insights only; UTC today minus 29 days |
to | YYYY-MM-DD | Insights only; UTC today |
The insight range includes both endpoints and must contain valid dates, from ≤ to, at most 90 days and no future end date. Dates filter stored daily rows. Unknown query fields are rejected; do not send organization IDs, URLs or credentials in query parameters. from/to do not filter accounts or campaigns.
Response fields
Successful responses contain data (an array) and meta. An empty data array is a valid result. The following envelope is illustrative, not customer data:
{
"data": [],
"meta": {
"source": "stored_snapshot",
"liveMetaRequest": false,
"limit": 50,
"offset": 0,
"nextOffset": null,
"returned": 0,
"generatedAt": "2026-10-04T00:00:00.000Z",
"dataAsOf": "Each row reports its own lastSyncAt or syncedAt; this request does not refresh data.",
"note": "Stored values may be stale. Account-level and campaign-level insight rows are different aggregation levels; do not sum them together. Currency is per account."
}
}| Resource | Fields |
|---|---|
| Account | id, accountName, currency, timezone, isActive, lastSyncAt |
| Campaign | id, metaAdAccountId, name, objective, status, effectiveStatus, dailyBudget, lifetimeBudget, syncedAt, account.currency, account.timezone |
| Insight | id, metaAdAccountId, campaignId, date, spend, impressions, reach, clicks, ctr, cpc, cpm, attributionWindow, syncedAt, account.currency, account.timezone, purchases, purchaseValue, roas, purchaseMeasurement |
Stored decimal money and ratio fields such as spend, dailyBudget, ctr and cpc are JSON strings; purchases, purchaseValue and roas are numbers or null. Retain each account’s currency when combining results. Raw provider payloads and account access tokens are not returned.
Pagination
Start with offset=0. When meta.nextOffset is a number, use it with the same filters for the next page. Stop when it is null. A full final page can point to a subsequent empty page. Accounts and campaigns are sorted by id; insights by date descending, then id ascending. Offset is capped at 10000; this is not an unlimited export or a transactionally frozen dataset.
Freshness and measurement
generatedAt describes when the response was built, not when Meta data was refreshed. Read lastSyncAt for accounts and syncedAt for campaigns and insights. Null or old timestamps do not prove fresh data. No freshness SLA is implied.
campaignId=null denotes account-level rows; a campaignId denotes campaign-level rows. These aggregation levels can overlap: do not sum both into one total. Purchase metrics require stored purchase action evidence. Missing evidence produces null, not zero; an explicitly reported zero remains zero. purchaseMeasurement is reported_purchase_value, reported_purchase_count or unavailable. ROAS is purchaseValue/spend only when value is available and spend is positive; otherwise null.
Errors and request limits
| HTTP | Meaning / action |
|---|---|
| 400 | Invalid or unknown fields, pagination or date range; correct the request. |
| 401 | Missing, malformed, expired or revoked key; obtain a valid key. |
| 403 | Scope missing or issuer is no longer OWNER/ADMIN; review access. |
| 404 | Requested account is unavailable in the key’s organization. |
| 429 | Rate limit reached; wait 60 seconds before retrying. |
| 503 | Protection service unavailable; access is closed until recovery. |
Read limits: 60 requests/minute/key, 120/minute/organization and 180/minute/IP, using shared 60-second windows. Invalid authentication also consumes the IP limit. Error responses provide statusCode, error, message, path and timestamp; the developer path and message are deliberately generic. Do not depend on detailed validation text.