Visibility and intelligence
Snapshot, source, competitor, Google Search, campaign-cycle, and agent knowledge-base API reference.
All supported methods below accept Authorization: Bearer $LOUDMINK_API_KEY and use the product attached to that key. Examples use Bash with your own key in the environment and synthetic data. See Authentication for shared errors.
Some GET requests below perform background synchronization, classification, or stuck-cycle recovery. Do not treat every read in this group as a side-effect-free health check.
GET /api/snapshots
Returns query-distribution snapshots for charting. Optional days defaults to 7, is parsed as a base-10 integer, and is clamped to 1–90. Send a valid integer; malformed values do not have a dedicated 400 validation response.
curl 'https://loudmink.ai/api/snapshots?days=30' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns 200 with a bare array, not a snapshots wrapper, and Cache-Control: no-store. For each date, entries include:
date(YYYY-MM-DD, server-local calendar),totalQueries,citedCount,mentionedCount,notVisibleCount,pendingCount.CitedCountandMentionedCountfor each prefixperplexity,chatgpt,grok,gemini, andclaude.
Dates cover today and the preceding days - 1 days in ascending order. Missing dates carry forward the latest snapshot found inside the requested window. Before the first snapshot in that window, all counts are zero. These filled points are response-only; the GET does not write snapshots. Locked-engine counts are zeroed, but stored aggregate counts are not recalculated on read. Citation and mention counts can overlap; do not sum them as mutually exclusive categories.
Unexpected failures return 500 with { error: "Failed to fetch snapshots" }.
POST /api/snapshots is not supported with an API key. Use the platform to manage snapshots.
GET /api/dashboard/competitors
Read the latest competitor snapshot. No parameters or body. Returns at most ten competitors plus the product's own row, sorted together by descending visibilityPct.
curl 'https://loudmink.ai/api/dashboard/competitors' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns { date, totalQueries, competitors }. Competitor entries contain name, domain, visibilityPct, avgPosition, and isYou. The product's own entry is named You. domain and avgPosition may be null. The route reads saved aggregate metrics without a fresh per-engine plan filter.
Illustrative response when no snapshots exist:
{ "date": null, "totalQueries": 0, "competitors": [] }Unexpected failures return 500 with { error: "Failed to fetch competitor data" }.
GET /api/dashboard/sources
Aggregate historical cited URLs across plan-allowed engines. days=90 selects 90 days; all other values, including omission, select 30. The cutoff is the date obtained by subtracting that many days from the request time; stored date strings on or after the cutoff are included.
curl 'https://loudmink.ai/api/dashboard/sources?days=90' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns { days, sources }, with up to 1,000 { url, engine, count } entries ordered by descending citation count. The same URL can appear separately for multiple engines. Counts represent stored query/engine/URL/date occurrences, not unique queries or domains. There is no pagination or all-time mode.
Unexpected failures return 500 with { error: "Failed to fetch source history" }.
GET /api/dashboard/source-classification
Returns citation-weighted ownership and source-type totals. days behaves exactly like /api/dashboard/sources. Requires an active workspace subscription for API-key callers.
This GET may use AI to classify source domains and save the results. It examines up to 2,000 URL groups from allowed engines and up to 100 candidate domains, excluding your own site and known competitors. Some sources may remain unclassified. Do not treat this as a free or side-effect-free health check.
curl 'https://loudmink.ai/api/dashboard/source-classification?days=30' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns { days, split, detail }:
| Field | Meaning |
|---|---|
split.totalCitations | Total citation occurrences included after URL-to-domain processing. |
split.self, split.competitor, split.neutral, split.unclassified | Citation counts by ownership/classification bucket. |
split.byType | Map of source type to citation count within the neutral bucket. |
detail.topCompetitorDomains | Up to three { domain, count } entries. |
detail.topSelfPages | Up to three { path, count } entries. |
detail.redditCitations, detail.youtubeCitations | Counts matched to Reddit and YouTube domains, not all forum/video types. |
These are counts, not percentages. Product-domain matching takes precedence over competitor matching; absent or unknown classifications enter unclassified.
Errors: subscription 403; unexpected failures return 500 with { error: "Failed to compute source classification breakdown" }.
GET /api/dashboard/search-summary
Read Google Search Console headline metrics. No parameters or body. Requires an existing Search Console connection with a selected property mapped to this product; a legacy unassigned connection is usable only in a single-product organization. This endpoint does not establish a connection.
curl 'https://loudmink.ai/api/dashboard/search-summary' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns { connected: false } when the connection/property is missing, belongs to another product, or requires reauthorization. Otherwise returns { connected: true, property, windowDays: 28, site, content }.
site and content contain clicks and impressions, with optional clicksTrend and impressionsTrend. Trends are signed absolute differences, not percentage changes. They compare the latest 28-day window ending three days before today against the preceding 28 days. Trend fields are omitted when the preceding window has no rows. site is fetched live from Google and becomes null if that fetch fails; content uses stored article statistics for this product and remains available.
Side effects: an unseeded connection schedules a background article-statistics sync. Token refresh can update stored credentials; a rejected refresh can delete the integration, requiring reconnection. There is no route-level active-subscription gate on this read. Unexpected failures return 500 with { error: "Failed to fetch search summary" }.
GET /api/dashboard/search-timeseries
Read daily Google Search and managed-content statistics. A numeric days value of 90 selects 90 days; all other values select 30. Connection requirements and synchronization/token side effects match search-summary.
curl 'https://loudmink.ai/api/dashboard/search-timeseries?days=90' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns { connected: false, series: [] } when disconnected or reauthorization is required. Connected responses are { connected: true, siteAvailable, days, series }. Each series entry contains date, impressions, clicks, contentClicks, and contentImpressions.
The inclusive window ends three days before today. Entries are ascending by date and include only dates present in either source. Missing values in a merged entry become zero. If the live site fetch fails, siteAvailable is false and stored content data is still returned; zero site values then indicate unavailable data, not measured zero traffic.
Unexpected failures return 500 with { error: "Failed to fetch search timeseries" }.
GET /api/campaigns/status
Read the latest campaign cycle by creation time. No parameters or body. This GET can mark a stale non-terminal cycle failed: after more than 15 minutes without an update in analyzing, 10 minutes in proposing, or 20 minutes in other non-terminal states. It writes a failure message and completion time. There is no active-subscription gate on this method.
curl 'https://loudmink.ai/api/campaigns/status' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"With no cycle, returns 200:
{ "hasCycle": false, "cycle": null, "summary": "No campaign cycles have run yet." }Otherwise returns { hasCycle: true, cycle, summary }. Cycle fields are id, status, isRunning, progress, error, startedAt, completedAt, and createdAt. Dates are ISO strings; completedAt may be null. Progress is a stage estimate: 35 for analyzing, 85 for proposing, 100 for complete, and 0 for other states. It is not a measurement of completed work. A response that auto-recovers a stale cycle can still contain its pre-update completedAt; fetch again for the persisted completion time.
POST /api/campaigns/status
Start a campaign cycle. No body or parameters. Requires an active subscription and at least one tracked query. It starts asynchronous campaign processing.
curl -X POST 'https://loudmink.ai/api/campaigns/status' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns 200 with { triggered: true, cycleId, autoRecoveredCycleId }. The last field is null unless a stale cycle was marked failed before creating the new one. Completion is asynchronous; use the status GET to inspect progress.
If a non-stale cycle is already running, returns 200 with { triggered: false, reason: "A cycle is already running.", cycleId, stage }. With no tracked queries, returns 400 with { triggered: false, reason: "No queries tracked for this product. Add queries first." }. Subscription failures return 403.
Dispatch failure can happen after the cycle row is committed. This method does not have a route-specific catch/error envelope; inspect status before retrying a failed request. It does not accept an idempotency key.
DELETE /api/campaigns/status
Cancel an active cycle for the key's product. No body or parameters. This is not deletion of campaign history: it marks one non-terminal cycle failed with Manually cancelled by user, sets its completion time, and attempts to send a cancellation event to stop processing between steps. Cancellation-event failure does not undo the saved state. This method has no additional active-subscription gate.
curl -X DELETE 'https://loudmink.ai/api/campaigns/status' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns 200 with { reset: true, cycleId }, or { reset: false, reason: "No active cycle to reset." }. The campaign-status methods do not define a uniform JSON envelope for unexpected database or runtime failures.
GET /api/agent/knowledge-base
Read metadata for the latest saved agent knowledge base. No body or parameters are needed. Diagnostic modes are outside this customer reference.
curl 'https://loudmink.ai/api/agent/knowledge-base' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Default response: 200 with { knowledgeBase }, where knowledgeBase is null if never built or an object containing id, builtAt, tokenEstimate, and cycleId.
This metadata request does not run a new visibility check or generate AI content. Knowledge-base content can include private business context; share it only with trusted applications.
POST /api/agent/knowledge-base
Compile current data and save a new knowledge-base row. No request body or parameters. Requires an active subscription. It completes the database compilation synchronously; this is not an asynchronous job response and does not replace previous builds.
curl -X POST 'https://loudmink.ai/api/agent/knowledge-base' \
-H "Authorization: Bearer $LOUDMINK_API_KEY"Returns 201 with { knowledgeBase: { id, builtAt, tokenEstimate } }. Subscription failures return 403. Unexpected failures have no route-specific JSON error envelope.
Dashboard routes requiring a session
GET /api/dashboard/changes, GET /api/dashboard/events, and GET /api/dashboard/next-action use session-only authentication. A Bearer API key alone does not grant access; they are not part of the API-key reference.