@linkpe-storefront/sdk
v0.1.0
Published
Official TypeScript SDK for building custom storefronts on the MyLinkpe Storefront API.
Maintainers
Readme
@linkpe-storefront/sdk
Official TypeScript SDK for building custom storefronts on the MyLinkpe Storefront API v1.
npm install @linkpe-storefront/sdkQuick start
import { LinkpeClient } from '@linkpe-storefront/sdk';
const linkpe = new LinkpeClient({
keyId: process.env.LINKPE_KEY_ID!,
keySecret: process.env.LINKPE_KEY_SECRET!,
// baseUrl defaults to https://api.mylinkpe.in
});
const store = await linkpe.store.get();
const products = await linkpe.products.list({ limit: 12 });
const product = await linkpe.products.get('prod_xxx');⚠ Security
Never expose keySecret in a browser bundle. The key pair grants full storefront access.
Use this SDK on a server (Next.js Route Handlers, Express, Cloudflare Workers, Bun, Deno, etc.) and proxy customer-facing operations through your own backend.
┌────────────┐ ┌─────────────────┐ ┌────────────────┐
│ Browser │ ─→ │ Your backend │ ─→ │ MyLinkpe API │
│ (no key) │ │ (uses this SDK) │ │ │
└────────────┘ └─────────────────┘ └────────────────┘Cart model
The SDK does NOT manage cart state. Cart lives in your frontend (cookie, localStorage, JWT — your choice). At checkout you pass the items to /checkout/initiate. Pricing is computed server-side, so customers cannot tamper.
Full example: checkout flow
const cart = [
{ product_id: 'prod_abc', quantity: 2 },
{ product_id: 'prod_xyz', quantity: 1 },
];
// 1. Validate cart (stock, prices)
const validation = await linkpe.cart.validate({ items: cart });
if (!validation.valid) {
// surface item-level issues
return;
}
// 2. (Optional) Apply a coupon and show preview
const couponPreview = await linkpe.coupons.preview({
code: 'SAVE10',
items: cart,
shipping_cost: 49,
});
// 3. Compute final totals for display
const totals = await linkpe.cart.totals({
items: cart,
coupon_code: 'SAVE10',
shipping_cost: 49,
});
// 4. Initiate checkout (creates the order in MyLinkpe)
const session = await linkpe.checkout.initiate(
{
items: cart,
customer: {
name: 'Asha Verma',
phone: '9999999999',
email: '[email protected]',
address: '12 MG Road, Bengaluru',
pincode: '560001',
},
coupon_code: 'SAVE10',
shipping_cost: 49,
},
{ idempotencyKey: crypto.randomUUID() }
);
// 5. Frontend invokes the gateway SDK using session.session.*
// (Razorpay.js / Cashfree.js / native UPI deeplink)
// 6. After payment, verify the gateway response:
await linkpe.checkout.verifyPayment({
order_id: session.order_id,
razorpay_order_id: '...',
razorpay_payment_id: '...',
razorpay_signature: '...',
});
// 7. Customer tracks the order later:
const order = await linkpe.orders.get(session.order_id, { phone: '9999999999' });API reference (resources)
| Resource | Methods |
|---|---|
| linkpe.store | get() |
| linkpe.products | list(), get(id), listReviews(productId) |
| linkpe.categories | list() |
| linkpe.cart | validate({ items }), totals({ items, coupon_code?, shipping_cost? }) |
| linkpe.coupons | preview({ code, items, shipping_cost? }) |
| linkpe.shipping | calculate({ delivery_pincode, items }) |
| linkpe.checkout | initiate(input, { idempotencyKey? }), verifyPayment(input) |
| linkpe.orders | get(id, { phone }) |
| linkpe.reviews | create({ order_id, token, rating, body?, product_id? }) |
Error handling
The SDK throws typed errors you can instanceof-check:
import {
LinkpeError,
LinkpeAuthError,
LinkpePermissionError,
LinkpeNotFoundError,
LinkpeRateLimitError,
LinkpeValidationError,
LinkpeServerError,
LinkpeNetworkError,
} from '@linkpe-storefront/sdk';
try {
await linkpe.products.get('does-not-exist');
} catch (err) {
if (err instanceof LinkpeNotFoundError) {
// 404 — show "product unavailable"
} else if (err instanceof LinkpeRateLimitError) {
// Back off using err.retryAfter (seconds)
} else if (err instanceof LinkpeError) {
// Anything else from the API — surface err.message + err.requestId
} else {
throw err;
}
}Every error has:
type— one ofinvalid_request,authentication_error,permission_error,rate_limited,not_found,server_error,network_errorcode— stable string code (PRODUCT_NOT_FOUND,RATE_LIMIT_EXCEEDED, etc.)message— human-readablestatus— HTTP statusrequestId— pass this to support if you hit a server error
Custom fetch / runtimes
The SDK uses globalThis.fetch by default (Node 18+, browsers, Workers, Bun, Deno). To use a custom fetcher (e.g., for retries, logging, undici):
new LinkpeClient({
keyId, keySecret,
fetch: myCustomFetch,
});Development
npm install
npm run typecheck
npm test
npm run buildLicense
MIT
