SDK
Use the TypeScript SDK for the default implementation path.
Use the SDK when you are building a frontend, server route, or workflow that should stay aligned with 01.software conventions.
Setup Flow
Install the package
Add @01.software/sdk to the project package manager already used by the repository.
Create the browser client
Use the Publishable Key only from approved origins. The browser client supports public reads plus capability- or customer-authorized Cart, Checkout, and PaymentSession operations.
Create the server client
Use the Secret Key only in trusted server code for writes and privileged workflows.
Verify the slice
Run the target project's typecheck, lint, tests, and build before handoff.
Client Choice
| Context | Client | Notes |
|---|---|---|
| browser UI | browser client | public reads and capability/customer-authorized commerce, origin-limited |
| server route | server client | import from @01.software/sdk/server for server-authoritative and privileged operations |
| React data fetching | query helpers | keep cache and loading states explicit |
| AI-generated code | existing project patterns | avoid adding framework layers |
Collection reads (find/count) and server-only bulk mutations
(updateMany/removeMany, via @01.software/sdk/server) share filter validation.
They preserve filter meaning without silently dropping or rewriting values:
equals: null and not_equals: null retain null through Payload REST. Other null
or undefined values inside where, empty condition objects (including where: {}),
empty arrays (including and/or), nesting beyond 10 levels, and arrays with more
than 1000 elements throw ValidationError before a request. false, 0, empty
strings, and Date conditions remain valid. This read-input restriction is a
BREAKING (0.x minor) change.
Top-level where: undefined is equivalent to omitting where; undefined inside
the filter is rejected. For an unfiltered read, omit where. For a dynamically
empty ID list, return an empty result before calling the SDK. For bulk mutations,
skip the call entirely when no conditions remain or the dynamic list is empty.
Raw collection operations do not replace domain-specific SDK methods or bypass
server-side access rules.
Review existing updateMany/removeMany callers before upgrading: calls that
previously failed with HTTP 400 can now perform actual updates or deletions.
Do not rely on the previous HTTP 400 as a mutation safeguard.
Large in/not_in lists can exceed URL length limits; use smaller batches where
the complete selection can be preserved. For not_in, keep the full exclusion
condition in every batch: splitting exclusions across separate mutations changes
which records are excluded.
Server collection writes (create, update, updateMany) accept an optional
locale (en or ko) for localized fields, sent as Payload's locale query
parameter. Without it the request is unchanged and the server writes the
platform default locale en; writes are never rewritten to the workspace
default, so a workspace that enables only ko (the Korean onboarding default)
must pass { locale: 'ko' }. An omitted or disabled write locale fails with
HTTP 400 and apiReason content_locale_not_enabled.
Import Boundaries
Use @01.software/sdk for the browser-safe client, commerce helpers, and core
types. Use @01.software/sdk/server for createServerClient, and use
@01.software/sdk/query only when your app needs React Query helpers. Error
guards are available from the client/server entry that creates the client and
also work across the root and @01.software/sdk/errors entries.
Rows marked none do not need any extra packages beyond @01.software/sdk.
| Import | Feature(s) | Install when used |
|---|---|---|
@01.software/sdk | browser-safe createClient, commerce helpers, collection helpers, types | none |
@01.software/sdk/client | browser-safe createClient entry and SDK error guards | none |
@01.software/sdk/server | createServerClient, server-only APIs, and SDK error guards | none; keep secretKey code on the server |
@01.software/sdk/errors | SDK error classes and guards | none |
@01.software/sdk/metadata | SEO metadata extraction and generation helpers | none |
@01.software/sdk/webhook | webhook handlers, event guards, and webhook types | none |
@01.software/sdk/query | React Query hooks, cache helpers, getQueryClient | @tanstack/react-query, react, react-dom |
@01.software/sdk/realtime | RealtimeConnection, useRealtimeQuery | @tanstack/react-query, react, react-dom |
@01.software/sdk/storefront-cache | product storefront cache resource helpers | none |
@01.software/sdk/embedded-admin | embedded app browser handshake and protocol types | none |
@01.software/sdk/embedded-admin/server | assertion verification and JWKS loading | none; keep receiver sessions on the server |
@01.software/sdk/ui/rich-text | RichTextContent, StyledRichTextContent | react, react-dom, @payloadcms/richtext-lexical |
@01.software/sdk/ui/form | FormRenderer | react, react-dom |
@01.software/sdk/ui/code-block | CodeBlock, highlight | react, react-dom, shiki, hast-util-to-jsx-runtime |
@01.software/sdk/ui/canvas | CanvasRenderer, CanvasFrame, useCanvas, prefetchCanvas | react, react-dom, @tanstack/react-query, @xyflow/react, quickjs-emscripten, postcss, sucrase |
@01.software/sdk/ui/canvas/server | canvas server helpers | postcss >=8 (optional peer) |
@01.software/sdk/ui/video | VideoPlayer | react, react-dom, @mux/mux-player-react |
@01.software/sdk/ui/image | Image | react, react-dom |
Video playback
For VOD, authorize the viewer in your server application, then call
createServerClient(...).video.playback(video.id) and pass its streamUrl to
<VideoPlayer video={video} streamUrl={streamUrl} />. Renew this bearer URL
before two hours for long playback or after a long pause. Free playback uses the metered gateway and may
return 403 at the monthly delivery limit or 503 if the usage limit cannot be checked. Existing raw Mux URL helpers apply only to unmigrated paid assets;
the stored public ID on a migrated asset remains for usage history.
Published SDK 0.67.0 supports the stored-ratio mapping below. The mapping is unavailable in published 0.65.1. Check support in the package version you use.
VideoPlayer displays the stored aspectRatio values 16_9, 9_16,
4_3, and 1_1 as CSS ratios in both the placeholder and ready player.
An unset ratio defaults to 16/9. Override the ready player with
style.aspectRatio, or the placeholder with placeholderStyle.aspectRatio;
each override applies only to its own rendering path.
CanvasRenderer renders reserved shape nodes (terminator, process,
decision, io, subprocess) with first-party SVG geometry, without a workspace
catalog row or QuickJS template.
If a feature is not listed here, it does not need a separate peer install. For the full component-to-peer mapping, see the SDK package README.
Gallery image and video items
Use client.content.galleryItems.list() in the browser to read a published gallery in curator order:
const gallery = await client.content.galleryItems.list({
gallerySlug: 'spring-lookbook',
limit: 24,
})Each item has optional mediaType: 'image' | 'video'; treat an omitted value
from an older response as image. Image items retain image media. Video
items include video.availability: 'ready' | 'processing' | 'unavailable' and
may include a video document id and safe uploaded thumbnail. Disabled or
plan-blocked video access, missing/deleted targets, and failed videos return
only { availability: 'unavailable' }, retaining the item's position and
pagination. The image relationship is not used as a video poster.
ready describes preparation, not playback permission. Your application server
must verify that the video belongs to the published gallery/item and apply its
viewer policy before calling server.video.playback(video.id). Pass the
returned streamUrl to your player; the server rechecks the current workspace,
video state, and feature/plan. Keep server credentials on that server. Gallery
DTOs omit playback URLs, provider IDs, tokens, and private storage fields.
Domain and integration references
- Customers SDK: Customer identity, hosted sessions and source-aware groups.
- Ecommerce SDK: Market context, product edits, orders and storefront caching.
- Events SDK: Canonical event dates and paid-admission projections.
- Community SDK: Browser-safe post reads and nullable detail results.
- Payments: Payment action reuse, reconciliation and custom server bridges.
- Membership: Prepare paid subscriptions, obtain server-owned billing custody context and deliver signed charge results.
- Embedded Admin: Receive and verify an embedded app session behind fixed origins.
- External Effects: Server-only effect claims, installation custody and customer links.
Paid Membership Subscription
Continue at Membership.
Embedded Admin Apps
Continue at Embedded Admin.
Collection actions use receiveEmbeddedAdminExecution and the server-only
verifyEmbeddedAdminExecution. Pin the full frameUrl and compare the actual
execution inputs. The required consumeExecution callback claims only in shared
durable atomic storage through expiresAt+60, with no business side effects.
Verification checks the deadline again after await; false, timeout, uncertain
commit or error denies approval. Begin business only after successful return and
apply app-owned idempotency. V2 has explicit capability negotiation and a separate
audience; it never falls back to v1 identity. Reload cannot extend its 60-second
prepare deadline. Repeating an action creates a new execution, not a guaranteed
retry of the same business result.
Error reasons
Canonical commerce failures keep their closed, typed reason on
CommerceSDKError.reason. Other endpoints expose their open-ended machine
reason on SDKError.apiReason. Shared handlers can import
getSDKErrorReason from @01.software/sdk/errors to read either family without
inspecting details.reason or details.body.reason; unknown commerce reasons
are returned verbatim from rawReason.
Raw collection failures keep Payload's native body. When it carries a machine
code in errors[0].data.code (or .reason) and no top-level reason, that
code becomes apiReason, for example content_locale_not_enabled. The typed
error class and code still follow the HTTP status.
PortOne Standard V2 cancellation and retry
Continue at Payments.
Server-only PortOne identity reconciliation
Continue at Payments.
Server-only custom payment bridge
Continue at Payments.
Idempotent mutation responses are not exactly-once gates
Continue at Payments.
Existing variant base prices
Continue at Ecommerce SDK.
Orders update compatibility
Continue at Ecommerce SDK.
External-effect claims (server only)
Continue at External Effects.
Installation credentials (server only)
Continue at External Effects.
Tenant Context Introspection
Trusted server workflows can read the resolved workspace features, active and inactive collections, and field configuration through the server-only client:
import { createServerClient } from '@01.software/sdk/server'
const server = createServerClient({
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
secretKey: process.env.SOFTWARE_SECRET_KEY!,
})
const context = await server.tenant.context()
const productSchema = await server.tenant.collectionSchema('products')Use server.tenant.context({ includeCounts: true }) only when collection counts
and webhook configuration are required. It performs additional reads and is
slower than the default call. Keep this API and both credentials in trusted
server code.
productSchema.collection.customFields is optional. When present, it describes
active workspace-defined fields stored under customData using machine keys,
types, optional required markers, and select option storage values. It excludes
operator labels and stored document values; ordinary collection authorization
still governs reads and writes.
Source-aware customer groups
Continue at Customers SDK.
External Customer links
Continue at External Effects.
Customer Auth
Continue at Customers SDK.
Self-withdrawal
Continue at Customers SDK.
Community public reads
Continue at Community SDK.
Event ranges and all-day dates
Continue at Events SDK.
Events Admission
Continue at Events SDK.
Market context
Continue at Ecommerce SDK.
Analytics
For website analytics, integrate an external tool such as GA4, Plausible, or Vercel Analytics in your own frontend. The SDK no longer provides analytics collection helpers.
Storefront Cache Resources
Continue at Ecommerce SDK.
Next.js Mapping
Continue at Ecommerce SDK.
Before Production
- Confirm collection and feature availability for the workspace plan.
- Confirm key storage and rotation ownership.
- Confirm failure handling for customer-facing flows.
Do not put Secret Key values in browser bundles, public env vars, analytics events, or generated examples.
Errors, retries and request identity
Branch on machine reason, never localized error text. Preserve requestId for support and tolerate unknown reasons. Canonical commerce uses CommerceSDKError.reason (unknown values remain in rawReason); generic failures use SDKError.apiReason. getSDKErrorReason reads both. A malformed canonical envelope or mismatched body/header request ID is a protocol failure.
Automatic SDK failure retries apply only to safe methods (GET, HEAD, OPTIONS) after network or timeout failures and retry-eligible HTTP failures (default statuses: 408/500/502/503/504), within the SDK's bounded retry budget and with bounded backoff (exponential by default). GET already has these retries; avoid adding an outer retry loop that multiplies attempts. A terminal 429 is not automatically retried; honor Retry-After. Customer-token 401 triggers at most one refresh, only for token_expired; the original request is resent only for GET/HEAD/OPTIONS, while unsafe methods return the original authentication error. Never automatically replay token exchange or unsafe mutations. Reuse the original durable idempotencyKey after an interrupted supported mutation; a response flag does not deduplicate your own side effects.
After a successful refresh, the single safe resend is independent of the transient retry budget, including retry.maxRetries: 0 or expiry on the final attempt. It does not reset that budget. Another 401 returns its typed authentication error and request ID without a second refresh.
After refresh, a canonical commerce response with retryable: false or no retryable field, or a Retry-After beyond the automatic wait bound, returns its typed error and request ID without another automatic retry.
On endpoints using validateAuthenticatedCustomer, except refresh itself, token_expired means the signature, issuer, audience, tenant and active-customer checks passed and only the access token expiry elapsed. While revocation verification is enabled, generation, password watermark and JTI revocation checks must also pass. Expired tokens that are revoked or fail another validation remain 401 token_invalid and do not trigger refresh. Configure refresh with a valid refresh token; the refresh endpoint itself returns token_invalid for an expired legacy bearer.
The split examples use published SDK 0.65.1, Next.js 16.3.8 where shown, and Node 24.15.0. Follow the linked task guides for complete app sessions and deployment checks.
Customer credits
Use server.credits for template grants, grant lookups with getGrant(), account reads and revocation; browser client.credits reads only the logged-in Customer. See Customer credits for monthly grant recipes and exact Checkout funding negotiation.
Next Actions
- Need exact HTTP contracts: open API.
- Need a shell-capable coding agent: open CLI.
- Need hosted, shell-less discovery: open MCP.
- Need event delivery: open Webhooks.
- Build a guest purchase with Ecommerce: Cart, Checkout, PortOne Standard V2 and order lookup.
Customer benefit vouchers
benefitVouchers is the API for Redemption coupons in Console. Tenant-admins configure them under Ecommerce → Redemption coupon definitions. Creating a definition and issuing a coupon to a customer are separate steps. Staff redeem these single-use benefits without an order; they have no Checkout discount or credit effect. Your server decides recipients and timing (for example from a membership webhook or your own cron); source uniqueness prevents duplicate effects only.
import { createServerClient } from '@01.software/sdk/server'
const server = createServerClient({ publishableKey, secretKey })
const { voucher, created } = await server.benefitVouchers.issue({
definitionId,
customerId,
sourceNamespace: 'member-benefits',
sourceRef: 'period:2030-01:member-opaque-id',
})
const redeemed = await server.benefitVouchers.redeem({
customerId,
voucherId: voucher.id,
requestId,
actorRef: 'staff:opaque-id',
})server.benefitVouchers.get({ customerId, voucherId }) and list({ customerId, state?, definitionId?, limit?, cursor? }) require a read-scoped server key. issue, redeem, and voidVoucher({ customerId, voucherId, requestId, actorRef, reason }) require write scope, sk01 credentials and no browser Origin. Void reasons are issued_in_error, benefit_revoked, customer_request, and other. Issuing and redeeming require effective Ecommerce and Customers; server get/list, customer self-list and void remain available after feature loss. The Console panel lives inside Customer detail and is unavailable with that screen when Customers is disabled.
Reuse the same sourceNamespace/sourceRef and identical issue input on an unknown outcome. For redeem/void, create a request UUID once and reuse it on retries; these POSTs are not automatically retried. Reusing an identity with different input returns 409. A successful transition is irreversible. Expiry uses database time and is inclusive at expiresAt. Correct an issued benefit by voiding it and issuing a new source identity.
client.benefitVouchers.listMine({ status: 'available', limit: 20 }) uses the Customer JWT and returns only identity, customer-visible copy, state and timestamps. Use status: 'all' for history and the returned nextCursor for another page (maximum 100). The response is private, no-store. Server lists return the server DTO and require customerId; cross-customer/tenant targets are masked as 404. Console Customer detail also offers role-gated redeem and void confirmations.
The staff app server must verify the staff member and Customer before redeeming: voucherId is not a bearer capability. actorRef is app-attested evidence, never a platform-verified staff identity or an authorization input. Use opaque references without personal data in sourceRef and actorRef. Definitions snapshot name, description and expiry at issue; later edits do not change issued vouchers. Voucher history survives Customer erasure and blocks tenant hard deletion. Referenced definitions must be archived.