API reference
Signal API
Signal identifies the companies and people visiting your site. This API gives you that data programmatically — the organisations that visited ranked by intent, the people identified, where they arrived from, and what Signal currently recommends.
0.1.0Every endpoint, parameter, limit and response shape below is read from the running service at build time. Nothing on this page is maintained by hand, so it cannot describe an endpoint that does not exist or omit one that does.
This page is the endpoint reference. The developer guide, workflows and case studies live alongside the service they describe.
Quickstart
Create a key in Exports & API, then make your first request. The key is shown once, on creation.
curl "https://app.signal.geysera.com/signal-api/v1/accounts" \
-H "Authorization: Bearer sk_sig_..."https://app.signal.geysera.com/signal-api/v1, as the service reports it in its own spec. We do not hardcode it here.Authentication
Authorization: Bearer sk_sig_...- Authorizationheaderrequired
- Bearer sk_sig_... (required)
- X-Correlation-IDheaderoptional
- optional; generated when absent, echoed on every response
401 means the key is missing, malformed, unknown or revoked. 403 means the key is valid but lacks the scope for that endpoint. The two are deliberately distinct: a 403 means your credential is fine and re-issuing it will not help.
Scopes
- readscope
- The /signal-api/v1 REST endpoints: accounts, visitors, attribution, recommendations.
- copilotscope
- Ask questions in natural language at /signal/copilot/ask. READ-ONLY: a key reaches the copilot's read tools and never the ones that change the workspace, whatever it is asked.
A key is scoped to one workspace. Results respect that workspace's plan caps, exactly as the dashboard does. Scopes are fixed when the key is created: to change reach, create a new key and revoke the old one.
/accountsList identified accounts
Query parameters
- pageintegeroptional1–1000, default 1
- page_sizeintegeroptional1–200, default 50
- classificationlead | customer | competitor | excluded or nulloptional
Response fields
- accountsarray of PublicAccountrequired
- totalintegerrequired
- pageintegerrequired
- page_sizeintegerrequired
Status codes: 200 Successful Response · 422 Validation Error
curl "https://app.signal.geysera.com/signal-api/v1/accounts" \
-H "Authorization: Bearer sk_sig_..."{
"accounts": [
{
"company_domain": "string",
"company_name": "string",
"intent_score": 0,
"visitor_count": 0,
"visit_count": 0,
"classification": "string",
"first_seen_at": "2026-09-11T14:23:07Z",
"last_seen_at": "2026-09-11T14:23:07Z"
}
],
"total": 0,
"page": 0,
"page_size": 0
}/attributionAttribution rollup for a window
The nightly attribution rollup, served as-is.
Deliberately reads the cached rollup only and never falls back to a live scan, unlike the dashboard endpoint. A live recompute scans up to 200k visitor rows; behind an API key that is a trivially repeatable way to exhaust the database, and an integrator polling on a cron would do it without meaning to. computed_at tells the caller how fresh the answer is so staleness is visible rather than hidden.
Query parameters
- daysintegeroptional1–365, default 30
Status codes: 200 Successful Response · 422 Validation Error
curl "https://app.signal.geysera.com/signal-api/v1/attribution" \
-H "Authorization: Bearer sk_sig_..."/recommendationsOpen recommended actions
Catalog-grounded recommendations that are currently actionable.
Queries signal_journey_recommendation directly rather than importing the dashboard's recommendations service. That service lives on an unmerged branch (PR #98), and importing it here would have made this endpoint raise ImportError at runtime while every unit test passed — a cross-branch dependency is not a dependency, it is a deferred outage.
"Open" means the same thing it means in the app: status 'new', or 'snoozed' with the snooze elapsed. Status mutation is deliberately NOT exposed — acting on a recommendation carries an optimistic-locking contract that needs its own design rather than being bolted onto a read-only v1.
Query parameters
No parameters.
Status codes: 200 Successful Response
curl "https://app.signal.geysera.com/signal-api/v1/recommendations" \
-H "Authorization: Bearer sk_sig_..."/visitorsList identified visitors
Visitors belonging to accounts inside the plan's resolution cap.
Two rules are load-bearing and mirror the dashboard exactly:
* The accessible set is the earliest cap accounts by first_seen_at. Skipping this would let a free tenant read their entire book through the API while the UI blurs it — the paywall has to hold on every surface or it holds on none. * Free-tier contact fields are withheld. `is_locked` says so explicitly rather than leaving an integrator to guess why the values are null.
Query parameters
- pageintegeroptional1–1000, default 1
- page_sizeintegeroptional1–200, default 50
- min_intentinteger or nulloptional0–100
- 0-100 display scale, as shown in the app.
- classificationlead | customer | competitor | excluded or nulloptional
Response fields
- visitorsarray of PublicVisitorrequired
- totalintegerrequired
- pageintegerrequired
- page_sizeintegerrequired
Status codes: 200 Successful Response · 422 Validation Error
curl "https://app.signal.geysera.com/signal-api/v1/visitors" \
-H "Authorization: Bearer sk_sig_..."{
"visitors": [
{
"company_domain": "string",
"company_name": "string",
"intent_score": 0,
"classification": "string",
"resolved_email": "string",
"resolved_name": "string",
"resolved_title": "string",
"employer": "string",
"first_visit_at": "2026-09-11T14:23:07Z",
"last_visit_at": "2026-09-11T14:23:07Z",
"visit_count": 0,
"is_locked": false
}
],
"total": 0,
"page": 0,
"page_size": 0
}Asking questions in natural language
With a copilot-scoped key you can ask about your workspace instead of assembling the query yourself. The response carries the answer, the tools that ran, and the figures behind it.
- POST /signal/copilot/askcopilot
- Ask a question about this workspace's commerce data
- POST /signal/copilot/streamcopilot
- Ask a question, streamed per analysis step
- GET /signal/copilot/threadscopilot
- List this workspace's conversations
- GET /signal/copilot/threads/{thread_id}copilot
- A conversation and its messages
Pagination
- paramsconvention
- page (1-based), page_size (default 50, maximum 200)
- responseconvention
- an array named for the resource (`accounts`, `visitors`) plus total, page, page_size. There is no `items` key.
- noteconvention
- total is capped at what your plan may resolve, never the raw row count
- out_of_rangeconvention
- page_size above 200 is rejected with 422 rather than silently clamped, so a script cannot believe it read more than it did
Unknown query parameters are ignored, not rejected. A misspelled parameter returns a normal response with defaults applied. A person notices; a script reports the wrong number confidently.
Rate limits
300 requests per 60 seconds, per key. Exceeding it returns 429.
Errors
Every error carries the same shape:
- error_codefield
- stable machine-readable code; one of CONFLICT, FORBIDDEN, INTERNAL, NOT_FOUND, RATE_LIMITED, UNAUTHORIZED, VALIDATION_ERROR
- messagefield
- human-readable description
- correlation_idfield
- echo of X-Correlation-ID; quote it in support requests
- detailsfield
- optional structured context
Branch on details rather than parsing message. Quote correlation_id when asking us about a specific request.
What is not available yet
- Writes. No endpoint creates or changes anything. The idempotency and concurrency contracts those need are not built, and shipping writes without them would be a promise we could not keep.
- Per-key narrowing below the workspace. Every key sees the whole workspace.
- Webhooks for these resources. Poll, or use Auto-sync Rules in the app.
Discovery
Both of these are generated from the running service. If this page and those ever disagree, they are right.
- https://app.signal.geysera.com/agent-api/capabilities — every action a key can call, with the scope each needs. Public, no key required.
- https://app.signal.geysera.com/signal-api/v1/openapi.json — OpenAPI for the REST endpoints.
Natural language
What it can read
The 33 read tools the copilot can call, published by the service and derived from its own registry. Write tools are absent because an API key cannot reach them — changes are made in the dashboard, or by asking in a signed-in session where each one is described and confirmed first.
- aov_decompositionread
- Splits AOV into average unit price x average units per order, before vs after a boundary date.
- attribution_overviewread
- Which channels, sources and campaigns the attributed sessions came from, and what they were worth — the same cached rollup the Attribution page renders.
- causal_impactread
- Did a dated change actually CAUSE a metric to move? Fits a Bayesian interrupted time series: models the pre-change trend, predicts what would have happened without the change, and reports the difference with a credible interval.
- customer_countsread
- How many distinct people bought, how often they came back, and how many were new.
- data_coverageread
- What this workspace can and cannot answer for a window: order count, pixel volume, how many orders link to a pixel session, and which days the order sync missed.
- dry_run_sync_ruleread
- Show exactly which contacts a rule WOULD push, without pushing anything.
- enrichment_configread
- Who this workspace enriches, under what conditions, and what it is spending.
- esp_connectionread
- Which email platform this workspace is connected to, if any, and whether the connection is verified.
- get_accountread
- Everything known about ONE account by domain: firmographics, its visitors, orders and ESP contacts.
- get_conversationread
- Read back one past conversation — its questions, answers and the caveats each answer carried.
- identification_statusread
- Is identification actually running right now, and when did it last resolve anyone? Use when a workspace says visitors stopped appearing — a quiet pipeline and quiet traffic look identical on the accounts page, and this is what tells them apart.
- intent_pagesread
- The page rules this workspace uses to score buying intent, and what share of its real traffic they match.
- journey_pathsread
- How visitors move BETWEEN pages — the page-to-page graph behind the Journey view, reading the same nightly rollup the page reads.
- list_alert_destinationsread
- Slack destinations receiving this workspace's alerts, and whether each is active.
- list_api_keysread
- The workspace's API keys — id, name, prefix, last used.
- list_conversationsread
- Your own past conversations in this workspace, most recently updated first, with each one's title, question count and when it was last touched.
- list_teamread
- Who has access to this workspace: members with their roles, invitations still pending, and how many seats are left.
- list_webhooksread
- Registered webhook endpoints and whether each is enabled.
- membership_conversion_pathsread
- Which OTHER products are in the basket when a given product is bought.
- open_recommendationsread
- The workspace's open recommended actions, from both the journey and attribution surfaces.
- page_funnelread
- Per page: sessions that saw it, and how many added to cart, reached checkout and purchased in that same session.
- page_to_product_attributionread
- Which pages were seen in the same session as a purchase, optionally restricted to orders containing a given product.
- price_historyread
- When a product's price actually changed.
- product_performanceread
- Revenue, orders, units and quantity-weighted unit price per product.
- recall_factsread
- What this workspace has taught the assistant, and when.
- revenue_and_aovread
- Revenue, order count, AOV, discount and units per period (day/week/month).
- search_accountsread
- The accounts board: search by name or domain, filter by classification and minimum intent, sort, paginate.
- search_visitorsread
- Individual identified people, with the filters the Visitors page offers: text search, classification, minimum intent, whether they have ordered, whether they have been contacted, and which intent page they hit.
- subscriptionread
- This workspace's plan status, when it next renews, and whether it is set to cancel at the end of the period.
- sync_rulesread
- The auto-sync rules that push identified accounts to the connected ESP: their filters, status and last run.
- visiting_accountsread
- Which organisations visited the site, ranked by intent score, with their visits, visitors and any orders.
- visitor_journeyread
- The pages ONE visitor viewed, in order, with time on each.
- workspace_setupread
- Is this workspace actually working? Store connection, onboarding progress, pixel status, identification health and the current plan and usage, in one call.
More documentation
Guides & case studies
This page covers the endpoints. Longer-form documentation lives on the app host, next to the service it describes, at https://app.signal.geysera.com/developers.
Get started
- Quickstart
Create a key and make your first call.
Guides
- Developer guide
The three surfaces, conventions, the copilot, webhooks, and the things that will surprise you.
Workflows
- Receive identified visitors by webhook
Get a POST the moment a visitor is identified, and not miss any.
- Export and keep in sync
Pull the account list once, then keep it current without refetching it all.
- Ask questions in natural language
Use the copilot from code, and read the parts of the answer that matter.
- Alert your team when a target account appears
Filter the webhook against your named-account list and post to Slack within minutes.
- Build a daily call list
One call, a ranking you can read, and a prompt that is willing to say leave this one alone.
- Write a first-touch email from what they read
An opener grounded in real behaviour, with the SKIP rule that stops it inventing one.
- Spot a buying committee
Three people from one company in a week is one deal, not three leads.
- Notice an account going quiet
The cheapest churn signal you have, weeks before the renewal conversation.
- Fill your CRM with who is actually visiting
Compare the two account sets first; the gap is usually not the one you assumed.
- Find the pages that create pipeline
Rank content by who it brings rather than how many, and read the coverage first.
- Score and route inbound leads
Use what someone did before the form to decide who should get it.
- Keep an ad audience in sync
Suppress customers, retarget high intent, and the consent questions to answer first.
- A weekly revenue brief your LLM writes
Gather deterministically, write with a model, and propagate the disclosures.
- Watch your own data quality
The workflow that protects every other workflow: knowing when the data went quiet.
Playbooks
- Account-based marketing, end to end
Six stages, the two that carry the value, and the human gate to keep.
- Turning content into pipeline
Measure content on who it brings, then prove the change with a causal test.
- Let an LLM run your workspace
The response contract, refusals, the confirmation gate, and what a key can never do.
Case studies
- Most of your visitors were not people
69% of one account's events were unflagged crawlers.
- The pipeline that reported success while doing nothing
A job that caught its own failure and completed, for days.
- Why attribution covers less than you think
The ceiling is structural, and knowing the number is the useful part.