Contacts and CRM
Every visitor who completes a Perspective funnel becomes a contact in Perspective's built-in CRM. A contact is a rich record that goes well beyond a name and email: it captures the visitor's journey through the funnel, the UTM parameters that brought them to you, the answers they gave to funnel questions, and system-managed metadata like verification status and booking confirmations.
Contacts are scoped to a funnel
Contacts in Perspective are not global — they belong to a specific funnel. This means that GET /v1/funnels/{funnelId}/contacts returns contacts who converted through that particular funnel, and POST /v1/funnels/{funnelId}/contacts creates a contact within that funnel's CRM context.
This scoping matters when you are integrating data: if a contact converts through multiple funnels, they will appear as separate records in each funnel's contact list. The funnelId is always the first piece of information you need — see Workspaces and Campaigns for how to discover it.
The Contact object
The Contact object returned by all contact endpoints shares a consistent shape. It is documented in full on the List Contacts reference page, which is the canonical source for every field. The main sections are:
Standard identity fields — email, phone, firstName, lastName, name, fullAddress, website, birthday, and a structured address object. These are the fields you can set when creating a contact and update via the API.
System metadata (meta) — Read-only fields managed by Perspective. These include conversion and session timestamps (ps_converted_at, ps_first_seen_at, ps_last_seen_at), how the contact entered the system (ps_source, which can be funnel, manual, zapier, make, or external-api), funnel navigation data (ps_start_slug, ps_end_slug), and verification flags (ps_email_verified, ps_phone_verified). Integration-specific booking flags (ps_cal_booked, ps_hubspot_booked, ps_calendly_booked, ps_ghl_booked) are also stored here.
UTM parameters (utmParams) — Read-only. Captured from the contact's first attributed visit: utm_source, utm_medium, utm_campaign, utm_term, and utm_content. These are set automatically when a visitor arrives through a tracked link and cannot be overwritten via the API.
Custom properties (properties) — A key-value map of contact-specific data collected by the funnel. The keys correspond to the field names configured in the funnel builder, and the values reflect the answers the contact gave to funnel questions. For example, a product quiz might store { "quiz_answer": "Option A", "score": 42 }. These are read via the standard Contact object and written via the Update Contact Value endpoint.
Messages (messages) — An array of messages (email, SMS) sent to this contact through Perspective automations.
Reading contacts
To list all contacts for a funnel, call GET /v1/funnels/{funnelId}/contacts. The response is paginated and supports sorting by conversion timestamp, email, first name, or last name. The default sort is newest conversions first (ps_converted_at descending).
To retrieve a single contact by ID, call GET /v1/funnels/{funnelId}/contacts/{contactId}. Both endpoints return the same Contact object shape.
See the full reference pages: List Contacts and Get Contact.
Creating contacts
You can create contacts programmatically via POST /v1/funnels/{funnelId}/contacts. Either email or phone must be provided (both can be supplied; at least one is required). Standard identity fields can be set at creation time. Note that meta, utmParams, and properties are read-only and cannot be set through this endpoint.
By default, creating a contact triggers any automation workflows configured for the contact's initial status in that funnel. Pass skipAutomationTrigger: true to bypass this if you are doing a bulk import or backfill where you do not want automation emails to fire.
See Create Contact for the full request schema.
Updating contacts
To update a contact's data after creation, use PUT /v1/funnels/{funnelId}/contacts/{contactId}/values. This endpoint updates one field at a time: send a fieldName and value. Recognised field names include all standard identity and address fields. Any field name that is not a known field and not a reserved system field is stored as a custom property under the contact's properties map — this is how you can write funnel question answers or your own custom attributes.
Like the create endpoint, updates trigger automation workflows by default unless skipAutomationTrigger: true is passed.
See Update Contact Value for allowed field names and an example.
CRM via MCP
For AI assistants working with contact data, the MCP server provides tools that let an agent look up contacts, read their CRM properties, and work with contact data conversationally. This includes discovering the available custom properties for a given funnel — useful when building personalized email campaigns.
See the MCP CRM tools reference for details.
Permissions
Contact endpoints require the appropriate CRM permissions on your API key. Read operations (GET) require crm:read; write operations (POST, PUT) require crm:write. See API Keys for how to configure permissions.