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 case | Best surface |
|---|---|
| Read a merchant's product catalog | UCP per-merchant (/api/ucp/products) |
| Read top stories + storefronts for citation | UCP discovery (/api/ucp/llm-discovery) |
| Track conversions from external sites | Xavio Dot pixel + /api/pixel/v1/collect |
| Sync Shopify orders + inventory both ways | Shopify connector app |
| Embed Xavio buttons on a WordPress site | WP plugin |
| No-code workflow (lead → CRM → Slack) | Zapier or n8n connector |
| Place an order from an AI agent | UCP capture flow with signed JWS |
| Mirror pixel events to your Meta CAPI / GA4 | Built into Dot configuration |
| Listen to merchant events in real time | Webhooks (HMAC-signed) |
| Query catalog with GraphQL | /graphql/v1 (pg_graphql) |
Surfaces
Xavio exposes four primary integration surfaces:
- UCP (Unified Commerce Protocol) — signed-envelope REST + GraphQL
- Cookie-session REST — the same
/api/*paths the web app uses,
- Pixel (Xavio Dot) — drop-in JavaScript snippet for cross-site
- Connectors — pre-built integrations (Shopify, WP, Zapier, n8n,
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.
Cookie session (browser apps + embeds)
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/loginflow (xv_session_*). - CORS: First-party only by default; restricted-origin policy on
- Session lifetime: 30 days sliding, 5-minute MFA freshness for
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
- Issuer: agent keys minted by you at
- Verifier: our server validates against the key ring + replay-window
- Key rotation: keys carry an explicit expiry; supports overlap window.
- Rate limit: per-key, configurable per integration agreement.
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
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/ucp/llm-discovery | None (public) | Top stories + storefronts + structured metadata. Edge-cached 5 min. |
| GET | /api/ucp/collections | None or signed | List storefronts (anonymous) or one storefront's collections (signed). |
| GET | /api/ucp/products | Signed | Product catalog for a storefront. Filter by category, in-stock, price range, etc. |
| GET | /api/ucp/capabilities | None | Describes every story component type — for LLMs to explain what a story does. |
| POST | /api/ucp/leads | Signed + mandate | Submit a lead form on behalf of a user. |
| POST | /api/ucp/capture | Signed + mandate | Place a purchase / booking / order on behalf of a user. |
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,
For booking:
host_id,booking_listing_id,preferred_at(ISO timestamp),
For rfq_accept:
quote_idand any custom acceptance fields the seller defined.
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.createdorder.created,order.paid,order.fulfilled,order.cancelled,
booking.created,booking.confirmed,booking.cancelledrfq.created,rfq.responded,rfq.acceptedinventory.updatedmerchant.approved_agent,merchant.revoked_agent
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:
| Cookie | Lifetime | Purpose |
|---|---|---|
_xvp | 90 days | First-party browser id |
_xvc | Session | Click-id (xvclid) bridging in-app → external |
_xv_external_id | 90 days (hashed) | SHA-256 of Xavio user id, when known |
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 whosename/id/autocomplete
block— fields containing any of these substrings are always skipped
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.
REST endpoints (cookie session)
The web app uses these. Browser-based embeds and dashboard integrations can use them with a valid session cookie.
Engagement
| Method | Path | Purpose |
|---|---|---|
| POST | /api/engagement/event | Log a single analytics event (view / tap / impression / etc.). Public; anon allowed for read-only kinds. |
| POST | /api/engagement/story-views | Record a story view. |
| POST | /api/engagement/story-likes | Like a story. |
| POST | /api/engagement/comments | Post a comment. |
| POST | /api/engagement/comment-likes | Like a comment. |
| POST | /api/engagement/follows | Follow a creator. |
| POST | /api/engagement/post-reactions | React to a post. |
| GET | /api/engagement/comment-suggestions | Get heuristic + AI reply suggestions for a post (free 3-chip suggestions, distinct from Pro AI Smart Reply). |
| POST | /api/engagement/notifications/read | Mark a notification read. |
| POST | /api/engagement/notifications/read-all | Mark all read. |
| POST | /api/engagement/notifications/seen | Mark notifications as seen. |
Commerce
| Method | Path | Purpose |
|---|---|---|
| GET / POST / PATCH / DELETE | /api/products | CRUD for products owned by the caller. |
| GET / POST / PATCH / DELETE | /api/services | Same for services. |
| GET / POST | /api/booking-listings | Booking listing CRUD. |
| GET / POST | /api/booking-listings/[id]/slots | List available slots. |
| GET / POST | /api/booking-requests | Customer-facing booking flow. |
| GET / POST | /api/orders | Place / list orders. |
| GET | /api/orders/[id] | Order detail. |
| POST | /api/orders/[id]/refund | Refund an order. |
| GET / POST | /api/cart | Buyer cart CRUD. |
| POST | /api/checkout | Initiate checkout. |
| GET | /api/posts/[id]/stats | Per-post analytics (host-only). |
| GET | /api/stories/[id]/rewatch | Free rewatch analytics (host-only). |
| GET | /api/stories/[id]/analytics | Combined story analytics. |
Pro AI Smart Reply
| Method | Path | Purpose |
|---|---|---|
| POST | /api/comments/[id]/smart-reply | Generate a Pro-tier AI reply for a comment you own. Gated by fn_consume_feature_quota('ai_smart_reply'). Pro 400/month cap enforced. |
Comment-keyword lead magnet
| Method | Path | Purpose |
|---|---|---|
| GET | /api/keyword-rules | List your rules across all hosts you own. |
| POST | /api/keyword-rules | Create 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]/fires | Last 50 fires for a rule. |
Auth
| Method | Path | Purpose |
|---|---|---|
| POST | /api/auth/login | Email + password / OTP / OAuth. |
| POST | /api/auth/logout | End session. |
| POST | /api/auth/refresh | Refresh tokens. |
| POST | /api/auth/mfa/enroll-totp | Begin TOTP enrolment. |
| POST | /api/auth/mfa/verify-enrol | Complete enrolment. |
| POST | /api/auth/mfa/verify-stepup | Step-up verification. |
| POST | /api/auth/passkey/begin | Begin passkey ceremony. |
| POST | /api/auth/passkey/complete | Complete passkey ceremony. |
| GET | /api/auth/audit | Recent 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
- Auth: same cookie session as the REST API.
- Connection-style pagination on every collection (
*Collectiontypes
- POST body size cap: 32 KB (over-large queries get 413). For
- Rate limit: 600 requests / minute / authenticated user (same as
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 family | Anonymous | Authenticated | Notes |
|---|---|---|---|
/api/ucp/llm-discovery | 60 / min / IP | — | Cached at the edge for 5 min. |
/api/ucp/* (signed) | — | Per-key quota | Negotiated per integration. |
/api/engagement/event | 100 / min / IP | 600 / min / IP | Anonymous allowed for read-only kinds only. |
/api/engagement/* (writes) | — | 600 / min | Per-IP and per-user. |
/api/products and other commerce | — | 600 / min | |
/graphql/v1 | — | 600 / min | Body capped at 32 KB. |
/api/dot/v1/collect | 100 / min / IP | — | Public ingest; dedup by event_id. |
/api/dot/v1/echo | 30 / min / IP | — | Debug endpoint. |
/api/auth/login | 10 / min / IP | — | Aggressive. |
/api/auth/audit | — | 60 / min |
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
- Ordering not guaranteed. Two events about the same order may
- 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
- 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
WordPress / WooCommerce
- Install: search "Xavio" in the WordPress plugin directory.
- Capabilities: embed Xavio buttons on any page, sync WooCommerce
- Auth: WP nonce + Xavio API key.
- Special: the plugin includes a Gutenberg block for the Xavio
Zapier
- Triggers:
new_order,new_lead,new_booking. - Actions:
create_lead,send_notification. - Search:
find_product. - Auth: API key.
- Tip: use the
new_leadtrigger to push leads into your CRM in
n8n
- Same triggers / actions / search as Zapier; self-hosted edition
- 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
https://xavio.in/robots.txt— per-UA block list.
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:
- Discovery: hit
/api/ucp/llm-discovery(no auth) to understand
- Capabilities: hit
/api/ucp/capabilitiesto learn the story
- Per-merchant context: request a UCP agent key from
- User-scoped actions (lead capture, order placement): obtain a
- Webhook receive: subscribe to
lead.created,order.created,
Key constraints to design around:
- Idempotency: every UCP write accepts an
Idempotency-Key
- Mandate expiry: mandates carry a hard
expires_at. After
- Spend ceilings: order mandates carry a
max_spend_inr. Exceeding
- No silent fan-out: a mandate scoped to one merchant can't be
Error envelope
Every error response is shape:
`{ ok: false, error: <code>, message: <human-readable>, status: <int>, details?: <object> }`
Common codes:
| Code | Status | Meaning |
|---|---|---|
auth | 401 | Missing or invalid session. |
forbidden | 403 | Authenticated but not allowed (RLS or gate). |
not_found | 404 | Resource doesn't exist. |
validation | 400 | Zod-validated body failed. details.issues carries the errors. |
rule_cap_exceeded | 409 | Tier cap reached. |
feature_locked | 403 | Feature not enabled on caller's tier. |
quota_denied | 403 or 429 | Per-feature quota refused. |
rate_limited | 429 | Per-minute IP / user cap hit. Retry-After header included. |
invalid_json | 400 | Body parse failed. |
idempotency_conflict | 409 | Same 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
- SLA: 99.95% uptime for Company tier; best-effort below that.
- Maintenance window: Saturday 02:00–06:00 IST (announced 7 days
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 /
- Server-side secrets are AEAD-encrypted at rest in the Postgres vault
- Audit log: every API key creation, revocation, mandate issue, and
- Vulnerability disclosure: <security at xavio.in> with PGP key on the
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
- 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.
- 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.