@tagadapay/headless-sdk
v1.13.1
Published
Headless SDK for using TagadaPay as a checkout, offers, and CRM backend from any external website
Readme
@tagadapay/headless-sdk
Use TagadaPay as a headless checkout and CRM backend from any website — React, Vue, vanilla JS, or plain HTML. Zero runtime dependencies in core.
This package is for when TagadaPay manages the cart. If you already have the order (Medusa, WooCommerce, a custom order API), do not use this SDK — tokenize with @tagadapay/core-js and charge with Node payments.process(). See Choose how you accept payments. Canonical example: headless-vanilla.
processPayment() pays a checkout session. Server payments.process() charges a vaulted instrument. They are not the same call.
Install
npm install @tagadapay/headless-sdk
# Optional: for card tokenization
npm install @tagadapay/core-jsQuick Start (Vanilla JS)
import { createHeadlessClient } from '@tagadapay/headless-sdk';
const tagada = createHeadlessClient({
storeId: 'store_abc123',
environment: 'production',
});
// Load checkout session
const session = await tagada.checkout.loadSession(checkoutToken, sessionToken);
// Set customer info (stored in memory, sent with address)
await tagada.checkout.updateCustomer(session.id, {
email: '[email protected]',
firstName: 'John',
lastName: 'Doe',
});
// Set address — customer fields are included automatically
await tagada.checkout.updateAddress(session.id, {
shippingAddress: { line1: '10 Rue de la Paix', city: 'Paris', postalCode: '75002', country: 'FR' },
});
// Tokenize card + pay with automatic 3DS / redirect handling
const { tagadaToken } = await tagada.payment.tokenizeCard({
cardNumber: '4242424242424242',
expiryDate: '12/28',
cvc: '123',
});
const result = await tagada.payment.processPayment({
checkoutSessionId: session.id,
tagadaToken,
});
if (result.status === 'succeeded') {
console.log('Payment succeeded!', result.order);
} else if (result.status === 'requires_redirect') {
// SDK handles this automatically in React; in vanilla JS, redirect manually:
window.location.href = result.redirectUrl;
} else if (result.status === 'failed') {
console.error(result.error);
}Quick Start (React)
import { TagadaHeadlessProvider, useCheckout, usePayment } from '@tagadapay/headless-sdk/react';
function App() {
return (
<TagadaHeadlessProvider storeId="store_abc123" environment="production">
<CheckoutPage />
</TagadaHeadlessProvider>
);
}
function CheckoutPage() {
const { session, updateCustomer, updateAddress } = useCheckout(checkoutToken, sessionToken);
const { processPayment, isProcessing, tokenizeCard } = usePayment({
onPaymentSuccess: (result) => router.push('/thank-you'),
onPaymentFailed: (result) => alert(result.error),
});
const handlePay = async () => {
// Customer + address (single atomic API call under the hood)
await updateCustomer({ email, firstName, lastName });
await updateAddress({ shippingAddress: { line1, city, postalCode, country } });
// Tokenize + pay — 3DS redirects and polling are handled automatically
const { tagadaToken } = await tokenizeCard({ cardNumber, expiryDate, cvc });
await processPayment({ checkoutSessionId: session.id, tagadaToken });
// onPaymentSuccess / onPaymentFailed callbacks fire automatically
};
return <button onClick={handlePay} disabled={isProcessing}>Pay Now</button>;
}Payment Flow
processPayment() handles the full payment lifecycle automatically:
- Tokenize → creates a payment instrument from the card
- Pay → submits payment to the processor
- 3DS / Redirect → if the bank requires authentication, the SDK redirects the user and resumes automatically on return
- Poll → waits for async processing to complete
- Result → returns a typed
ProcessPaymentResult
The return type is a discriminated union:
| Status | Meaning |
|--------|---------|
| succeeded | Payment confirmed. Show success screen. |
| requires_redirect | User must visit a URL (3DS, bank auth). Auto-handled in React. |
| failed | Payment declined or errored. result.error has details. |
| pending | Still processing (rare — polling timed out). |
Address Handling
The SDK handles both shipped and digital products:
// Shipped product — billing defaults to shipping
await tagada.checkout.updateAddress(sessionId, {
shippingAddress: { line1: '...', city: '...', country: 'FR' },
});
// Digital product — billing only, no shipping needed
await tagada.checkout.updateAddress(sessionId, {
billingAddress: { country: 'FR' },
});
// Separate billing and shipping
await tagada.checkout.updateAddress(sessionId, {
shippingAddress: { line1: '...', city: '...', country: 'FR' },
billingAddress: { line1: '...', city: '...', country: 'DE' },
});
// Or use the combined method
await tagada.checkout.updateCustomerAndAddress(sessionId, {
customer: { email: '[email protected]', firstName: 'John', lastName: 'Doe' },
shippingAddress: { line1: '...', city: '...', country: 'FR' },
});Funnel Navigation
Send a shopper into a TagadaPay funnel using the cart from the loaded checkout session — same flow as the WooCommerce / Shopify plugins, in one call.
const tagada = createHeadlessClient({
storeId: 'store_abc123',
accountId: 'acc_abc123', // required for funnel.navigate()
environment: 'production',
});
// Load (or create) a checkout session so the SDK has a cart.
await tagada.checkout.loadSession(checkoutToken, sessionToken);
// Get a funnel URL — caller decides how to redirect (SPA-friendly).
const { url } = await tagada.funnel.navigate({
funnelId: 'fnlv2_abc123',
stepId: 'step_abc123',
returnUrl: 'https://merchant.com/thank-you',
});
window.location.assign(url);funnel.navigate() bootstraps an anonymous CMS session on first call and
caches it for subsequent calls in the same page. The cart, currency, customer
email, and promotion code are sourced from the loaded CheckoutSession.
Modules
| Module | What it does |
|--------|-------------|
| tagada.checkout | Session management — load, update cart, promo codes, shipping |
| tagada.payment | Full payment lifecycle — APMs, tokenize, 3DS, pay, poll, express checkout |
| tagada.offers | Upsells & order bumps — preview, pay, post-purchase accept/decline |
| tagada.customer | CRM data — profile, orders, subscriptions |
| tagada.catalog | Product browsing — list products, variants, prices |
| tagada.funnel | Funnel navigation — bootstrap session and redirect into a funnel step |
React Hooks
One hook per page of a typical storefront:
| Hook | Built for |
|------|-----------|
| useCheckout(checkoutToken?, sessionToken?) | Checkout page — session, cart, addresses, promo, shipping. On a landing page pass null and use createSessionUrl on the CTA |
| usePayment(options?) | Payment form — tokenize, pay, automatic 3DS |
| useOffers(...) | Post-purchase offer pages — preview + one-click charge |
| useOrder(orderId) | Thank-you page — the order + relatedOrders from accepted upsells (watched automatically) |
| useCustomer(customerId?) | Account dashboard — profile, orders, subscriptions |
| useCatalog() | Product pages — products, variants, prices |
CDN Usage
<script src="https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk/dist/tagada-headless.min.js"></script>
<script>
const tagada = TagadaHeadless.create({ storeId: 'store_abc123' });
</script>Example
A complete React checkout app is available as a live demo and open-source reference:
- Live demo: headless-react-eta.vercel.app
- Source code: github.com/TagadaPay/examples/tree/main/headless-react
Architecture
- Zero dependencies in core — native
fetch, no axios - Tree-shakeable ESM — unused modules are eliminated by bundlers
- Framework-agnostic core + thin React hooks layer
- TypeScript first — full type coverage, JSDoc on every method
- Optional
@tagadapay/core-jspeer — only needed for client-side card tokenization - Automatic 3DS — handles redirects, iframe challenges, and polling out of the box
Package Exports
| Import path | What you get |
|------------|--------------|
| @tagadapay/headless-sdk | Core client + all modules |
| @tagadapay/headless-sdk/react | React hooks + provider |
License
MIT
