TypeScript SDK
The official @simply360/sdk package — installation, configuration, the resource clients it exposes, and code examples for common operations.
Overview
The official Simply360 TypeScript SDK (@simply360/sdk) provides a typed client for the Simply360 REST API. It works in Node.js 18+, modern browsers, and edge runtimes. The SDK is a thin, typed wrapper over the HTTP API — one resource client per top-level resource, each method maps to a single HTTP request.
Installation
The SDK ships as the @simply360/sdk package. It is currently in developer preview and is not yet published to the public npm registry — contact developers@simply360.app for access, and watch the API Changelog for the public release announcement. Once the package is available in your registry, install it with:
npm install @simply360/sdk
Basic Setup
import { Simply360 } from '@simply360/sdk';
const s360 = new Simply360({
apiKey: process.env.S360_API_KEY!, // s360_live_...
});
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string | — | Static API key. Provide either apiKey or getToken. |
getToken |
() => Promise<string> | string |
— | Dynamic token provider, used for Cognito JWT or OAuth2 flows where the token refreshes. |
teamSimplyId |
string | — | Team simplyId, sent as X-Team-Id. Required when using a Cognito JWT. |
allowUnauthenticated |
boolean | false |
Allow requests without credentials to documented unauthenticated public endpoints. |
baseUrl |
string | https://api.simply360.app |
Override to target a non-production environment. |
timeout |
number | 30000 |
Request timeout in milliseconds. |
headers |
Record<string, string> |
{} |
Extra headers added to every request. |
Switching Teams Mid-Session
If you build an app that switches between teams (e.g., the Simply360 webapp), you can update the team header on the existing client without recreating it:
s360.setTeamSimplyId('NEW0-TEAM-SIMP');
The older setTeamId method still works but is a deprecated alias for setTeamSimplyId.
Resource Clients
The Simply360 class exposes one resource client per top-level resource. The most commonly used clients are:
| Property | Resource |
|---|---|
s360.dataRecords | Data records (CRUD, search, batch, audit log, files, children/related) |
s360.dataCollections | Data collections and field schemas |
s360.dataViews | Data views and view records |
s360.dataWizards | Data wizards, schemas, and execution |
s360.messages | Outgoing messages and message status |
s360.messageTemplates | Message templates (CRUD) |
s360.conversations | Conversations and conversation messages |
s360.reports | Reports and report execution |
s360.automations | Automations, executions, manual triggers |
s360.files | File metadata, download URLs, image variants |
s360.actionTags | SimplyTags and scan history |
s360.webhooks | Webhook subscriptions and delivery logs |
s360.apiKeys | API keys (create, list, rotate, revoke) |
s360.sessionTokens | Session tokens (create, list, revoke) |
s360.users | Users (current, list, get) |
s360.auditLog | Audit log entries |
s360.constituentAuth | Constituent identity verification flows |
s360.appStore | App-store purchase verification and entitlements |
Newer platform surfaces follow the same pattern — the SDK also exposes clients such as s360.signingRequests, s360.billing, s360.paymentAccounts, s360.contentTemplates, s360.styleKits, s360.websites (plus the related Website Studio clients), s360.actionCredentials, and s360.teamAgent. Every method maps to a single documented REST endpoint.
Presigned File Uploads
Some API methods return a short-lived presigned upload URL for direct-to-storage file staging. Use the SDK helper to PUT the bytes instead of writing a raw fetch call in app code:
import { uploadPresignedFile } from '@simply360/sdk';
const presigned = await s360.dataRecords.presignAiGraphUpload({
fileName: file.name,
contentType: file.type || 'application/octet-stream',
});
await uploadPresignedFile({
uploadUrl: presigned.data.uploadUrl,
body: file,
contentType: file.type || 'application/octet-stream',
});
The helper resolves after any 2xx response and throws when the storage service returns a non-2xx response.
Common Operations
List Records
const response = await s360.dataRecords.list({
dataCollectionSimplyId: 'XXXX-XXXX-XXXX',
limit: 50,
sort: '-createdAt',
fields: 'FLDS-FRST-NAME,FLDS-LAST-NAME,FLDS-EMAL-ADDR',
});
// response.data: DataRecord[]
// response.meta.pagination.total: number
Get a Record
const response = await s360.dataRecords.get('WXYZ-5678-IJKL');
console.log(response.data.fields);
Create a Record
const response = await s360.dataRecords.create({
dataCollectionSimplyId: 'XXXX-XXXX-XXXX',
fields: {
'FLDS-FRST-NAME': 'Jane',
'FLDS-LAST-NAME': 'Doe',
'FLDS-EMAL-ADDR': 'jane@example.com',
},
});
Update a Record (partial)
await s360.dataRecords.update('WXYZ-5678-IJKL', {
fields: { 'FLDS-EMAL-ADDR': 'jane.doe@newdomain.com' },
});
Replace a Record (full overwrite)
await s360.dataRecords.replace('WXYZ-5678-IJKL', {
fields: { /* full set of fields */ },
});
Delete a Record
await s360.dataRecords.delete('WXYZ-5678-IJKL');
Search Records
const response = await s360.dataRecords.search({
dataCollectionSimplyId: 'XXXX-XXXX-XXXX',
query: 'Jane',
filters: [
{ field: 'FLDS-EMAL-ADDR', operator: 'contains', value: '@example.com' },
],
limit: 10,
});
Batch Operations
await s360.dataRecords.batchCreate({
dataCollectionSimplyId: 'XXXX-XXXX-XXXX',
records: [
{ fields: { 'FLDS-NAME': 'A' } },
{ fields: { 'FLDS-NAME': 'B' } },
],
});
await s360.dataRecords.batchUpdate({
records: [
{ dataRecordSimplyId: 'WXYZ-5678-IJKL', fields: { 'FLDS-EMAL': 'a@x.com' } },
{ dataRecordSimplyId: 'MNOP-9012-QRST', fields: { 'FLDS-EMAL': 'b@x.com' } },
],
});
await s360.dataRecords.batchDelete({
dataRecordSimplyIds: ['WXYZ-5678-IJKL', 'MNOP-9012-QRST'],
});
Working with Collections
const collections = await s360.dataCollections.list();
const detail = await s360.dataCollections.get('XXXX-XXXX-XXXX');
console.log(detail.data.fields); // included by default
const fields = await s360.dataCollections.listFields('XXXX-XXXX-XXXX');
Executing a Data View
Get the records that match a saved view's filters and sort:
const records = await s360.dataViews.getRecords('VIEW-1234-ABCD', {
limit: 50,
offset: 0,
});
Simply Action Tags
The actionTags client exposes typed URL/Link Page CRUD, retained scan analytics, CSV import/export, custom domains, and signed webhooks. Standalone API-key use requires the 500-Action band or higher. Account, Team User, saved-payment-method, and billing methods are first-party Cognito Team Admin operations even though they share generated SDK types; an API key cannot use them.
const action = await s360.actionTags.create({
name: 'Visitor resources',
actionType: 'LINK_PAGE',
linkPageSettings: {
title: 'Welcome',
theme: 'SYSTEM',
callsToAction: [{ label: 'Hours', url: 'https://example.org/hours' }],
},
});
const dryRun = await s360.actionTags.importCsv({ csv, dryRun: true });
if (dryRun.data.validRows === dryRun.data.totalRows) {
await s360.actionTags.importCsv({
csv,
dryRun: false,
idempotencyKey: crypto.randomUUID(),
});
}
Reuse an import idempotency key only when retrying the exact same CSV. Webhook creation returns its HMAC secret once. Domain listing is a pure read; verifyDomain() is the explicit reconciliation mutation. Powered record/Wizard fields are rejected for a standalone Team rather than silently removed.
Pagination
The SDK uses manual offset pagination — advance the offset yourself until response.meta.pagination.hasMore is false. Maximum page size is 100. See Pagination, Sorting & Field Selection for details.
let offset = 0;
const limit = 100;
const all: DataRecord[] = [];
while (true) {
const response = await s360.dataRecords.list({ dataCollectionSimplyId, limit, offset });
all.push(...response.data);
if (!response.meta.pagination.hasMore) break;
offset += limit;
}
Error Handling
The SDK throws ApiError for any non-2xx response. Responses that cannot be parsed (for example, an HTML error page from an intermediary) are also surfaced as ApiError rather than a raw parse error. See Error Handling for details.
import { Simply360, ApiError } from '@simply360/sdk';
try {
await s360.dataRecords.get('NONE-XIST-ENT0');
} catch (error) {
if (error instanceof ApiError) {
console.error(error.statusCode, error.code, error.message);
}
}
TypeScript Types
All request and response types are exported from the SDK. Use them to type your own functions and data structures.
import type {
Simply360Config,
ApiResponse,
ApiListResponse,
DataRecord,
DataCollection,
ListRecordsParams,
CreateRecordParams,
SearchRecordsParams,
} from '@simply360/sdk';
function processRecords(response: ApiListResponse<DataRecord>) {
for (const record of response.data) {
// record is fully typed
console.log(record.dataRecordSimplyId, record.fields);
}
}
Targeting a Different Environment
The SDK targets production by default. To use an enabled non-production environment, override baseUrl with the matching API base URL:
const s360 = new Simply360({
apiKey: process.env.S360_API_KEY!,
baseUrl: process.env.SIMPLY360_API_URL ?? 'https://api.simply360.app',
});
# Staging
export SIMPLY360_API_URL="https://api.staging.simply360.app"
# Development
export SIMPLY360_API_URL="https://api.dev.simply360.app"
Staging is a paid add-on or an included offer benefit. Development is a separate, limited preview add-on or beta grant; Staging access does not include Development. Use an API key created in the selected environment — credentials do not cross environment boundaries. See Environments for the complete endpoint and access matrix.