Quickstart

Five minutes from nothing to your first identified company.

Signal tells you which companies and people visit your website. This page gets you a working integration; the guides go deeper.


1. Get a key

Sign in, go to Exports & API, name a key and choose what it reaches.

ScopeReaches
readthe REST endpoints
copilotthe natural-language endpoint

The key is shown once. It is stored hashed — if you lose it, create another and revoke the old one. Scopes are fixed at creation: to change what a key reaches, make a new one. A credential whose powers can grow after it was reviewed is one nobody can reason about.

2. Your first call

curl "https://app.signal.geysera.com/signal-api/v1/accounts?page_size=5" \
  -H "Authorization: Bearer sk_sig_…"
{ "accounts": [ … ], "total": 1927, "page": 1, "page_size": 5 }

That is the whole authentication story: one header.

3. Ask a question instead

With a copilot-scoped key:

curl https://app.signal.geysera.com/agent-api/signal/copilot/ask \
  -H "Authorization: Bearer sk_sig_…" -H "Content-Type: application/json" \
  -d '{"question": "which companies visited most last week?", "thread_id": null}'

The response carries the answer, the tools that ran, and the figures behind it. It is read-only whatever it is asked.

4. Stop polling

# Register an endpoint; we POST the moment someone is identified.

Webhooks are how most integrations should work. Polling asks us every few minutes whether anything happened; a webhook tells you when it does. → Receive identified visitors by webhook


Before you build: four things that will save you a day

1. total is not a row count. It is what your plan permits you to resolve. Rates computed against it change when your billing changes. Use it to page, not to divide.

2. Unknown query parameters are ignored, not rejected. ?limit=10 returns 200 and the default page size. Assert that the response's page_size is what you asked for — one line, catches every parameter typo you will ever write.

3. 401 and 403 mean different things. 401 = the key is missing, malformed, unknown or revoked. 403 = the key is fine and lacks the scope. Re-issuing a key fixes the first and never the second.

4. Identification yield depends on your audience, not your setup. Two accounts with identical configuration matched ~50% and ~0% of visitors. That is a property of who visits you, not a misconfiguration. Read why attribution covers less than you think before you build a target around a rate.


Discover the surface instead of trusting this page

curl https://app.signal.geysera.com/agent-api/capabilities

Public, no key needed, and generated from the routes' own auth dependencies — so it cannot describe an endpoint that does not exist or omit one that does. It carries the endpoint list with the scope each needs, the pagination bounds, the rate limit and its scope, the error vocabulary, and the response headers you should act on.

Every number in this documentation is derived from that endpoint or asserted against the code by a test. If this page and /capabilities ever disagree, /capabilities is right — and that is a bug we want to hear about.


Where to go next

Guides — what you are trying to do

Reference

  • Full API guide — scopes, conventions, limits
  • GET /signal-api/v1/openapi.json — OpenAPI 3.1 for the REST endpoints

Case studies — what we learned running this


What is not available yet

Stated plainly so you do not design around something that does not exist:

  • Writes. No endpoint creates or changes anything. The idempotency and concurrency contracts that would need are not finished, 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.
  • More than one webhook event type. Today: signal.visitor_identified.

Markdown source: /developers/quickstart.md