# Other **Category:** Store **Base URL:** `/store/analytics` **Authentication:** Mixed **Routes:** 26 routes documented ## Overview This section documents 26 API routes for other. ## Quick Reference | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/store/analytics/config` | GET /store/analytics/config Returns analytics configuration ... | | POST | `/store/attentive/opt-in` | POST /store/attentive/opt-in Explicit SMS opt-in when custom... | | GET | `/store/banners` | GET /store/banners?store_handle=vnsh Returns the banners tha... | | GET | `/store/bundle-products/:id` | No description | | GET | `/store/content-pages` | GET /store/content-pages?slug=shipping-policy Returns one op... | | GET | `/store/custom` | No description | | POST | `/store/flow-builder/accept` | No description | | GET | `/store/flow-builder/button/:buttonId` | // GET /store/flow-builder/button/:buttonId - Get button det... | | POST | `/store/flow-builder/decline` | No description | | POST | `/store/flow-builder/init` | No description | | POST | `/store/flow-builder/init-with-order` | No description | | GET | `/store/flow-builder/receipt` | // GET /store/flow-builder/receipt - Get receipt for current... | | GET | `/store/membership/status` | GET /store/membership/status?order_id= Returns FLP/TRN m... | | POST | `/store/oauth/token` | No description | | POST | `/store/payment-intent/update-amount` | POST /store/payment-intent/update-amount Updates a Stripe Pa... | | GET | `/store/payment-methods/:account_holder_id` | GET /store/payment-methods/:account_holder_id List the saved... | | POST | `/store/payment-methods/:account_holder_id` | POST /store/payment-methods/:account_holder_id Save (vault) ... | | DELETE | `/store/payment-methods/:account_holder_id/:method_id` | DELETE /store/payment-methods/:account_holder_id/:method_id ... | | GET | `/store/payment-sessions` | GET /store/payment-sessions List payment sessions for a coll... | | DELETE | `/store/payment-sessions` | DELETE /store/payment-sessions Delete specific payment sessi... | | POST | `/store/payment/confirm-with-token` | POST /store/payment/confirm-with-token Stripe's recommended ... | | GET | `/store/products/:id/pdp-sections` | GET /store/products/:id/pdp-sections Get visible PDP section... | | GET | `/store/products/:id/reviews` | No description | | GET | `/store/products/:id/subscription-offer` | No description | | POST | `/store/products/:id/track-view` | POST /store/products/:id/track-view Storefront product-page ... | | POST | `/store/reviews` | No description | | GET | `/store/sites/by-domain` | No description | | POST | `/store/tracking/events` | No description | --- ## GET Store Analytics Config **Endpoint:** `GET /store/analytics/config` **Authentication:** Customer (Optional) ### Description GET /store/analytics/config Returns analytics configuration for frontend SDK initialization Only exposes public-safe credentials (appId, trackingDomain) Never exposes API keys or secrets ### Response **Success:** ```typescript { provider, config, } ``` **Also returns:** ```typescript { provider, config, } ``` **Also returns:** ```typescript { provider, config, } ``` **Error (500):** ```typescript { error, message, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/analytics/config' \ -H 'Content-Type: application/json' ``` --- ## POST Store Attentive Opt-in **Endpoint:** `POST /store/attentive/opt-in` **Authentication:** Customer (Optional) ### Description POST /store/attentive/opt-in Explicit SMS opt-in when customer checks the "Get 10% off" checkbox. This is the ONLY place Attentive sync should happen during checkout. Returns the phone that was synced so frontend can track it and avoid duplicates. ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response **Success:** ```typescript { success, skipped, message, } ``` **Also returns:** ```typescript { success, skipped, message, } ``` **Also returns:** ```typescript { success, syncedPhone, isNew, } ``` **Also returns:** ```typescript { success, error, } ``` **Error (400):** ```typescript { error, } ``` **Error (500):** ```typescript { success, error, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/attentive/opt-in' \ -H 'Content-Type: application/json' ``` --- ## GET Store Banners **Endpoint:** `GET /store/banners` **Authentication:** Customer (Optional) ### Description GET /store/banners?store_handle=vnsh Returns the banners that are live RIGHT NOW for one storefront, highest priority first. Scheduling lives in the banner module (see resolveWindow): a banner uses its own window when set, otherwise it inherits its CAMPAIGN's window — OmniCart promotions carry no dates at all, only campaigns do — and a banner with neither is treated as inactive rather than always-on. The active/inactive decision is made HERE rather than by the storefront so a cached client bundle can never keep showing a finished sale. ### Response **Success:** ```typescript { banners, } ``` **Also returns:** ```typescript { banners, } ``` **Also returns:** ```typescript { banners, } ``` **Also returns:** ```typescript { banners, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/banners' \ -H 'Content-Type: application/json' ``` --- ## GET Store Bundle-products :id **Endpoint:** `GET /store/bundle-products/:id` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Response **Success:** ```typescript { bundle_product, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/bundle-products/:id' \ -H 'Content-Type: application/json' ``` --- ## GET Store Content-pages **Endpoint:** `GET /store/content-pages` **Authentication:** Customer (Optional) ### Description GET /store/content-pages?slug=shipping-policy Returns one operator-edited page, or null. WHY NULL AND NOT 404 -------------------- `{ page: null }` with a 200 is the contract. The storefront still ships the original copy for each of these routes and falls back to it whenever this returns null, so an unseeded database, a typo'd slug and a page that has been deleted all degrade to "the site looks exactly as it does today". A 404 would make the storefront choose between rendering an error page and swallowing an exception, and the wrong choice there is a blank policy page — which for legal copy is worse than stale copy. The published/unpublished decision is made HERE rather than by the storefront so a cached client bundle can never reveal a draft. ### Response **Success:** ```typescript { page, } ``` **Also returns:** ```typescript { page, } ``` **Also returns:** ```typescript { page, preview_locked, } ``` **Also returns:** ```typescript { page, } ``` **Also returns:** ```typescript { page, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/content-pages' \ -H 'Content-Type: application/json' ``` --- ## GET Store Custom **Endpoint:** `GET /store/custom` **Authentication:** Customer (Optional) ### Response The handler does not return an object literal, so the response shape is not derivable from the source. ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/custom' \ -H 'Content-Type: application/json' ``` --- ## POST Store Flow-builder Accept **Endpoint:** `POST /store/flow-builder/accept` **Authentication:** Customer (Optional) ### Request Body | Field | Type | Required | |-------|------|----------| | `button_id` | string | Yes | | `cart_id` | string | No | ### Response **Success:** ```typescript { next_button, redirect_url, is_terminal, } ``` **Error (400):** ```typescript { error, } ``` **Error (404):** ```typescript { error, } ``` **Error (400):** ```typescript { error, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/flow-builder/accept' \ -H 'Content-Type: application/json' ``` --- ## GET Store Flow-builder Button :buttonId **Endpoint:** `GET /store/flow-builder/button/:buttonId` **Authentication:** Customer (Optional) ### Description // GET /store/flow-builder/button/:buttonId - Get button details ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `buttonId` | string | Yes | ButtonId identifier | ### Response **Success:** ```typescript { button, session, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/flow-builder/button/:buttonId' \ -H 'Content-Type: application/json' ``` --- ## POST Store Flow-builder Decline **Endpoint:** `POST /store/flow-builder/decline` **Authentication:** Customer (Optional) ### Request Body | Field | Type | Required | |-------|------|----------| | `button_id` | string | Yes | ### Response **Success:** ```typescript { next_button, redirect_url, is_terminal, } ``` **Error (400):** ```typescript { error, } ``` **Error (404):** ```typescript { error, } ``` **Error (400):** ```typescript { error, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/flow-builder/decline' \ -H 'Content-Type: application/json' ``` --- ## POST Store Flow-builder Init **Endpoint:** `POST /store/flow-builder/init` **Authentication:** Customer (Optional) ### Request Body | Field | Type | Required | |-------|------|----------| | `flow_id` | string | Yes | | `cart_id` | string | No | ### Response **Success (201):** ```typescript { session, entry_button, } ``` **Error (400):** ```typescript { error, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/flow-builder/init' \ -H 'Content-Type: application/json' ``` --- ## POST Store Flow-builder Init-with-order **Endpoint:** `POST /store/flow-builder/init-with-order` **Authentication:** Customer (Optional) ### Request Body | Field | Type | Required | |-------|------|----------| | `flow_id` | string | Yes | | `cart_id` | string | Yes | | `order_id` | string | Yes | | `payment_collection_id` | string | Yes | | `original_order_total` | number | Yes | ### Response **Success:** ```typescript { session, entry_button, } ``` **Error (400):** ```typescript { error, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/flow-builder/init-with-order' \ -H 'Content-Type: application/json' ``` --- ## GET Store Flow-builder Receipt **Endpoint:** `GET /store/flow-builder/receipt` **Authentication:** Customer (Optional) ### Description // GET /store/flow-builder/receipt - Get receipt for current session ### Response **Success:** ```typescript { receipt, } ``` **Error (400):** ```typescript { error, } ``` **Error (404):** ```typescript { error, } ``` **Error (400):** ```typescript { error, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/flow-builder/receipt' \ -H 'Content-Type: application/json' ``` --- ## GET Store Membership Status **Endpoint:** `GET /store/membership/status` **Authentication:** Customer (Optional) ### Description GET /store/membership/status?order_id= Returns FLP/TRN membership credentials stored in order metadata. Used by the storefront checkout-success page to display the password. ### Response **Success:** ```typescript { membership, } ``` **Error (400):** ```typescript { message, } ``` **Error (404):** ```typescript { message, } ``` **Error (500):** ```typescript { message, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/membership/status' \ -H 'Content-Type: application/json' ``` --- ## POST Store Oauth Token **Endpoint:** `POST /store/oauth/token` **Authentication:** Customer (Optional) ### Request Body | Field | Type | Required | |-------|------|----------| | `grant_type` | unknown | Yes | | `client_id` | string | Yes | | `client_secret` | string | Yes | | `scope` | string | No | ### Response **Error (400):** ```typescript { error, details, } ``` **Error (401):** ```typescript { error, message, } ``` **Error (400):** ```typescript { error, message, } ``` **Error (500):** ```typescript { error, message, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/oauth/token' \ -H 'Content-Type: application/json' ``` --- ## POST Store Payment-intent Update-amount **Endpoint:** `POST /store/payment-intent/update-amount` **Authentication:** Customer (Optional) ### Description POST /store/payment-intent/update-amount Updates a Stripe PaymentIntent's amount without changing the clientSecret. This allows updating the cart total (e.g., after tax/shipping calculation) without remounting Stripe Elements and losing user input. Critical for Express Checkout flows (Apple Pay/Google Pay) where we need to update the amount based on shipping address changes (tax calculation). Uses custom StripeProviderService which extends the platform's Stripe provider with additional methods for PaymentIntent updates. Stripe allows updating PaymentIntent amounts as long as the status is 'requires_payment_method', 'requires_confirmation', or 'requires_action'. ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response **Success (200):** ```typescript { success, updated, amount, message, } ``` **Also returns (200):** ```typescript { success, updated, previousAmount, newAmount, status, clientSecret, } ``` **Error (400):** ```typescript { error, } ``` **Error (404):** ```typescript { error, } ``` **Error (500):** ```typescript { error, } ``` **Error (400):** ```typescript { error, currentStatus, } ``` **Error (400):** ```typescript { error, type, } ``` **Error (500):** ```typescript { error, message, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/payment-intent/update-amount' \ -H 'Content-Type: application/json' ``` --- ## GET Store Payment-methods :account_holder_id **Endpoint:** `GET /store/payment-methods/:account_holder_id` **Authentication:** Customer (Optional) ### Description GET /store/payment-methods/:account_holder_id List the saved payment methods for the authenticated customer's account holder. Ownership is enforced (see resolveOwnedAccountHolder) — a customer can only ever list their OWN account holder's methods. ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `account_holder_id` | string | Yes | Account_holder_id identifier | ### Response **Success:** ```typescript { payment_methods, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/payment-methods/:account_holder_id' \ -H 'Content-Type: application/json' ``` --- ## POST Store Payment-methods :account_holder_id **Endpoint:** `POST /store/payment-methods/:account_holder_id` **Authentication:** Customer (Optional) ### Description POST /store/payment-methods/:account_holder_id Save (vault) a payment method against the authenticated customer's account holder, so it can later be charged by reference (subscriptions read subscription.payment_context.payment_method_reference — the returned `id` is that reference). Provider-agnostic: this forwards to the payment module's createPaymentMethods, which delegates to the provider's optional `savePaymentMethod` hook. `data` is the PAN-free, provider-specific token payload the storefront collected client-side (Hyperswitch SDK payment_method / setup token, Stripe SetupIntent payment_method, …). No raw card data is handled here. ⚠️ Provider hook: the vendored Hyperswitch provider NOW implements `savePaymentMethod` — it mints/attaches the token payload to the account holder's HS customer and returns the vaulted method id. The 501 branch below is a defensive fallback: the payment module wrapper still returns `{}` (id: undefined) for ANY provider that lacks the hook, so we surface that as NOT_IMPLEMENTED rather than pretending a method was vaulted. For Hyperswitch it will not fire. ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `account_holder_id` | string | Yes | Account_holder_id identifier | ### Request Body | Field | Type | Required | |-------|------|----------| | `data` | record | No | ### Response **Success (201):** ```typescript { payment_method, reference, } ``` **Error (501):** ```typescript { type, message, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/payment-methods/:account_holder_id' \ -H 'Content-Type: application/json' ``` --- ## DELETE Store Payment-methods :account_holder_id :method_id **Endpoint:** `DELETE /store/payment-methods/:account_holder_id/:method_id` **Authentication:** Customer (Optional) ### Description DELETE /store/payment-methods/:account_holder_id/:method_id Detach a saved payment method from the authenticated customer's account holder. Ownership of the account holder is enforced first (resolveOwnedAccountHolder) so a customer can never delete a method attached to another customer's account holder. Forwards to the payment module's deletePaymentMethods, which delegates to the provider's optional `deletePaymentMethod` hook. ⚠️ Provider hook: the vendored Hyperswitch provider NOW implements `deletePaymentMethod` and really detaches the method at the gateway. It ALSO enforces method ownership a second time inside the hook — it lists the account holder's own HS methods and refuses (NOT_FOUND) any method_id that is not among them, so a caller who owns this account holder still cannot delete a method belonging to another customer's HS customer. (Providers without the hook remain a silent 200 no-op.) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `account_holder_id` | string | Yes | Account_holder_id identifier | | `method_id` | string | Yes | Method_id identifier | ### Response **Success:** ```typescript { id, object, deleted, } ``` ### Example Request ```bash curl -X DELETE 'https://your-store.omnicart.cc/store/payment-methods/:account_holder_id/:method_id' \ -H 'Content-Type: application/json' ``` --- ## GET Store Payment-sessions **Endpoint:** `GET /store/payment-sessions` **Authentication:** Customer (Optional) ### Description GET /store/payment-sessions List payment sessions for a collection with filters ### Response **Success:** ```typescript { sessions, count, collection_id, } ``` **Error (400):** ```typescript { message, } ``` **Error (500):** ```typescript { message, error, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/payment-sessions' \ -H 'Content-Type: application/json' ``` --- ## DELETE Store Payment-sessions **Endpoint:** `DELETE /store/payment-sessions` **Authentication:** Customer (Optional) ### Description DELETE /store/payment-sessions Delete specific payment sessions with retry logic ### Response **Success:** ```typescript { success, deleted, failed, errors, metadata, } ``` **Error (400):** ```typescript { message, } ``` **Error (400):** ```typescript { message, } ``` **Error (500):** ```typescript { message, error, } ``` ### Example Request ```bash curl -X DELETE 'https://your-store.omnicart.cc/store/payment-sessions' \ -H 'Content-Type: application/json' ``` --- ## POST Store Payment Confirm-with-token **Endpoint:** `POST /store/payment/confirm-with-token` **Authentication:** Customer (Optional) ### Description POST /store/payment/confirm-with-token Stripe's recommended two-step confirmation flow for one-page checkouts: 1. Client creates ConfirmationToken (contains payment method + billing details) 2. Server creates PaymentIntent with FINAL amount (after tax calculation) 3. Server confirms payment using ConfirmationToken This avoids updating PaymentIntent amounts which can cause Elements to remount. Reference: https://docs.stripe.com/payments/accept-a-payment-deferred ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response **Success (200):** ```typescript { success, paymentIntent, } ``` **Error (400):** ```typescript { error, } ``` **Error (404):** ```typescript { error, } ``` **Error (400):** ```typescript { error, } ``` **Error (500):** ```typescript { error, } ``` **Error (400):** ```typescript { error, type, code, } ``` **Error (400):** ```typescript { error, type, } ``` **Error (500):** ```typescript { error, message, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/payment/confirm-with-token' \ -H 'Content-Type: application/json' ``` --- ## GET Store Products :id Pdp-sections **Endpoint:** `GET /store/products/:id/pdp-sections` **Authentication:** Customer (Optional) ### Description GET /store/products/:id/pdp-sections Get visible PDP sections for a product (storefront) Reads from product.metadata.pdp_sections ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Response **Success:** ```typescript { sections, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/products/:id/pdp-sections' \ -H 'Content-Type: application/json' ``` --- ## GET Store Products :id Reviews **Endpoint:** `GET /store/products/:id/reviews` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Response **Success:** ```typescript { reviews, count, limit, offset, average_rating, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/products/:id/reviews' \ -H 'Content-Type: application/json' ``` --- ## GET Store Products :id Subscription-offer **Endpoint:** `GET /store/products/:id/subscription-offer` **Authentication:** Customer (Optional) ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Response The handler does not return an object literal, so the response shape is not derivable from the source. ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/products/:id/subscription-offer' \ -H 'Content-Type: application/json' ``` --- ## POST Store Products :id Track-view **Endpoint:** `POST /store/products/:id/track-view` **Authentication:** Customer (Optional) ### Description POST /store/products/:id/track-view Storefront product-page view emitter. Publishes a `product.viewed` event onto the platform event bus; the existing `attentive-product-viewed` subscriber listens for it and pushes the "Product Viewed" custom event to Attentive. Why this route exists: `product.viewed` is NOT a built-in platform event. It only fires when this endpoint is hit, typically once per product page mount on the storefront. The Attentive subscriber maintains its own 5-minute in-memory dedup per (product, customer) pair, so rapid page refreshes / re-mounts won't flood Attentive. ### URL Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Id identifier | ### Request Body | Field | Type | Required | |-------|------|----------| | `variant_id` | string | No | ### Response **Success:** ```typescript { success, } ``` **Also returns:** ```typescript { success, } ``` **Error (400):** ```typescript { error, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/products/:id/track-view' \ -H 'Content-Type: application/json' ``` --- ## POST Store Reviews **Endpoint:** `POST /store/reviews` **Authentication:** Customer (Optional) ### Request Body | Field | Type | Required | |-------|------|----------| | `title` | string | No | | `content` | string | Yes | | `rating` | number | Yes | | `product_id` | string | Yes | | `first_name` | string | Yes | | `last_name` | string | Yes | ### Response The handler does not return an object literal, so the response shape is not derivable from the source. ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/reviews' \ -H 'Content-Type: application/json' ``` --- ## GET Store Sites By-domain **Endpoint:** `GET /store/sites/by-domain` **Authentication:** Customer (Optional) ### Response **Success:** ```typescript { site, } ``` **Also returns:** ```typescript { site, } ``` ### Example Request ```bash curl -X GET 'https://your-store.omnicart.cc/store/sites/by-domain' \ -H 'Content-Type: application/json' ``` --- ## POST Store Tracking Events **Endpoint:** `POST /store/tracking/events` **Authentication:** Customer (Optional) ### Request Body This route does not declare a validation schema, so the accepted fields are not derivable from the source. Check the handler before relying on a particular body. ### Response **Success (202):** ```typescript { accepted, event_id, } ``` **Also returns (202):** ```typescript { accepted, event_id, } ``` **Error (400):** ```typescript { accepted, reason, } ``` **Error (400):** ```typescript { accepted, reason, } ``` ### Example Request ```bash curl -X POST 'https://your-store.omnicart.cc/store/tracking/events' \ -H 'Content-Type: application/json' ``` ---