Start in your local coding agent.
Copy the prompt above and paste it in your local coding agent of choice. It builds this template into your workspace, ready to customize and test.
Coding agents on XanoA Customer 360 identity layer on Xano - stitch Segment events, Snowflake attributes, and Salesforce CRM into one consent-masked profile served through a single API and MCP tool.
Start building in Xano: Access the prompt at https://go.xano.co/start-xano-with-template-skill and run it here with customer-360-segment-snowflake-salesforce as your template. Copy and paste the prompt in your local coding agent of choice.
Copied! Paste the prompt in your coding agent of choice.
workspace customer_360 {
acceptance = {ai_terms: false}
preferences = {
internal_docs : false
track_performance: true
sql_names : false
sql_columns : true
}
}
Copy the prompt above and paste it in your local coding agent of choice. It builds this template into your workspace, ready to customize and test.
Coding agents on XanoA Customer 360 identity layer on Xano: stitch anonymous and known identifiers into one customer, merge behavioral events (Segment), warehouse attributes (Snowflake), and CRM records (Salesforce) into a single profile, and serve it through one API with per-field consent masking and a full audit log.
Product, support, and sales each see a different customer because the data lives in three systems: events in Segment, revenue and firmographics in Salesforce, warehouse-modeled attributes in Snowflake. This template makes Xano the place those sources are joined - the identity graph, the merged-attribute cache, and the consent state live in Xano's native database, so every downstream consumer (a support console, in-app personalization, a sales workflow, or an AI agent) resolves the same customer with the same consent rules.
When customer data is scattered across a CDP, a warehouse, and a CRM, every team builds its own half-right join. Identity resolution gets re-implemented in each tool, "who is this customer" disagrees between systems, and consent - which fields a customer has actually allowed you to use, and for what - is enforced inconsistently if at all. The result is duplicated logic, contradictory profiles, and privacy risk.
This template centralizes that join. It keeps a native identity graph (anonymous_id / user_id / email aliases resolving to one identity), a merged-attribute cache with a deterministic source-precedence policy, and per-purpose consent that is enforced at read time so no consumer ever receives a field the customer hasn't allowed. The read path is self-contained and served entirely from Xano; Snowflake and Salesforce are pulled in on the write/enrich path to refresh the cache. It gives you the mechanisms that support a SOC 2 / GDPR / CCPA program - consent capture and withdrawal, per-field masking, and an immutable audit trail of every access - without pretending to be a compliance certification.
backend/
ai/
mcp_server/
customer_360.xs
tool/
lookup_customer_context.xs
api/
customer_360/
api_group.xs
customers_by_id_get.xs
customers_consent_get.xs
customers_consent_post.xs
customers_get.xs
customers_timeline_get.xs
customers_traits_get.xs
events_segment_post.xs
seed_post.xs
sync_snowflake_post.xs
function/
c360_apply_consent.xs
c360_assemble_360.xs
c360_auth.xs
c360_ingest_event.xs
c360_link_alias.xs
c360_query_salesforce.xs
c360_query_snowflake.xs
c360_resolve_identity.xs
c360_salesforce_delta_sync.xs
c360_salesforce_refresh.xs
c360_upsert_attribute.xs
c360_write_audit.xs
table/
attribute.xs
audit_log.xs
consent.xs
consumer.xs
event.xs
field_policy.xs
identity_alias.xs
identity.xs
sync_state.xs
task/
c360_nightly_salesforce_sync.xs
workflow_test/
c360_auth_rejects_invalid_key.xs
c360_masks_denied_analytics_fields.xs
c360_segment_ingest_resolves_and_dedups.xs
workspace/
customer_360.xs
Three planes, joined in Xano:
identity_alias edge (anonymous_id, user_id, or email) pointing at one identity. c360_resolve_identity stitches them with a fixed precedence (user_id → email → anonymous_id): it finds the existing identity for any provided identifier, creates one only when none matches, and links the remaining aliases. Merging two already-separate identities is deliberately not automatic - it's a destructive operation left to an explicit, audited step.attribute table (segment / snowflake / salesforce / manual). c360_assemble_360 merges them with a deterministic precedence - manual > salesforce > snowflake > segment - so the resolved value for any key is well-defined and every consumer agrees.field_policy maps each attribute key to a consent purpose and a sensitivity. c360_apply_consent checks the customer's consent for that purpose on every read; anything not granted is withheld (value nulled, key listed in masked_keys). Masking is a function, not an addon - Xano addons only attach related data, they can't transform it.The read path (GET /customers/*, the MCP tool) is served entirely from these native tables, so it runs and is tested without any third-party credentials. The enrich path refreshes the cache from outside:
POST /events/segment accepts identify/track/page/group events, deduplicates on messageId (at-least-once delivery), resolves the identity, stores the event for the timeline, and promotes identify traits to segment-sourced attributes.c360_query_snowflake calls the Snowflake SQL API v2 (POST /api/v2/statements, PAT auth, parameterized bindings) for LTV, 30-day product usage, and cohort, and upserts them as snowflake-sourced attributes.c360_salesforce_refresh runs the OAuth2 refresh-token flow; c360_query_salesforce runs SOQL against Contact/Account; a nightly task (c360_nightly_salesforce_sync) delta-syncs Contacts modified since a stored SystemModstamp cursor.Every read writes an audit_log row (who accessed which customer, and which fields were masked).
Start with your coding agent. Paste the prompt below into a local MCP-capable coding agent - Claude Code, Cursor, Windsurf, and others. It installs the Xano CLI, connects Xano, and imports this template.
Start building in Xano: Access the prompt at https://go.xano.co/start-xano-with-template-skill and run it here with customer-360-segment-snowflake-salesforce as your template.
The agent will walk you through the setup below.
backend/ export to a Xano workspace (the CLI/agent flow below does this for you).POST /api:c360-customer-360/seed - idempotent; creates 6 customers with aliases, seeded Segment/Snowflake/Salesforce attributes, mixed consent, field policies, API consumers, and events. No credentials needed.frontend/index.html, enter your instance base URL and the demo key c360_demo_support_key, and click Load demo data. Search a customer, open their 360, and flip a consent purpose to watch masking change live.POST /events/segment.The read path and Segment ingest run with no external credentials. Snowflake and Salesforce enrichment require your own accounts - see Environment variables.
All endpoints live in the customer_360 API group (canonical c360-customer-360). Consumer endpoints authenticate with a consumer key passed as api_key (query or body); see the note below.
Read (consumer-authenticated):
| Method | Path | Purpose |
|---|---|---|
GET |
/customers |
Search / list identities by email or display name (pass ?q=). A collection route is used instead of /customers/search because Xano routing is non-cascading and a {customer_id} wildcard would collide with a search literal at the same segment. |
GET |
/customers/{customer_id} |
The consent-masked 360: resolved identity + merged attributes + masked_keys. |
GET |
/customers/{customer_id}/timeline |
The event stream, newest first. |
GET |
/customers/{customer_id}/traits |
Just the masked trait key/values. |
GET |
/customers/{customer_id}/consent |
Current per-purpose consent state. |
Write:
| Method | Path | Purpose |
|---|---|---|
POST |
/customers/{customer_id}/consent |
Record/update consent for a purpose (granted / denied). Upserts and audits - the GDPR/CCPA capture-and-withdrawal mechanism. |
POST |
/events/segment |
The Segment webhook sink (see the HMAC note under Environment variables). |
POST |
/sync/snowflake |
Manually refresh one customer's warehouse attributes (requires Snowflake credentials). |
POST |
/seed |
Load the demo dataset (no auth). |
MCP server (c360-mcp): exposes one tool, lookup_customer_context, that returns a customer's consent-masked 360 and recent events by customer_id, email, or user_id - for support copilots and in-app assistants. It is read-only and never creates or mutates an identity.
Auth note. Consumers pass their key as the
api_keyparameter. A production hardening step is to move this to anX-API-Keyheader enforced in middleware; the template uses a parameter so the demo frontend and tests work without header plumbing.
anonymous_id / user_id / email value linked to an identity (unique per kind+value).message_id for dedup); powers the timeline.SystemModstamp delta).Run from a deployed workspace:
xano unit_test run_all) - the Snowflake and Salesforce legs, validated against mocks built from each vendor's own API documentation (the SQL API v2 statement response; the OAuth token + SOQL query response). These prove the request shape, auth headers, status handling, and response parsing against the documented contract - not against a live account.xano workflow_test run_all) - end-to-end on the seed data, credential-free:c360_masks_denied_analytics_fields - a customer with analytics consent denied gets ltv / cohort / product_logins_30d withheld; a fully-consented customer gets nothing masked.c360_segment_ingest_resolves_and_dedups - a new Segment identify event resolves an identity and lands on the timeline; a replay of the same messageId is deduplicated.c360_auth_rejects_invalid_key - unknown and revoked (inactive) consumer keys are rejected.What is and isn't proven for real: the identity graph, merge, consent masking, audit, and Segment ingest are exercised end-to-end against shipped seed data. The Snowflake and Salesforce enrich calls are proven against their documented contracts via mocks; running them against live data requires your own credentials (below). The nightly Salesforce task is wired and safe to leave enabled - without credentials the external call fails and is caught/logged as a no-op.
Set these to enable the outbound enrich path. The read path and Segment ingest need none of them.
Snowflake (SQL API v2). Requires a programmatic access token, and the token's user must have a network policy that allows your Xano instance's egress IPs. Large results return 202 and must be polled - this template reads the first synchronous page.
SNOWFLAKE_ACCOUNT_HOST - https://<account>.snowflakecomputing.com.SNOWFLAKE_PAT - the programmatic access token (sent as a Bearer token).SNOWFLAKE_DATABASE, SNOWFLAKE_SCHEMA, SNOWFLAKE_WAREHOUSE, SNOWFLAKE_ROLE - the query context.Salesforce (REST + SOQL). Requires an API-enabled edition (Enterprise/Unlimited/Developer - base Essentials/Professional/Group editions have no API access) and a Connected App with the api and refresh_token scopes; mint the refresh token once via an interactive OAuth flow.
SALESFORCE_LOGIN_URL - https://login.salesforce.com (or your My Domain / https://test.salesforce.com for sandboxes).SALESFORCE_CLIENT_ID, SALESFORCE_CLIENT_SECRET - the Connected App consumer key/secret.SALESFORCE_REFRESH_TOKEN - the stored refresh token.SALESFORCE_API_VERSION - optional, defaults to v67.0.Segment.
SEGMENT_WEBHOOK_SECRET - optional shared secret that gates POST /events/segment. When it is set, the endpoint rejects any request whose ?secret= query parameter doesn't match; when it is unset (e.g. the demo workspace) ingest is open. To use it, append ?secret=<value> to the webhook URL you configure in Segment.
The query-string gate is a basic deterrent, not production-grade auth. Because the secret travels in the URL, it can be captured in server access logs, proxies, and browser history - HTTPS encrypts the transport, but the full URL is still logged at each hop. Don't rely on it alone for a real deployment. Harden it one of two ways (both need a small Xano middleware to read the request header / raw body, which this template does not ship):
X-Webhook-Secret) instead of the query string, so it never appears in a URL; orX-Signature) computed over the raw request body - the strongest option, and the one Segment recommends.Get started for free. Paste the template prompt into your coding agent, then customize and test it like any other Xano backend.