Add a shop to any website in minutes.
T2Shop gives you a hosted product catalog, shopping cart, and payments — all embedded on your existing website with a single script tag. No backend required.
Quick start
Go from signup to a live cart on your website in under 15 minutes.
- 01
- 02
Create your store
Give it a name and your website URL. You can have multiple stores later.
- 03
Add products
Go to Products → New product. Set a name, price, and stock count.
- 04
Embed the cart widget
Paste one script tag into your website. Works on any platform — Webflow, WordPress, plain HTML.
- 05
Connect your bank
Go to Payments → Connect Stripe. A quick onboarding form and you can start accepting payments.
Embed the cart
Choose how you integrate: script tag + global (no bundler) or npm package + createT2ShopWidgets (React, Next.js, Vite, etc.). The cart opens as a slide-over drawer. Logged-in merchants can copy snippets from the dashboard under Integration.
API URL & Store ID
Set apiBaseUrl to your T2Shop site origin (same host you use for the dashboard), e.g. https://your-store.t2shop.app. In the dashboard, go to Store → Settings and copy your Store ID for storeId.
<!-- Paste before </body> on every page. Use your hosted widget URL (see dashboard → Integration). -->
<script src="https://cdn.t2shop.dev/widget/latest/t2shop-widget.js" defer></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
T2ShopWidgets.config({
apiBaseUrl: "https://YOUR_T2SHOP_DOMAIN",
storeId: "YOUR_STORE_ID",
widgets: {
cart: true,
// Or pass options instead of true:
// cart: {
// elementName: "t2-cart-widget",
// theme: { primaryColor: "#2563eb", mode: "light" },
// ui: { floatingPlacement: "bottom-right", floatingSize: "sm" },
// },
},
});
});
</script>Connect it to your buttons
After the widget loads, you can call these from any button or link on your page:
// Cart is available only after config() with widgets.cart enabled.
// Optional: guard custom "Add to cart" buttons
if (!T2ShopWidgets.isCartWidgetEnabled()) return;
// Open / close the cart drawer
T2ShopWidgets.cart.open();
T2ShopWidgets.cart.close();
// Add a line item (image URL is required for the cart row)
await T2ShopWidgets.cart.addProduct({
productId: "YOUR_PRODUCT_ID",
image: "https://your-cdn.com/product.jpg",
quantity: 1,
});Product IDs are shown on each product in your dashboard. Use T2ShopWidgets.config once per page load; enable the cart with widgets: { cart: true }.
Static pages: inline name and price
If you hand-write a few product cards in HTML, you can pass name and price so the cart doesn't need an extra API call to show the line. Stock and checkout still use your T2Shop store.
// Small static sites: pass name + price yourself (no separate catalog API call for the line label)
await T2ShopWidgets.cart.addProduct({
productId: "YOUR_PRODUCT_ID",
name: "Handmade mug",
price: 24.99,
image: "https://your-cdn.com/mug.jpg",
quantity: 1,
});React, Next.js, or a bundler (npm)
Install t2-shop-widgets and call createT2ShopWidgets once per app. That gives you .products.get, .cart.addProduct, and an isolated HTTP client — not the global window.T2ShopWidgets.
Recommended: singleton module
Create one file (e.g. lib/t2shop-widget.ts) that exports a single widgetApi. Import it from your components instead of calling createT2ShopWidgets in every file. The reference implementation in the monorepo is t2shop-widget/app/widget-init.ts.
// Recommended: one module that creates a single SDK instance (singleton) and
// re-exports it. Import that module once at app startup (e.g. main.tsx / root layout client).
// Same pattern as the open-source demo: t2shop-widget/app/widget-init.ts
import { createT2ShopWidgets } from "t2-shop-widgets";
export const widgetApi = createT2ShopWidgets({
apiBaseUrl: "https://YOUR_T2SHOP_DOMAIN",
storeId: "YOUR_STORE_ID",
widgets: {
cart: {
theme: { primaryColor: "#2563eb", mode: "light" },
ui: { floatingPlacement: "bottom-right", floatingSize: "sm" },
},
},
});
// Elsewhere in your app:
// import { widgetApi } from "@/lib/t2shop-widget";
// await widgetApi.products.get({ pageSize: 50 });
// await widgetApi.cart.addProduct({ productId, image, quantity: 1 });One-off inline
If you only need the cart in one place, you can construct the instance inline:
// React, Next.js, Vite — install "t2-shop-widgets" and call createT2ShopWidgets once:
import { createT2ShopWidgets } from "t2-shop-widgets";
const shop = createT2ShopWidgets({
apiBaseUrl: "https://YOUR_T2SHOP_DOMAIN",
storeId: "YOUR_STORE_ID",
widgets: { cart: true },
});
await shop.cart.addProduct({
productId: "YOUR_PRODUCT_ID",
image: "https://your-cdn.com/product.jpg",
quantity: 1,
});Load products from the API (SDK)
If you build a custom grid or search (not only static HTML cards), the SDK can fetch your store catalog from the same public endpoint as the cart: GET /api/public/v1/products. Call .products.get after config or on a createT2ShopWidgets instance.
Query parameters
page— 1-based page number (omit for server default, typically page 1).pageSize— how many products per page (API allows 1–100).search— optional filter (name/slug search on the server).status—DRAFT|ACTIVE|ARCHIVED; the SDK defaults toACTIVEif omitted.
Response: items (this page), total (matching rows across all pages), page, pageSize — use total with pageSize to build pagination UI (Math.ceil(total / pageSize) pages).
Global embed
// After T2ShopWidgets.config(...) — wraps GET /api/public/v1/products
// page = 1-based page index; pageSize = 1–100 per request; search = filter by name/slug
const { items, total, page, pageSize } = await T2ShopWidgets.products.get({
status: "ACTIVE",
page: 1,
pageSize: 20,
search: "mug",
});npm / createT2ShopWidgets (singleton)
Example hook pattern: t2shop-widget/app/hooks/use-store-catalog.tsx
// With createT2ShopWidgets → widgetApi (widgets/products/sdk.ts)
const { items, total, page, pageSize } = await widgetApi.products.get({
status: "ACTIVE",
page: 2,
pageSize: 20,
search: "desk",
});Pagination & search
Increase page for “next page”; combine with search for filtered lists.
// Pagination: use response.total and pageSize to compute pages (e.g. Math.ceil(total / pageSize))
const pageSize = 20;
let page = 1;
const { items, total, page: currentPage } = await widgetApi.products.get({
status: "ACTIVE",
page,
pageSize,
});
const totalPages = Math.max(1, Math.ceil(total / pageSize));
// Next page: await widgetApi.products.get({ ...params, page: currentPage + 1, pageSize });Managing products
Creating a product
Go to Products → New product. Fill in the name, price, and stock count. Set the status to Active when you're ready for it to appear in your cart.
Product status
Draft products are hidden from your cart. Active products appear immediately. Archive a product to hide it without deleting it.
Stock tracking
T2Shop tracks stock automatically. When stock reaches 0, the product is no longer purchasable in the cart.
Accepting payments
T2Shop uses Stripe to process payments. Each store connects its own Stripe account — money goes directly to your bank without passing through T2Shop.
1. Connect Stripe
From your dashboard, go to Payments and click Connect Stripe. You'll be walked through a short Stripe onboarding — takes about 5 minutes.
2. Enter bank details
Stripe will ask for your bank account information so payouts can be deposited directly. This is handled entirely by Stripe — T2Shop never sees your bank details.
3. Start accepting payments
Once onboarding is complete, your cart widget will accept card payments. Payouts are deposited to your bank on a rolling 2-day schedule.
Test mode
While testing, use the Stripe test card 4242 4242 4242 4242 with any future expiry and any 3-digit CVC.
Allowed domains
For security, your cart widget only works on domains you explicitly allow. This prevents anyone else from embedding your store on their website.
How to add your domain
- 1. In the dashboard, go to Store → Security
- 2. Under Trusted Origins, enter your website URL
- 3. Save — the cart will work on that domain immediately
Cart not loading?
If the cart silently fails, check that your website's exact domain (including https://) is listed in Trusted Origins. Both www and non-www versions must be added separately.
Viewing orders
Every checkout from your cart widget creates an order in your dashboard.
Order statuses
Pending → Requires payment → Paid → Fulfilled. You can see the full status timeline on each order's detail page.
Customer details
Each order shows the customer's name, email, and what they ordered. Use this to fulfil physical goods or trigger your own notifications.
Payment records
The payment section of each order shows the Stripe payment ID and amount. Use this for refund disputes or reconciliation.
Go-live checklist
Run through this before accepting your first real payment.
- Account created and verifiedDone
- Store created with a name and site URLDone
- At least one product set to ActiveDone
- Widget script added to your websiteDone
- Your website domain added under Store → Security → Trusted Origins
- Stripe account connected from Payments → Connect Stripe
- Test checkout from your live website