Skip to content

Raw APIs and the Node.js SDK

Instant API is the data API layer every dataset gets automatically, with three calling modes: WebAPI, OpenAPI, and Client API. This page first explains how the three modes differ in use cases, authentication, and URLs; then it walks through the 9 core APIs with raw curl examples in WebAPI mode; finally, it shows how the Node.js SDK wraps them.

1. The Three Calling Modes

ModeUse casesIdentity semanticsCoverage
WebAPILovrabet-generated web pages, micro-frontend child apps, logged-in users accessing data in the browserThe current logged-in userAll 9 core Instant APIs
OpenAPIThird-party systems, server-side jobs, Agent gateways, cross-system integrationApp-level access credentialsA subset of data operations; see the OpenAPI docs
Client APICLIs, Agents, local scripts, and server-side tools that access data as an individualPersonal identity authenticationAll 9 core Instant APIs

How to choose:

  • If you're already in a Lovrabet page or a same-domain browser environment, use WebAPI.
  • For server-to-server integration from an external system, use OpenAPI.
  • When an automation tool must act as a specific user, use Client API.

2. Authentication

ModeAuthenticationHeader or credentialNotes
WebAPICookie session authenticationThe browser sends the cookie automatically; Node.js can pass an explicit Cookie headerInherits the current logged-in user's permissions
OpenAPIHMAC-SHA256 signatureX-Time-Stamp, X-App-Code, X-Dataset-Code, X-TokenThe AccessKey must stay on the server and never appear in frontend code
Client APIPersonal identity authenticationX-User-AKRepresents a specific individual — ideal for CLIs, Agents, scripts, and server-side tools

3. URL Format Differences

ModeURL formatRequest bodyMethod naming
WebAPI/api/{appCode}/{datasetCode}/{method}Business parameters passed directlycamelCase, e.g. getOne, batchCreate
OpenAPI/openapi/data/{method}{ appCode, datasetCode, paramMap }; batchCreate uses paramListSome methods use kebab-case, e.g. get-one, batch-create
Client API/client/{appCode}/{datasetCode}/{method}Business parameters passed directlycamelCase, e.g. getOne, batchCreate

4. Conventions Used on This Page

The curl examples on this page use the raw WebAPI. WebAPI supports all 9 Instant APIs with a fixed path rule:

Plain
POST {runtimeDomain}/api/{appCode}/{datasetCode}/{method}

WebAPI authenticates with a cookie. The request body carries business parameters directly — no appCode, datasetCode, or paramMap wrapper:

Bash
export RUNTIME_DOMAIN="https://runtime.lovrabet.com"
export APP_CODE="app_xxx"
export DATASET_CODE="dataset_xxx"
export LOVRABET_COOKIE="your-session-cookie"
Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/filter" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{"currentPage":1,"pageSize":20}'

If your runtime uses Client API with personal authentication, switch the path to /client/{appCode}/{datasetCode}/{method}. The request body still carries business parameters directly, and authentication uses the X-User-AK header:

Bash
curl -X POST "$RUNTIME_DOMAIN/client/$APP_CODE/$DATASET_CODE/filter" \
  -H "Content-Type: application/json" \
  -H "X-User-AK: $LOVRABET_USER_AK" \
  -d '{"currentPage":1,"pageSize":20}'

OpenAPI differs from WebAPI in URL, authentication, and request body. Don't infer OpenAPI details from the curl examples here — see OpenAPI.

5. Detailed SDK Documentation

This page only maps Node.js SDK methods to the raw APIs — it doesn't cover full SDK installation, configuration, authentication, error handling, or the type system. For details, see:

DocumentPurpose
TypeScript SDKFull Node.js / TypeScript SDK integration, model configuration, authentication, and method reference
Java SDKJava server-side integration, request objects, authentication, and call examples
OpenAPIOpenAPI authentication, signing, paths, request bodies, and the full API reference

6. Node.js SDK Basics

A minimal model configuration for the Node.js SDK:

TypeScript
import { createClient } from "@lovrabet/sdk";

const client = createClient({
  appCode: process.env.LOVRABET_APP_CODE,
  runtimeDomain: process.env.LOVRABET_RUNTIME_DOMAIN || "https://runtime.lovrabet.com",
  cookie: process.env.LOVRABET_COOKIE,
  models: [
    {
      tableName: "orders",
      datasetCode: process.env.LOVRABET_DATASET_CODE!,
      alias: "orders",
    },
  ],
});

const orders = client.models.orders;

In cookie/WebAPI mode, the SDK sends orders.filter(params) as:

Plain
POST /api/{appCode}/{datasetCode}/filter
body: params

In Client API mode, it sends:

Plain
POST /client/{appCode}/{datasetCode}/filter
body: params

7. API Summary

APIWebAPI / Client API pathOpenAPI pathNode.js SDK methodDescription
filter/api/{appCode}/{datasetCode}/filter or /client/{appCode}/{datasetCode}/filter/openapi/data/filterclient.models.<alias>.filter(params)Lists, search, filtering, pagination
aggregate/api/{appCode}/{datasetCode}/aggregate or /client/{appCode}/{datasetCode}/aggregate/openapi/data/aggregateclient.models.<alias>.aggregate(params)Grouped statistics, sums, counts, averages
getOne/api/{appCode}/{datasetCode}/getOne or /client/{appCode}/{datasetCode}/getOne/openapi/data/get-oneclient.models.<alias>.getOne(id)Read a single record by ID
create/api/{appCode}/{datasetCode}/create or /client/{appCode}/{datasetCode}/create/openapi/data/createclient.models.<alias>.create(data)Create a single record
batchCreate/api/{appCode}/{datasetCode}/batchCreate or /client/{appCode}/{datasetCode}/batchCreate/openapi/data/batch-createclient.models.<alias>.batchCreate(items)Create records in bulk
update/api/{appCode}/{datasetCode}/update or /client/{appCode}/{datasetCode}/update/openapi/data/updateclient.models.<alias>.update(id, data) or update({ id, ...data })Update one or many records
delete/api/{appCode}/{datasetCode}/delete or /client/{appCode}/{datasetCode}/deleteNot supportedclient.models.<alias>.delete(id) or delete({ id })Delete one or many records
getSelectOptions/api/{appCode}/{datasetCode}/getSelectOptions or /client/{appCode}/{datasetCode}/getSelectOptionsNot supportedclient.models.<alias>.getSelectOptions(params)Fetch dropdown options
excelExport/api/{appCode}/{datasetCode}/excelExport or /client/{appCode}/{datasetCode}/excelExportNot supportedclient.models.<alias>.excelExport(params)Export an Excel file

The OpenAPI request body differs from WebAPI / Client API: OpenAPI puts business parameters in paramMap, and batchCreate uses paramList. For signing details and request bodies, see OpenAPI.

8. The 9 APIs in Detail

8.1 filter

filter queries a batch of records, with support for conditions, field selection, sorting, and pagination.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/filter" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "where": {
      "$and": [
        { "status": { "$eq": "paid" } },
        { "amount": { "$gte": 100 } }
      ]
    },
    "select": ["id", "orderNo", "status", "amount", "createdAt"],
    "orderBy": [{ "createdAt": "desc" }],
    "currentPage": 1,
    "pageSize": 20
  }'

SDK wrapper:

TypeScript
const result = await orders.filter({
  where: {
    $and: [
      { status: { $eq: "paid" } },
      { amount: { $gte: 100 } },
    ],
  },
  select: ["id", "orderNo", "status", "amount", "createdAt"],
  orderBy: [{ createdAt: "desc" }],
  currentPage: 1,
  pageSize: 20,
});

The response is a paginated structure whose key fields are tableData, paging, and tableColumns.

8.2 aggregate

aggregate computes aggregate statistics. It supports SUM, COUNT, and AVG, plus groupBy, having, and orderBy.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/aggregate" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "select": ["status"],
    "aggregate": [
      { "type": "COUNT", "field": "id", "alias": "order_count" },
      { "type": "SUM", "field": "amount", "alias": "total_amount", "round": true, "precision": 2 }
    ],
    "where": { "createdAt": { "$gte": "2026-01-01" } },
    "groupBy": ["status"],
    "having": [
      { "columnName": "total_amount", "condition": { "$gte": 10000 } }
    ],
    "orderBy": [{ "total_amount": "desc" }],
    "currentPage": 1,
    "pageSize": 20
  }'

SDK wrapper:

TypeScript
const result = await orders.aggregate({
  select: ["status"],
  aggregate: [
    { type: "COUNT", field: "id", alias: "order_count" },
    { type: "SUM", field: "amount", alias: "total_amount", round: true, precision: 2 },
  ],
  where: { createdAt: { $gte: "2026-01-01" } },
  groupBy: ["status"],
  having: [
    { columnName: "total_amount", condition: { $gte: 10000 } },
  ],
  orderBy: [{ total_amount: "desc" }],
  currentPage: 1,
  pageSize: 20,
});

The response is also a paginated structure; each item in tableData is an aggregation result.

8.3 getOne

getOne reads a single record by ID.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/getOne" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{"id":"order_001"}'

SDK wrapper:

TypeScript
const order = await orders.getOne("order_001");

const sameOrder = await orders.getOne({ id: "order_001" });

When you know the ID, call getOne directly — don't emulate a single-record fetch with filter.

8.4 create

create inserts one record; the request body is simply the business fields to write.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/create" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "customerId": "customer_001",
    "amount": 199.9,
    "status": "pending"
  }'

SDK wrapper:

TypeScript
const created = await orders.create({
  customerId: "customer_001",
  amount: 199.9,
  status: "pending",
});

Shared rules such as defaults, uniqueness, and state-machine checks belong in the Before Hook for create.

8.5 batchCreate

batchCreate inserts multiple records in one call. The raw WebAPI request body is an array — no need to wrap it as { items: [...] }.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/batchCreate" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '[
    { "customerId": "customer_001", "amount": 100, "status": "pending" },
    { "customerId": "customer_002", "amount": 200, "status": "pending" }
  ]'

SDK wrapper:

TypeScript
const createdRows = await orders.batchCreate([
  { customerId: "customer_001", amount: 100, status: "pending" },
  { customerId: "customer_002", amount: 200, status: "pending" },
]);

The SDK validates that the input is a non-empty array with at most 1,000 items.

8.6 update

update modifies one or more records. The request body must include id; the remaining fields are the values to update.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/update" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "id": "order_001",
    "status": "paid",
    "paidAt": "2026-04-23T10:00:00Z"
  }'

To update in bulk, pass id as an array:

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/update" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "id": ["order_001", "order_002"],
    "status": "archived"
  }'

SDK wrapper:

TypeScript
const updated = await orders.update({
  id: "order_001",
  status: "paid",
  paidAt: "2026-04-23T10:00:00Z",
});

const updatedBatch = await orders.update(
  ["order_001", "order_002"],
  { status: "archived" },
);

The SDK enforces a 1,000-record limit on bulk updates.

8.7 delete

delete removes one or more records. Deletion is a high-risk write operation — automation scripts should explicitly confirm the dataset and the ID.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/delete" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{"id":"order_001"}'

Bulk delete:

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/delete" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{"id":["order_001","order_002"]}'

SDK wrapper:

TypeScript
await orders.delete("order_001");

await orders.delete({ id: ["order_001", "order_002"] });

The SDK enforces a 1,000-record limit on bulk deletes. OpenAPI mode does not support delete; use WebAPI or Client API mode instead.

8.8 getSelectOptions

getSelectOptions turns dataset data into a { label, value } options array for frontend components.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/getSelectOptions" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "code": "id",
    "label": "name"
  }'

SDK wrapper:

TypeScript
const options = await orders.getSelectOptions({
  code: "id",
  label: "name",
});

It works well for Select, Radio, Checkbox, filters, and typeahead inputs. OpenAPI mode does not support getSelectOptions; use WebAPI or Client API mode instead.

8.9 excelExport

excelExport exports dataset query results to an Excel file, typically returning a downloadable file URL.

Bash
curl -X POST "$RUNTIME_DOMAIN/api/$APP_CODE/$DATASET_CODE/excelExport" \
  -H "Content-Type: application/json" \
  -H "Cookie: $LOVRABET_COOKIE" \
  -d '{
    "where": { "status": { "$eq": "paid" } },
    "select": ["id", "orderNo", "status", "amount"],
    "orderBy": [{ "createdAt": "desc" }]
  }'

SDK wrapper:

TypeScript
const fileUrl = await orders.excelExport({
  where: { status: { $eq: "paid" } },
  select: ["id", "orderNo", "status", "amount"],
  orderBy: [{ createdAt: "desc" }],
});

Reuse the page's filter conditions for exports so the on-screen query and the exported file always match. OpenAPI mode does not support excelExport; use WebAPI or Client API mode instead.

基于飞书知识库同步生成,内容以飞书源文档为准