Customer 360 API with Salesforce and Snowflake
All templates

Customer 360 API with Salesforce and Snowflake

A 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.
ClaudeOpenAI CodexCursorVS Code

Copy and paste the prompt in your local coding agent of choice.

Template Details

9 Tables 10 APIs 12 Functions 1 Tasks

Integrations

Segment Snowflake Salesforce
Template Preview
Client appClient appWeb · mobile · agentcustomer_360 APIcustomer_360 APIcustomers/{customer_id}customers/{customer_id}/consentcustomers/{customer_id}/consentcustomerscustomers/{customer_id}/time...customers/{customer_id}/traitsevents/segment+2 moreBusiness logicBusiness logicC360 apply consentC360 assemble 360C360 authC360 ingest eventC360 link aliasC360 query salesforceC360 query snowflake+2 moreDataDataattributeaudit_logconsentconsumereventfield_policyidentity_alias+2 moreExternal servicesExternal services Segment Snowflake Salesforce

Overview

A 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.

What it provides

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.

Repo layout

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

How it works

Three planes, joined in Xano:

  • Identity graph (native, authoritative). Every inbound identifier becomes an identity_alias edge (anonymous_id, user_id, or email) pointing at one identity. c360_resolve_identity stitches them with a fixed precedence (user_idemailanonymous_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.
  • Merged-attribute cache (native). Each attribute is stored per source in the 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.
  • Consent + masking (enforced at read). 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:

  • Segment (inbound, credential-free). 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.
  • Snowflake (outbound). 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.
  • Salesforce (outbound). 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).

Quick start

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.

  1. Push the backend. Deploy the backend/ export to a Xano workspace (the CLI/agent flow below does this for you).
  2. Load the demo. 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.
  3. Open the frontend. Open 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.
  4. (Optional) Connect the real sources. Set the environment variables below to enable the Snowflake and Salesforce enrich path against your own accounts. Segment ingest works immediately by pointing a Segment Webhooks destination at 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.

API surface

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_key parameter. A production hardening step is to move this to an X-API-Key header enforced in middleware; the template uses a parameter so the demo frontend and tests work without header plumbing.

Database Tables

  • identity — the canonical customer record (primary email, display name, external ref).
  • identity_alias — the graph edges: an anonymous_id / user_id / email value linked to an identity (unique per kind+value).
  • event — the native Segment event stream (unique on message_id for dedup); powers the timeline.
  • attribute — the merged-profile cache, one row per (identity, key, source); the read path serves from here.
  • consent — per-purpose consent state (granted/denied) for each identity; the source of truth for masking.
  • field_policy — maps each attribute key to a consent purpose and a sensitivity tier (low/medium/high/pii).
  • consumer — API consumers and their keys (active/inactive) that authenticate to the read API.
  • audit_log — an append-only record of every access: consumer, identity, action, and which fields were masked.
  • sync_state — per-source cursor + last-synced timestamp (drives the Salesforce SystemModstamp delta).

Testing

Run from a deployed workspace:

  • Unit tests (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.
  • Workflow tests (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.

Environment variables

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_HOSThttps://<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_URLhttps://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):

    • move the secret to a custom request header (e.g. X-Webhook-Secret) instead of the query string, so it never appears in a URL; or
    • verify Segment's HMAC-SHA1 signature (X-Signature) computed over the raw request body — the strongest option, and the one Segment recommends.

Frequently asked questions

Can I run this without Snowflake or Salesforce credentials?
Yes. The read path — identity resolution, the merged 360, consent masking, the timeline, and the audit log — is served entirely from Xano's native tables and runs on the shipped seed data with no external credentials. Segment ingest also runs credential-free. Snowflake and Salesforce are only needed to refresh the attribute cache from your own live accounts on the enrich path.
Each attribute key is mapped by field_policy to a consent purpose (e.g. ltv → analytics). On every read, c360_apply_consent checks the customer's consent for that purpose; anything not granted is withheld — its value is nulled and the key is listed in masked_keys. Consumers never receive a field the customer hasn't allowed, and every access is recorded in the audit log.
It is not a compliance certification. It provides the mechanisms that support such a program: per-purpose consent capture and withdrawal, per-field masking enforced at read time, sensitivity tiers, and an append-only audit trail of every access. Compliance is an organizational outcome — this template gives you the technical controls, not the certificate.
Against mocks built from each vendor's own API documentation — the Snowflake SQL API v2 statement response and the Salesforce OAuth token + SOQL query response. The unit tests prove the request shape, auth, and response parsing against the documented contract. Running against live data requires your own credentials.
Every template runs on any Xano plan, including the free tier. All you need is a Xano account and a coding agent connected to the CLI and Developer MCP.
You can import and run it with your local coding agent — it works against the seed data it ships with. Paste this prompt into your agent: 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. You can also do a manual clone from Github, still using the Xano CLI and Developer MCP to connect to Xano to build and deploy.
Yes — that's the intent. The backend is plain XanoScript that you can read and AI can build on: add or edit tables, endpoints, and logic, or swap integrations. It ships with tests you can extend as you go.
Xano gives you an enterprise-grade backend — database, APIs, and logic — that AI can build and you can visually inspect, edit, and trust. Hosted, scalable, and production-ready from day one. Speed of generation, without the black box.

Get started for free today

Xano gives you everything you need to ship modern applications—fast, securely, and at scale.

Get started