Developers · Guide

Xavio for developers

Every public endpoint, auth flow, webhook, connector. The integrator's reference.

This guide is the integrator's reference. It documents every public endpoint, every authentication flow, every connector, every webhook, and every operational expectation you need to ship an integration on top of Xavio — without reading our source code.

If you're an LLM agent or an AI-first integrator, the structured endpoints under /api/ucp/* are designed for you specifically. Start with LLM-first integration below.

Audience

  • Engineers integrating Xavio into a website, mobile app, or backend.
  • AI agents / LLMs that need to read catalog data or place orders.
  • Connector developers (Shopify app, WordPress plugin, etc.).
  • BI / analytics teams pulling data via API or webhooks.
  • Security teams reviewing our authn / authz model.

What you can build

Use caseBest surface
Read a merchant's product catalogUCP per-merchant (/api/ucp/products)
Read top stories + storefronts for citationUCP discovery (/api/ucp/llm-discovery)
Track conversions from external sitesXavio Dot pixel + /api/pixel/v1/collect
Sync Shopify orders + inventory both waysShopify connector app
Embed Xavio buttons on a WordPress siteWP plugin
No-code workflow (lead → CRM → Slack)Zapier or n8n connector
Place an order from an AI agentUCP capture flow with signed JWS
Mirror pixel events to your Meta CAPI / GA4Built into Dot configuration
Listen to merchant events in real timeWebhooks (HMAC-signed)
Query catalog with GraphQL/graphql/v1 (pg_graphql)

Surfaces

Xavio exposes four primary integration surfaces:

  1. UCP (Unified Commerce Protocol) — signed-envelope REST + GraphQL
designed for AI agents and server-to-server flows.
  1. Cookie-session REST — the same /api/* paths the web app uses,
for browser-based or embed flows.
  1. Pixel (Xavio Dot) — drop-in JavaScript snippet for cross-site
conversion tracking + first-party identity bridging.
  1. Connectors — pre-built integrations (Shopify, WP, Zapier, n8n,
MCP) for the common cases.

Pick the surface that fits — they're all production grade and all documented below.

Authentication

Xavio uses three distinct authn flows. Pick the right one for your integration.

The first-party app uses Supabase SSR cookies. Browser-based integrations that share the user's cookie can call the same /api/engagement/*, /api/keyword-rules/*, etc. endpoints the dashboard uses.

  • Endpoint base: https://xavio.in/api/*
  • Auth: HTTP cookies set by /auth/login flow (xv_session_*).
  • CORS: First-party only by default; restricted-origin policy on
`/api/auth/*`.
  • Session lifetime: 30 days sliding, 5-minute MFA freshness for
sensitive mutations.

You should not use this for server-to-server — it's for embeds in contexts that share the user's browser session.

Signed JWS (UCP — agents + S2S)

UCP envelopes are designed for agent-driven and server-to-server flows. Every UCP request carries a JWS-signed envelope proving the caller's identity and the request's intent.

  • Endpoint base: https://xavio.in/api/ucp/*
  • Auth: Authorization: JWS <compact-jws> header.
  • The JWS payload includes: caller key id, target merchant, requested
action, intent identifier, timestamp, nonce.
  • Issuer: agent keys minted by you at
`https://xavio.in/dev/keys`.
  • Verifier: our server validates against the key ring + replay-window
cache.
  • Key rotation: keys carry an explicit expiry; supports overlap window.
  • Rate limit: per-key, configurable per integration agreement.
UCP envelopes carry **mandates** for write actions (e.g. "this user authorised this agent to place orders up to ₹2 000 / day"). Mandates are issued by Xavio after the merchant approves the agent in the dashboard.

API key (Dot pixel)

For the pixel snippet, we use a public pixel id of the form xvp_<base32>. The pixel id is safe to embed on a public page — it does not authorise any write action beyond logging events scoped to that pixel.

For server-side pixel sends, you authenticate with a private key (nf_live_<...>) issued from the merchant developer portal.

UCP — Unified Commerce Protocol

UCP is Xavio's structured-data + agent surface. It's the most efficient way for an LLM or an external service to read Xavio data and (with permission) act on it.

Endpoints

MethodPathAuthPurpose
GET/api/ucp/llm-discoveryNone (public)Top stories + storefronts + structured metadata. Edge-cached 5 min.
GET/api/ucp/collectionsNone or signedList storefronts (anonymous) or one storefront's collections (signed).
GET/api/ucp/productsSignedProduct catalog for a storefront. Filter by category, in-stock, price range, etc.
GET/api/ucp/capabilitiesNoneDescribes every story component type — for LLMs to explain what a story does.
POST/api/ucp/leadsSigned + mandateSubmit a lead form on behalf of a user.
POST/api/ucp/captureSigned + mandatePlace a purchase / booking / order on behalf of a user.
All responses are JSON. Errors follow `{ error: string, code: string, status: int }` shape.

LLM discovery (no auth)

The discovery endpoint returns the highest-engagement stories + storefronts in a structured format LLMs can cite reliably.

Response shape: { refreshed_at, stories: [...], storefronts: [...] }.

Each story carries: short_id, canonical URL, host slug + name, caption, created_at, media type, attached overlay kinds (product, book_now, lead_form, etc.), engagement counts, and geo hints when present.

Each storefront carries: slug, name, category, description, GST / FSSAI / RERA badge presence, location, follower count, top categories.

The endpoint is read-only, rate-limited by IP at 60 requests / minute, and cached at the edge for 5 minutes. Use this for any "what's hot on Xavio right now" prompt.

Capabilities

GET /api/ucp/capabilities documents every story component type with its schema. Use this to teach an LLM what a story _does_, not just what it shows.

Component types currently exposed: text, image, video, audio, poll, question, quiz, reaction, this_or_that, product, service, buy_now, book_now, add_to_cart, lead_form, whatsapp_cta, live_audio. Each carries a JSON Schema describing its config.

Per-merchant access

GET /api/ucp/products?host=<slug> returns a merchant's full product catalog when called with a valid signed JWS. The merchant must have approved your agent in their developer dashboard, and your key must be within its validity window.

Filters supported: category, min_price, max_price, in_stock, gst_class, updated_after, limit, cursor. Pagination is cursor-based.

Each product response includes: id, title, description, price (in INR paise), variants array (size / colour / inventory per variant), images, category path, HSN code, GST class, fulfillment options, and the updated_at timestamp so you can incrementally sync.

Lead capture

POST /api/ucp/leads accepts a lead submission. The JWS must carry a mandate granting the agent permission to submit a lead on behalf of the end user. Mandate fields: user_id, host_id, purpose (always "lead_capture"), expires_at.

Body shape: { form_id, values: { ... } } where values matches the form schema returned from GET /api/ucp/capabilities.

Response: { ok: true, lead_id } or an error per the standard envelope.

Purchase / booking capture

POST /api/ucp/capture is the headline write endpoint. It places an order, books a slot, or fulfills an RFQ on behalf of a user.

Body discriminator: kind: "order" | "booking" | "rfq_accept".

For order:

  • host_id, items: [{product_id, variant_id, qty}], shipping_address,
`payment_method`, optional `coupon_code`, optional `notes`.

For booking:

  • host_id, booking_listing_id, preferred_at (ISO timestamp),
`payment_method`.

For rfq_accept:

  • quote_id and any custom acceptance fields the seller defined.
Response: `{ ok: true, capture_id, order_id?, booking_id?, payment_url?, status }`.

Mandate fields required: user_id, purpose matching the kind, spend ceiling, expires_at.

Webhooks for UCP

Configure your webhook URL in the developer portal at https://xavio.in/dev/webhooks. Xavio will POST signed payloads (HMAC SHA-256 in the X-Nafafy-Signature header) for these events:

  • lead.created
  • order.created, order.paid, order.fulfilled, order.cancelled,
`order.refunded`
  • booking.created, booking.confirmed, booking.cancelled
  • rfq.created, rfq.responded, rfq.accepted
  • inventory.updated
  • merchant.approved_agent, merchant.revoked_agent
Delivery retries: exponential backoff up to 24 hours. After 24h of failure, the webhook is paused; you receive an email and must manually resume from the dashboard.

Pixel — Xavio Dot

The Pixel is for tracking conversions on external sites (your Shopify store, your blog, your landing page) and bridging identity back to Xavio.

Snippet

Add to any page you want to track:

The snippet loads from https://xavio.in/pixel.js. Configure your pixel id (format xvp_<base32>) and the events you want to track.

Identity layers

The pixel maintains three first-party identifiers:

CookieLifetimePurpose
_xvp90 daysFirst-party browser id
_xvcSessionClick-id (xvclid) bridging in-app → external
_xv_external_id90 days (hashed)SHA-256 of Xavio user id, when known
These cookies are first-party only. There is no third-party tracking, no cross-site profile build.

Events

Standard events with documented schemas:

  • page_view — every page load.
  • view_content — viewing a product / category / article.
  • add_to_cart — buyer added an item.
  • initiate_checkout — buyer opened checkout.
  • purchase — order completed. Required for conversion tracking.
  • lead — form submission.
  • search — site search.
  • custom_* — your own events.

Form Harvester — auto-capture identity (opt-in)

By default you improve match rate by hand-wiring nf('identify', …). The Form Harvester does it for you: when enabled, the snippet listens for submit events, finds the email / phone inputs on the form (by input type, autocomplete, or field name/id), **normalizes and SHA-256 hashes them in the browser**, and attaches the resulting em_hash / ph_hash to your events. Raw email/phone values are never sent — only the hashes leave the page.

Enable it one of two ways:

<!-- 1) data attributes on the snippet tag -->
<script
  async
  src="https://nafafy.com/nf.js"
  data-id="nfd_…"
  data-harvest="true"
  data-harvest-block="search,coupon,confirm_email"
></script>
<!-- 2) config object (set BEFORE the snippet loads) -->
<script>
  window.nf =
    window.nf ||
    function () {
      (window.nf.queue = window.nf.queue || []).push(arguments);
    };
  window.nf.harvest = { enabled: true, allow: [], block: ['search', 'coupon'] };
</script>
<script async src="https://nafafy.com/nf.js" data-id="nfd_…"></script>
  • allow — if non-empty, only fields whose name/id/autocomplete
contains one of these substrings are harvested.
  • block — fields containing any of these substrings are always skipped
(blocklist beats allowlist). Use it for search boxes, coupon codes, or a "confirm email" field.

Normalization matches Xavio's server-side hashing exactly (email → trim+lowercase; phone → digits-only, strip leading zeros), so a harvested hash stitches to the same identity as one you pass explicitly. Harvesting respects consent: once nf('consent','revoke') is called, nothing is captured.

Mirror to Meta CAPI / GA4

If you've configured a connected Meta CAPI access token or GA4 Measurement ID in /dashboard/pixel/<id>, every event the pixel captures is also sent to those endpoints with the same event_id. This deduplicates against your existing Meta / GA dashboards.

Server-side ingest

For server-side fires (e.g. after a webhook completes), POST to /api/pixel/v1/collect with your private key (nf_live_<...>) in the Authorization header.

Server-side and browser-side events with the same event_id are deduplicated within a 48-hour window (Valkey-backed) so you can fire the same event from both ends safely.

Debug endpoint

GET /api/dot/v1/echo?id=<pixel_id>&event=<name> returns the resolution path Xavio would take without writing an event — useful for debugging origin allowlists and event configuration. 30 calls / minute / IP cap.

The web app uses these. Browser-based embeds and dashboard integrations can use them with a valid session cookie.

Engagement

MethodPathPurpose
POST/api/engagement/eventLog a single analytics event (view / tap / impression / etc.). Public; anon allowed for read-only kinds.
POST/api/engagement/story-viewsRecord a story view.
POST/api/engagement/story-likesLike a story.
POST/api/engagement/commentsPost a comment.
POST/api/engagement/comment-likesLike a comment.
POST/api/engagement/followsFollow a creator.
POST/api/engagement/post-reactionsReact to a post.
GET/api/engagement/comment-suggestionsGet heuristic + AI reply suggestions for a post (free 3-chip suggestions, distinct from Pro AI Smart Reply).
POST/api/engagement/notifications/readMark a notification read.
POST/api/engagement/notifications/read-allMark all read.
POST/api/engagement/notifications/seenMark notifications as seen.

Commerce

MethodPathPurpose
GET / POST / PATCH / DELETE/api/productsCRUD for products owned by the caller.
GET / POST / PATCH / DELETE/api/servicesSame for services.
GET / POST/api/booking-listingsBooking listing CRUD.
GET / POST/api/booking-listings/[id]/slotsList available slots.
GET / POST/api/booking-requestsCustomer-facing booking flow.
GET / POST/api/ordersPlace / list orders.
GET/api/orders/[id]Order detail.
POST/api/orders/[id]/refundRefund an order.
GET / POST/api/cartBuyer cart CRUD.
POST/api/checkoutInitiate checkout.
GET/api/posts/[id]/statsPer-post analytics (host-only).
GET/api/stories/[id]/rewatchFree rewatch analytics (host-only).
GET/api/stories/[id]/analyticsCombined story analytics.

Pro AI Smart Reply

MethodPathPurpose
POST/api/comments/[id]/smart-replyGenerate a Pro-tier AI reply for a comment you own. Gated by fn_consume_feature_quota('ai_smart_reply'). Pro 400/month cap enforced.
Errors: 401 auth, 403 quota_denied or not_host_owner, 404 not_found, 429 monthly cap reached, 500 model unavailable.

Comment-keyword lead magnet

MethodPathPurpose
GET/api/keyword-rulesList your rules across all hosts you own.
POST/api/keyword-rulesCreate a rule. Tier-gated to premium_seller+.
PATCH/api/keyword-rules/[id]Update a rule.
DELETE/api/keyword-rules/[id]Delete (audit log preserved).
GET/api/keyword-rules/[id]/firesLast 50 fires for a rule.

Auth

MethodPathPurpose
POST/api/auth/loginEmail + password / OTP / OAuth.
POST/api/auth/logoutEnd session.
POST/api/auth/refreshRefresh tokens.
POST/api/auth/mfa/enroll-totpBegin TOTP enrolment.
POST/api/auth/mfa/verify-enrolComplete enrolment.
POST/api/auth/mfa/verify-stepupStep-up verification.
POST/api/auth/passkey/beginBegin passkey ceremony.
POST/api/auth/passkey/completeComplete passkey ceremony.
GET/api/auth/auditRecent security events for the caller.

GraphQL

Available at https://xavio.in/graphql/v1 via pg_graphql.

  • Schema derives directly from the public Postgres schema, filtered
through the `omit_in_schema` directive so internal columns / tables don't leak.
  • Auth: same cookie session as the REST API.
  • Connection-style pagination on every collection (*Collection types
with `edges`, `pageInfo`, `node`).
  • POST body size cap: 32 KB (over-large queries get 413). For
larger queries, use REST endpoints or filter server-side.
  • Rate limit: 600 requests / minute / authenticated user (same as
REST).

For Apollo Client setup: type policies are documented in graphql_llm_tweaks.md in our internal memory; the practical takeaway is that pg_graphql v1.5.x generates PascalCase type names (e.g. Dots not dots), and connection-style merge functions are strongly recommended for paginated reads.

Rate limits

Endpoint familyAnonymousAuthenticatedNotes
/api/ucp/llm-discovery60 / min / IP—Cached at the edge for 5 min.
/api/ucp/* (signed)—Per-key quotaNegotiated per integration.
/api/engagement/event100 / min / IP600 / min / IPAnonymous allowed for read-only kinds only.
/api/engagement/* (writes)—600 / minPer-IP and per-user.
/api/products and other commerce—600 / min
/graphql/v1—600 / minBody capped at 32 KB.
/api/dot/v1/collect100 / min / IP—Public ingest; dedup by event_id.
/api/dot/v1/echo30 / min / IP—Debug endpoint.
/api/auth/login10 / min / IP—Aggressive.
/api/auth/audit—60 / min
All limits are token-bucket via Valkey. When you hit a limit you get a `429` with a `Retry-After` header in seconds.

Webhooks

Signing

Every webhook delivery carries an X-Nafafy-Signature header:

sha256=<hex_hmac>

The HMAC is computed over the raw request body using your webhook secret (issued at webhook setup time). Verify before processing.

A X-Nafafy-Timestamp header carries the dispatch time in ISO-8601. Reject requests where the timestamp is more than 5 minutes in the past to prevent replay.

Delivery semantics

  • At least once. Idempotency is your responsibility. Use the
delivery's `event_id` to dedupe.
  • Ordering not guaranteed. Two events about the same order may
arrive out of order. Reconcile on the merchant-side state.
  • Retries: exponential backoff over 24h, then paused.
  • Resume: dashboard manual resume after fix + an automatic test fire.

Inspecting deliveries

/dashboard/connectors/webhooks/<id>/deliveries shows every recent delivery with status, latency, response body, and a Replay action to re-fire.

Connectors

Pre-built integrations. Each connector is documented in detail in its own repo / store listing; this section is the orientation.

Shopify

  • Install: search "Xavio" in the Shopify App Store.
  • Capabilities: two-way product sync, two-way order sync, inventory
bridge, customer mapping, GST class mapping.
  • Auth: Shopify OAuth (we receive a delegated app token).
  • Pricing: bundled with Premium merchant+ on Xavio.
  • Common pattern: keep Shopify as source-of-truth for SKUs, use Xavio
as the demand-discovery and conversion surface.

WordPress / WooCommerce

  • Install: search "Xavio" in the WordPress plugin directory.
  • Capabilities: embed Xavio buttons on any page, sync WooCommerce
products to Xavio's catalogue, mirror orders.
  • Auth: WP nonce + Xavio API key.
  • Special: the plugin includes a Gutenberg block for the Xavio
storefront embed and a Classic Editor shortcode.

Zapier

  • Triggers: new_order, new_lead, new_booking.
  • Actions: create_lead, send_notification.
  • Search: find_product.
  • Auth: API key.
  • Tip: use the new_lead trigger to push leads into your CRM in
near-real-time without a webhook server.

n8n

  • Same triggers / actions / search as Zapier; self-hosted edition
publishes the node package on the n8n community registry.
  • Self-host control over the workflow runtime; identical Xavio shape.

MCP server

  • For AI agents that speak Model Context Protocol.
  • Exposes: catalog reads, lead writes, order placement (with mandate).
  • Auth: same signed-JWS UCP envelope, surfaced as MCP tool calls.
  • Install: see <https://xavio.in/developers/mcp>.

llms.txt and robots.txt

Xavio publishes both files and treats them as the authoritative crawler policy.

  • https://xavio.in/llms.txt — pointers for LLMs to the structured
UCP endpoints + the trust / guides surface.
  • https://xavio.in/robots.txt — per-UA block list.
Allowed UAs (search-time citation):

Googlebot, Bingbot, DuckDuckBot, OAI-SearchBot, ChatGPT-User, PerplexityBot, Perplexity-User, Claude-User, GoogleOther.

Blocked UAs (training-corpus):

GPTBot, ClaudeBot, anthropic-ai, Google-Extended, CCBot, FacebookBot, Meta-ExternalAgent, Applebot-Extended, Bytespider, Diffbot, omgili.

If you're building a crawler, request the appropriate UA and we'll add you to the allow list — provided your traffic is search-time citation and you respect canonical URLs.

LLM-first integration

Recommended path for an AI agent that wants to read Xavio data and optionally act on a user's behalf:

  1. Discovery: hit /api/ucp/llm-discovery (no auth) to understand
what's on Xavio right now.
  1. Capabilities: hit /api/ucp/capabilities to learn the story
component types and their schemas.
  1. Per-merchant context: request a UCP agent key from
`https://xavio.in/dev/keys`. The merchant approves your agent in their dashboard. You then call `/api/ucp/products?host=<slug>` with your signed JWS.
  1. User-scoped actions (lead capture, order placement): obtain a
**mandate** from the user via the in-app consent flow. The mandate becomes part of your JWS envelope and gates the write.
  1. Webhook receive: subscribe to lead.created, order.created,
etc. so you can close the loop in real time.

Key constraints to design around:

  • Idempotency: every UCP write accepts an Idempotency-Key
header. Reuse the same key for retries; we deduplicate on it for 24 hours.
  • Mandate expiry: mandates carry a hard expires_at. After
expiry, the user must re-authorise.
  • Spend ceilings: order mandates carry a max_spend_inr. Exceeding
it returns 403.
  • No silent fan-out: a mandate scoped to one merchant can't be
reused on another. Cross-merchant carts require separate mandates.

Error envelope

Every error response is shape:

`{ ok: false, error: <code>, message: <human-readable>, status: <int>, details?: <object> }`

Common codes:

CodeStatusMeaning
auth401Missing or invalid session.
forbidden403Authenticated but not allowed (RLS or gate).
not_found404Resource doesn't exist.
validation400Zod-validated body failed. details.issues carries the errors.
rule_cap_exceeded409Tier cap reached.
feature_locked403Feature not enabled on caller's tier.
quota_denied403 or 429Per-feature quota refused.
rate_limited429Per-minute IP / user cap hit. Retry-After header included.
invalid_json400Body parse failed.
idempotency_conflict409Same idempotency key with different payload.

Operational

  • Status: <https://xavio.in/status>
  • API changelog: <https://xavio.in/developers/changelog>
  • Deprecation policy: 6 months for breaking changes, with banner in
the developer portal + email to all keys.
  • SLA: 99.95% uptime for Company tier; best-effort below that.
  • Maintenance window: Saturday 02:00–06:00 IST (announced 7 days
ahead).

Security

  • All endpoints use TLS 1.2+. HSTS preload.
  • API keys are issued via the developer portal; rotate from there.
  • We do not store card data — payment is via Razorpay / Cashfree /
PhonePe; PCI scope sits with them.
  • Server-side secrets are AEAD-encrypted at rest in the Postgres vault
extension.
  • Audit log: every API key creation, revocation, mandate issue, and
write action is logged. Exportable for SOC 2 evidence.
  • Vulnerability disclosure: <security at xavio.in> with PGP key on the
trust page.

Webhooks signature reference

Generate the expected signature on your side:

expected = "sha256=" + hex(hmac_sha256(secret, raw_request_body))

Compare with X-Nafafy-Signature using a constant-time comparison. Reject the request if they differ.

Constant-time comparison matters — string-equality comparison leaks timing information about the secret prefix.

Sandbox

A sandbox environment with seed data is available at <https://sandbox.xavio.in>. It mirrors the production API shape with test merchant accounts pre-loaded. Use sandbox API keys (issued from the dev portal in sandbox mode) and a Razorpay test key for end-to-end payment testing.

FAQ

Where do I get API keys? <https://xavio.in/dev/keys>. You'll need a Xavio account.

How do I become an approved agent for a specific merchant? The merchant approves you from their dashboard at /dashboard/connectors/agents. They see your agent name, the scopes you requested, and click Approve / Deny / Revoke.

Can I get bulk catalog access without per-merchant approval? Yes — public storefronts publish their catalog under /api/ucp/products?host=<slug> for any valid signed JWS. Read-only. Write actions always require a merchant-issued mandate.

Is there an SDK? Not yet. The shape is intentionally HTTP + JSON + standard JWS so any language can integrate. SDKs (Python, TypeScript, Go) are on the roadmap; once they ship, they will live at https://xavio.in/developers/sdks.

Can I get a longer-lived agent key? Default agent keys live 90 days. Longer-lived keys (1 year) are available under contract — talk to <partnerships at xavio.in>.

Does Xavio support OAuth for delegated access? Not at the standard API level. The UCP mandate model handles delegated access today. OAuth 2.1 is on the roadmap for partner integrations that need it.

How do I report a vulnerability? Email <security at xavio.in> with the PGP key from <https://xavio.in/.well-known/security.txt>. We'll respond within 1 business day.

Where to go next

  • <https://xavio.in/developers> — the live developer portal.
  • <https://xavio.in/dev/keys> — issue / rotate API keys.
  • <https://xavio.in/llms.txt> — the LLM-discovery pointer file.
  • <https://xavio.in/status> — operational status.
  • <https://xavio.in/developers/changelog> — API changelog.
  • Users — for buyer-side context.
  • Sellers — for what your merchant integration unlocks.
  • Companies — for B2B + enterprise contract terms.

Frequently asked questions

Does Nafafy have a public API?

Yes. Nafafy exposes signed UCP endpoints for agent/server-to-server commerce (catalogue, search, knowledge/RAG, quote, checkout), plus webhooks and connectors. AI agents can self-register at /api/ucp/agents/register and discover the catalogue at /api/ucp/llm-discovery.

How do AI agents buy on Nafafy?

Through the UCP (Universal Commerce Protocol) layer: agents discover products via signed endpoints, request quotes, and complete authorized purchases using spending mandates. Nafafy is agent-ready — it advertises tools via llms.txt and a WebMCP tool registrar.