Malonlin SDK Docs

Complete store launch

A store is more than its name and first product. This guide explains the larger pieces to plan when building a standalone storefront or seller tool. The SDK calls the API; the backend owns validation, eligibility, money, and permissions.

1. Start with the right account and plan#

Create/sign in to the marketplace account first. It is the same user identity used for the profile, API subscription, and personal wallet when your deployments point at the shared database. Provision the API key from User settings → API subscriptions and keep it server-side.

Check the account subscription and API-key entitlements before promising store count, product count, member count, or premium API functionality. An API access plan and the store's business plan are separate concepts.

2. Create the store record#

Use the authenticated helper; the backend derives the owner from the JWT:

ts
const store = await sdk.account.createStore({
  name: 'Market Garden',
  email: 'orders@example.com',
  categories: ['Food & Drink'],
  contact: { phone: '+27110000000' },
  physicalAddress: {
    line1: '1 Example Street',
    city: 'Cape Town',
    state: 'Western Cape',
    postalCode: '8001',
    country: 'South Africa',
  },
});

const memberId = await sdk.members.myStoreMemberId(store.id);
if (!memberId) throw new Error('Could not resolve this account’s store membership.');

The create input requires name, email, and physicalAddress (line1, city, state, postalCode, and country). The address is important for seller identity, customer transparency, and shipping/fulfillment decisions. The server generates the store handle; do not treat an app-generated handle or owner ID as authoritative.

3. Configure commercial and storefront details#

Plan the information your customer sees before publishing:

  • Name, about text, logo, and banner: identify the seller and make the storefront recognizable.
  • Categories and contact details: help buyers find the store and know how to reach it.
  • Store handle: provides a stable storefront identifier. Your standalone app can map it to its own routes, but hosting and custom-domain routing remain your responsibility.
  • Subscription and entitlements: select an available store plan when the business needs higher product/member limits or plan-specific features. Store subscription purchases are for a STORE subject; paid plans must use that store's wallet, and the backend checks the owner.
  • Policies and tax configuration: communicate returns, service conditions, taxes, and delivery expectations clearly. Product refund/tax fields are not legal advice; use the applicable server-supported settings and meet local requirements.

Use sdk.stores.updateStore(...) for supported store fields and sdk.subscriptions.storeContext(...) to inspect the current store plan/entitlements. The backend's current input schema is the source of truth.

4. Build the catalog by product type#

The backend supports four product types. Pick the correct type because it changes checkout and fulfillment behavior:

Type Prepare these details Why it matters
PHYSICAL Price, inventory, variants, images, shipping mode/costs, pickup/delivery details Stock and shipping options affect what can be ordered and fulfilled.
PRE_ORDER Availability, estimated prep time, allowed fulfillment types, capacity/waitlist policy Customers are ordering before normal stock is ready; the backend tracks limits and fulfillment.
SERVICE Duration, pricing model/rate card, availability slots, location, booking capacity Checkout must reserve a service time and calculate the service price correctly.
DIGITAL Product price and server-issued file metadata/upload references The purchase library and secure download path depend on files attached to the product. Never invent an arbitrary storage key.

Every product needs name and price. For a simple draft, start with a physical product:

ts
const product = await sdk.products.createStoreProduct(
  {
    name: 'Hand-thrown Ceramic Mug',
    description: 'A locally made stoneware mug.',
    price: 240,
    currencyCode: 'ZAR',
    productType: 'PHYSICAL',
    totalInventory: 12,
    categories: ['Home & Living'],
    images: [],
    published: false,
  },
  store.id,
  memberId,
);

Then enrich the product with variants, inventory, approved media uploads, shipping configuration, and refund/tax fields as needed. The field reference lists create/update fields and conditional requirements. For SERVICE, PRE_ORDER, and DIGITAL, satisfy the product-type rules in the backend guide before publishing; GraphQL nullability alone does not express all business validation.

Keep products unpublished while you review pricing, stock, media, and fulfillment. Publishing is a customer-visible action:

ts
await sdk.products.toggleStoreProductPublished(product.id, true, store.id, memberId);

5. Add your team with least privilege#

Resolve the signed-in user's member ID with sdk.members.myStoreMemberId(store.id). Invite teammates through sdk.members.createInvitation(...) and grant only the permissions their jobs need. For example, staff who only view orders should not receive inventory, settings, or member-management permissions.

Subscriptions can enforce store member limits. Re-check the store plan before inviting additional members; a client-side check is only a friendly preview, never an access-control decision.

See Store and member management for invitation and permission flows.

6. Finish the buyer journey#

Before opening the store to customers, test the full path with a separate buyer account:

  1. Load public store and product pages with sdk.stores.listPublicStores() and sdk.products.publicStoreProducts(...).
  2. Add an item to a server-backed cart, and verify the server's current price, stock, options, and fulfillment rules.
  3. Collect buyer profile and delivery details only when the selected product/fulfillment requires them.
  4. Call checkout readiness for feedback, then call the self-scoped checkout operation with an idempotency key.
  5. Treat the server's order and isPaid state as authoritative. A local checkout event or a browser redirect is not proof of payment.
  6. Exercise pre-order, booking, digital download, cancellation/refund, and receipt-confirmation flows that apply to your catalog.

The backend resolves current prices and stock at checkout. Never trust a browser-calculated total or fulfillment state.

7. Set up wallet, payout, and financial monitoring#

User and store wallets are different accounts. API-plan purchases belong to the marketplace user's wallet; a paid store subscription uses the store wallet. Sales proceeds may follow hold/release rules rather than appearing as immediately withdrawable funds.

Use the wallet guide for balance, funding, idempotency, payout, currency, and confirmation rules. Configure Ozow/payment credentials on the server, not in your standalone client. Where the system holds store funds, buyer receipt confirmation is the release trigger; the documented fallback remains server-managed.

8. Observe and maintain the store#

  • Use store order and analytics clients to monitor operations. Paid sales use isPaid: true; do not define sales as only delivered.
  • Subscribe to the currently supported backend webhook event (payment.completed) for server-to-server fulfillment notifications. Verify its HMAC and deduplicate event IDs.
  • Use SDK local events for your own app UX/analytics. They do not replace backend webhooks.
  • Upload media through sdk.uploads and the configured same-origin upload service.
  • Review API-key activity, rotate exposed credentials, and keep API/store subscriptions current.

What a standalone seller app must provide itself#

The SDK supplies data and workflow calls. Your app still needs to build its own seller dashboard, customer storefront, responsive/accessibility design, routing/domain mapping, login/session UX, error states, order support, and any required legal/compliance pages. It also must keep private credentials on a trusted server, and arrange any integrations the Malonlin API does not provide.

Use Standalone account and API setup for the shared account/key prerequisites and Feature clients for the SDK surface.

Malonlin SDK documentation