npm package: @syncteamsstudio/sdk
Description: Official SyncTeams workflow SDK for Node.js and TypeScript consumers.
Author: SyncTeams
Latest version: 0.5.0

# SyncTeams Workflow SDK

A TypeScript/Node.js client for the SyncTeams Workflow API. This SDK provides a simple interface for executing workflows, monitoring task status, and handling approval flows with full type safety.

---

## Installation

```bash
npm install @syncteamsstudio/sdk
```

**Requirements:** Node.js 18 or newer

---

## Quick Start

```ts
import { WorkflowClient, WorkflowStatus } from '@syncteamsstudio/sdk';

const client = new WorkflowClient({
  apiKey: process.env.SYNCTEAMS_API_KEY!,
});

async function run() {
  // Execute a workflow
  const { taskId } = await client.executeWorkflow({
    workflowId: 'your_workflow_id',
    input: { email: 'user@example.com' },
    uniqueId: 'customer-123',
  });

  // Wait for completion
  const result = await client.waitForCompletion(taskId, {
    pollIntervalMs: 2_000,
    onUpdate: ({ status }) => console.log(`Status: ${status}`),
  });

  if (result.status === WorkflowStatus.COMPLETED) {
    console.log('Workflow completed successfully!');
  }
}

run().catch(console.error);
```

---

## Configuration

| Option | Required | Default | Description |
| --- | --- | --- | --- |
| `apiKey` | ✅ | – | Your SyncTeams API key |
| `baseUrl` | ❌ | `https://api.syncteams.studio` | API base URL |
| `timeoutMs` | ❌ | `30000` | Request timeout in milliseconds |
| `retry` | ❌ | See below | Retry configuration for failed requests |

### Retry Configuration

By default, the SDK retries transient failures with exponential backoff:
- Maximum attempts: 3
- Initial delay: 1 second
- Backoff factor: 2x
- Retries on: Network errors, timeouts, and 5xx responses

---

## API overview

### `executeWorkflow(input)`

Starts a workflow execution.

```ts
const { taskId, status } = await client.executeWorkflow({
  workflowId: 'your_workflow_id',
  uniqueId: 'unique-identifier',
  input: { /* your workflow input */ },
});
```

Returns the `taskId` and initial status.

### `getTaskStatus(taskId)`

Fetches the latest status and the filtered event log for a task.

```ts
const status = await client.getTaskStatus(taskId);
console.log(status.status, status.eventLogs?.length ?? 0);
```

### `continueTask({ taskId, decision, message? })`

Resumes a waiting workflow after an approval decision.

```ts
import { ApprovalDecision } from '@syncteamsstudio/sdk';

await client.continueTask({
  taskId,
  decision: ApprovalDecision.APPROVE,
});

await client.continueTask({
  taskId,
  decision: ApprovalDecision.REJECT,
  message: 'Missing documentation',
});
```

When `decision` is `ApprovalDecision.REJECT`, `message` is required.

### `waitForCompletion(taskId, options?)`

Polls a task until it reaches a terminal status (`COMPLETED`, `FAILED`, or `CANCELED`).

```ts
const finalStatus = await client.waitForCompletion(taskId, {
  pollIntervalMs: 1000,
  maxWaitTimeMs: 15 * 60 * 1000,
  onUpdate: ({ status, eventLogs }) => {
    console.log('Status:', status);
  },
});
```

Options:
- `pollIntervalMs`: Polling frequency (default: 2000ms)
- `maxWaitTimeMs`: Maximum wait time before timeout
- `onUpdate`: Callback fired on status changes
- `exitOnWaiting`: Return early when task enters approval state

### `executeAndWait(input, options?)`

Convenience method that executes a workflow and waits for completion.

```ts
import { ApprovalDecision } from '@syncteamsstudio/sdk';

const result = await client.executeAndWait(
  { workflowId: 'your_workflow_id', input: { amount: 500 } },
  {
    pollIntervalMs: 1000,
    onWaiting: async ({ taskId }) => {
      // Handle approval workflow
      await client.continueTask({ taskId, decision: ApprovalDecision.APPROVE });
      return true;
    },
  },
);
```

---

## Error Handling

The SDK throws `WorkflowAPIError` for API failures, providing access to status codes and response details.

```ts
import { WorkflowAPIError } from '@syncteamsstudio/sdk';

try {
  await client.executeWorkflow({ workflowId: 'invalid', input: {} });
} catch (error) {
  if (error instanceof WorkflowAPIError) {
    console.error('API Error:', error.status, error.data);
  } else {
    console.error('Unexpected error:', error);
  }
}
```

Transient errors (timeouts, rate limits, server errors) are automatically retried.

---

## Webhooks

You can receive workflow updates via webhooks instead of polling:

```ts
import type { WebhookEventPayload } from '@syncteamsstudio/sdk';

app.post('/webhooks/syncteams', async (req, res) => {
  const payload = req.body as WebhookEventPayload;
  
  console.log('Task', payload.taskId, 'status:', payload.status);
  
  // Process the event
  
  res.sendStatus(200);
});
```

Verify signatures with the built-in helper:

```ts
import {
  verifyWebhookSignature,
  WEBHOOK_SIGNATURE_HEADER,
  WEBHOOK_TIMESTAMP_HEADER,
} from '@syncteamsstudio/sdk';

app.post('/webhooks/syncteams', async (req, res) => {
  const rawBody = JSON.stringify(req.body);
  const signatureHeader = req.header(WEBHOOK_SIGNATURE_HEADER) || '';
  const timestampHeader = req.header(WEBHOOK_TIMESTAMP_HEADER) || '';

  const isValid = verifyWebhookSignature({
    payload: rawBody,
    signatureHeader,
    timestampHeader,
    signingSecret: process.env.SYNCTEAMS_WEBHOOK_SECRET!,
  });

  if (!isValid) {
    return res.sendStatus(400);
  }

  return res.sendStatus(200);
});
```

Use the raw JSON request body for verification. If your framework parses/reformats the body before validation, the signature may fail.

---

## TypeScript Support

The SDK is written in TypeScript and includes full type definitions and enums:

```ts
import { 
  WorkflowStatus, 
  ApprovalDecision,
  WorkflowEventType,
  type TaskStatusResponse 
} from '@syncteamsstudio/sdk';

// Use enums for type safety
if (status === WorkflowStatus.COMPLETED) {
  // Handle completion
}

// All available workflow statuses
WorkflowStatus.QUEUED
WorkflowStatus.PENDING
WorkflowStatus.RUNNING
WorkflowStatus.WAITING
WorkflowStatus.CANCELED
WorkflowStatus.FAILED
WorkflowStatus.COMPLETED

// Approval decisions
ApprovalDecision.APPROVE
ApprovalDecision.REJECT
```

---

## Support

- Documentation: [https://www.syncteams.studio/docs](https://www.syncteams.studio/docs)
- Email: support@syncteams.studio

---

## License

MIT