---
title: "Identify website visitor by email"
method: POST
path: "/api/website-visitors/identify"
tags: ["website_visitors"]
---

# Identify website visitor by email

`POST /api/website-visitors/identify`

## Request

- Base URL: `https://beta.getsales.io/signals/v1`
- URL: `https://beta.getsales.io/signals/v1/api/website-visitors/identify`
- Auth: HTTP bearer and API key in header `Team-SID`

Name the person behind a browser from the customer's own backend, after a login or a signup: the site, the first-party visitor id the page holds (_gs_vid), the email, and a form name when a form was submitted (it becomes the fact website_form_submitted of the open session). The person is found by email in the team's tables; nobody matched leaves the email on the row as identified_email; an address on the team's own site marks the visit internal; a visitor bound by a code or by hand keeps its person. On a site set to companies it names nobody: no bind, no identified_email, no fact, only the internal rule; the form still joins the session's events. A visitor id the collector has not seen yet is 422 relation_not_found: retry in a few seconds. For an agent in the app, identify_website_visitor is the tool.

Contract:
- MCP tool `identify_website_visitor_by_email`, registry package `mcp.signals/website_visitors`, mount `signals.visits`.
- Operation `action`, response envelope `action`.
- Flags: none.

## Request body

- IdentifyWebsiteVisitorByEmailRequest: Request body of `identify_website_visitor_by_email`.
  - `site_sid` string, required: The site the page belongs to.
  - `visitor_id` string, required: The first-party visitor id the page holds (_gs_vid), as the customer's backend read it from the browser.
  - `email` string, required: The address the person logged in or signed up with; the person is found by it in the team's tables.
  - `name` string, nullable: Taken as the script's identify takes it; not stored until the inbound lead slice.
  - `company` string, nullable: Taken as the script's identify takes it; not stored until the inbound lead slice.
  - `form` string, nullable: The form the person submitted (signup): it joins the open session's events once per name and becomes the fact website_form_submitted.

## Response `200`

`action` success envelope.

- IdentifyWebsiteVisitorByEmailResponse
  - `success` true, required
  - `operation` 'action', required
  - `action` string, required: kebab-case verb; matches the route segment.
  - `item` object, nullable, required
    - `sid` string, required: Website visitor sid (sg_wv_...).
    - `team_sid` string, required: Owning team (ts_tm_..., external: gs.service.id).
    - `site_sid` string, required: The site the browser visited (sg_si_...): the same browser on two sites is two rows.
    - `visitor_id` string, required: The first-party visitor id the script stores (_gs_vid, a lowercase UUID v4), or eph_ plus 40 hex characters for a hit that carried none.
    - `is_ephemeral` boolean, required: The row belongs to a day, not to a browser (consent not given, storage blocked): a stranger the next day, never bound.
    - `person_sid` string, nullable, required: The person the visitor is bound to (cr_pp_..., playtables); null while unbound.
    - `identified_email` string, nullable, required: The email an identify or a form gave when no person matched: the "Add to table" rows of the feed. Null otherwise.
    - `bound_by` 'code' | 'identify' | 'fingerprint' | 'manual', nullable, required: Which rung bound the visitor: code (the person code in our link), identify (an email a person matched), fingerprint (the device), manual (a bind by hand). Null while unbound.
    - `bound_at` string, nullable, required: ISO 8601 UTC, when the bind was written; null while unbound.
    - `first_seen_at` string, required: ISO 8601 UTC, the receipt time of the first hit.
    - `last_seen_at` string, required: ISO 8601 UTC, the receipt time of the newest hit.
    - `sessions_count` integer, required: Sessions opened for this visitor: the returning visitors.
    - `browser` string, nullable, required: From the newest session; null when unknown.
    - `browser_version` string, nullable, required
    - `os` string, nullable, required
    - `os_version` string, nullable, required
    - `device` 'desktop' | 'mobile' | 'tablet' | 'unknown', required: desktop | mobile | tablet | unknown, from the newest session.
    - `screen` string, nullable, required
    - `language` string, nullable, required
    - `timezone` string, nullable, required
    - `geo_country` string, nullable, required: ISO 3166-1 alpha-2 of the newest session; null when the edge gave none.
    - `geo_region` string, nullable, required
    - `geo_city` string, nullable, required
    - `network_type` string, nullable, required: The newest resolved session's classification: business, isp, mobile, hosting, education, government or unknown; null until one resolved.
    - `network_name` string, nullable, required: The organization behind the newest resolved session's address; null until one resolved.
    - `network_domain` string, nullable, required: The company domain the data service derived; null when none.
    - `asn` integer, nullable, required
    - `as_name` string, nullable, required
    - `is_internal` boolean, required: The newest session was internal (the site's ignored_ips, or an identified email of the team's own domains).
    - `created_at` string, required: ISO 8601 UTC.
    - `updated_at` string, required: ISO 8601 UTC.
  - `result` object, required
    - `bound` boolean, required: A person is bound after the call (always true by hand; from the backend, false when the email matched nobody and stayed on the row as identified_email, or the site is set to companies).
    - `person_sid` string, nullable, required: The bound person (cr_pp_...), or null.
  - `meta` object, required
    - `trace_id` string, required: UUID v7; same 128-bit value as the X-Trace-Id header.
    - `span_id` string, required: 16 hex chars, root span of this request.
    - `timestamp` string, required: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
    - `duration_ms` integer, required: Server-side wall clock.
    - `team_sid` string, nullable: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
    - `actor_type` string, nullable: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.

## Other responses

- `4XX`: MCP error envelope. `error.code` is one of validation_failed, nothing_to_update, not_found, relation_not_found, invalid_transition, limit_exceeded, payment_required, duplicate_rejected, conflict, delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
- `5XX`: MCP error envelope with `error.code` internal_error or service_unavailable.

---

[API](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-signals.md) - [All operations](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-signals/llms.txt) - [OpenAPI document](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-signals/revisions/310ca5d2219d?raw)
