Skip to content

Public Endpoints

The /public/* endpoints are designed to be called from a browser by the JavaScript SDK. They authenticate with a write key (not an API key) and validate the request Origin against the workspace’s allowed domains.

Auth headerWhere to use
X-Write-Key: <key>All public endpoints

The write key is org-scoped (it resolves to one organization) and the Origin header must match a domain registered on the write key’s stream config. Server-side calls without an Origin header bypass the domain check but still need a valid key.

These endpoints are also wrapped by the SDK:

EndpointSDK wrapper
POST /public/enrich/lookup<G8Form /> progressive form
GET /public/visitors/companyg8.visitors.identify()
GET /public/visitors/scoreg8.visitors.score()
GET /public/signals/companyg8.signals.company()
POST /public/copilot/chatg8.copilot.ask()

For machine-readable schemas see the interactive API docs.


Authentication

All requests must include the write key:

Terminal window
curl "https://be.graph8.com/api/v1/public/visitors/company" \
-H "X-Write-Key: $WRITE_KEY" \
-H "Origin: https://yoursite.com"

Errors

StatusMeaning
401Missing X-Write-Key, invalid key, or key not linked to an org
403Origin not in the workspace’s allowed domains

Lookup Contact (Progressive Form)

POST /public/enrich/lookup

Look up a contact by email and report which form fields graph8 already knows. Used by <G8Form /> to hide pre-filled fields and only ask for what’s missing.

The supported form-field set is fixed: name, company, phone, title, website.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail to look up

Example

Terminal window
curl -X POST "https://be.graph8.com/api/v1/public/enrich/lookup" \
-H "X-Write-Key: $WRITE_KEY" \
-H "Origin: https://yoursite.com" \
-H "Content-Type: application/json" \
-d '{"email": "jane@acme.com"}'

Response

{
"data": {
"found": true,
"known_fields": {
"name": "Jane Smith",
"company": "Acme Inc",
"title": "VP of Engineering",
"website": "https://acme.com"
},
"missing_fields": ["phone"]
}
}

If no match is found, found is false and missing_fields lists all 5 fields.


Identify Visitor Company

GET /public/visitors/company

Resolve the caller’s IP address to a company using the ip_2_company table. graph8 reads the IP from X-Forwarded-For, then X-Real-IP, then the direct connection.

If a domain match is found, the response is enriched with industry, employee count, city, and country from the OpenSearch mashup index.

Example

Terminal window
curl "https://be.graph8.com/api/v1/public/visitors/company" \
-H "X-Write-Key: $WRITE_KEY" \
-H "Origin: https://yoursite.com"

Response

{
"data": {
"company_name": "Acme Inc",
"company_domain": "acme.com",
"industry": "Technology",
"employee_count": "500",
"city": "San Francisco",
"country": "US",
"confidence": 0.85
}
}

If the IP cannot be resolved, all fields except confidence (which is 0.0) are null.


Score Visitor

GET /public/visitors/score

Return an engagement score (0-100) for the current visitor based on their last 7 days of events.

Example

Terminal window
curl "https://be.graph8.com/api/v1/public/visitors/score" \
-H "X-Write-Key: $WRITE_KEY" \
-H "Origin: https://yoursite.com"

Response

{
"data": {
"engagement": 65,
"intent": "medium",
"signals": ["multi_page_visit", "high_activity"]
}
}

intent is high (>=70), medium (>=30), or low. Signals are derived from page diversity and event volume.


Company Intent Signals

GET /public/signals/company

Return buying-intent signals for a company domain (not the current visitor). Aggregates the last 30 days of events from any visitors resolved to that domain.

Query Parameters

ParameterTypeRequiredDescription
domainstringYesCompany domain (e.g. acme.com)

Example

Terminal window
curl "https://be.graph8.com/api/v1/public/signals/company?domain=acme.com" \
-H "X-Write-Key: $WRITE_KEY" \
-H "Origin: https://yoursite.com"

Response

{
"data": {
"domain": "acme.com",
"score": 75,
"intent": "high",
"signals": [
"pricing_page",
"demo_page",
"multiple_visitors",
"deep_exploration"
],
"last_seen": "2026-04-15T14:30:00Z"
}
}

The signals[] list is derived from page paths (/pricing, /demo, /book, /case-stud*), unique visitor count (>=3), unique page count (>=5), and total event count (>=20).


Copilot Chat

POST /public/copilot/chat

Send a message to graph8 copilot scoped to the org’s knowledge base (global context docs, brand brief, FAQs). Unlike the authenticated copilot, this endpoint has no admin tools - it can only read from the org’s RAG index.

Request Body

FieldTypeRequiredDescription
messagestringYesUser message
session_idstringNoConversation session ID (echoed back)
contextobjectNoOptional client-side context

Example

Terminal window
curl -X POST "https://be.graph8.com/api/v1/public/copilot/chat" \
-H "X-Write-Key: $WRITE_KEY" \
-H "Origin: https://yoursite.com" \
-H "Content-Type: application/json" \
-d '{"message": "Do you offer SOC 2 compliance?"}'

Response

{
"data": {
"response": "Yes - Acme is SOC 2 Type II compliant as of...",
"session_id": null,
"sources": [
{"title": "Security FAQ", "type": "faq"}
]
}
}

When the RAG search or AI completion fails, the endpoint returns a graceful fallback string instead of a 5xx - check sources to see whether real context was retrieved.