---
id: sdks.typescript
title: JavaScript and TypeScript SDK Quickstart
summary: Use the server-side ES module SDK to submit a Fieldloop batch and inspect row processing.
kind: quickstart
product_area: developer_tools
status: stable
updated: 2026-10-31
canonical: /docs/sdks/typescript
---

# JavaScript and TypeScript SDK Quickstart

## Prerequisites and installation

Use Node.js 22+, ES modules and a source checkout of `teammately-js`. Build the checkout with its npm workflow:

```sh
# In the SDK checkout:
npm ci
npm run build
# In an npm application:
npm install /path/to/teammately-js
```

For an application using another package manager, use that manager's local-package installation workflow. The package is `@teammately/sdk` and includes TypeScript declarations. Inject the API key through your server host's secret mechanism and configure the three destination variables below.

## Submit and inspect a batch

### Example: Submit an immutable captured batch

```typescript
import { Batch, Client, ReceiptError } from "@teammately/sdk";

const client = new Client({ apiKey: process.env.TEAMMATELY_API_KEY! });
const scope = {
  organization: process.env.TEAMMATELY_ORGANIZATION!,
  project: process.env.TEAMMATELY_PROJECT!,
  source: process.env.TEAMMATELY_FIELDLOOP_SOURCE!,
};
const batch = Batch.prepare([{
  source_event_id: "support-ticket-1042:reply",
  occurred_at: "2026-10-31T09:30:00Z",
  input: { question: "Has my bicycle shipped?" },
  output: { reply: "Your bicycle is being packed." },
}], "support-ticket-1042:batch-1");

const receipt = await client.fieldloop.submitBatch(scope, batch);
try {
  const processed = await client.fieldloop.waitReceipt(scope, receipt.batch_id);
  console.log(processed.accepted_count, processed.duplicate_count,
    processed.conflict_count, processed.rejected_count);
} catch (error) {
  if (error instanceof ReceiptError) {
    console.error("Batch processing ended:", error.receipt.status);
  }
  throw error;
}
```

Replace this fictional application record and its application-owned keys with selected, redacted records. Teammately issues destination and receipt IDs. Keep credential-bearing SDK code on the server.

## Cancellation and continuous ingestion

Operations accept `signal` and `timeoutMs`. Create an ingestor with `client.fieldloop.ingestor(scope)`, use `await ingestor.add(log)`, and drain with `await ingestor.close()` in a `finally` block.

`add` acknowledges memory. Failed batches remain in `status` and `pendingBatch`; recover with their original bytes/key. Defaults impose no capacity or operation deadline. Receipt callbacks must return promptly. See [Delivery and Recovery](/docs/sdks/delivery-and-recovery).

## Success and recovery

Inspect row counts after processing. Preserve `ReceiptError.receipt` for terminal processing outcomes. `Batch.prepare` rejects unsafe numeric integers; use `Batch.restore(originalBytes, originalKey)` when exact JSON bytes, including large integer literals, must be retained.

## Related reference pages

{% related-card-grid %}
- [Delivery and recovery](/docs/sdks/delivery-and-recovery)
- [Fieldloop API](/docs/public-api/fieldloop)
- [Fieldloop troubleshooting](/docs/troubleshooting/fieldloop)
{% /related-card-grid %}
