npm package: @nextcut/sdk
Description: Official Node.js SDK for the NextCut Video API
Latest version: 1.0.0

# @nextcut/sdk

Official Node.js SDK for the [NextCut Video API](https://nextcut.io/features/video-api).

## Install

```bash
npm install @nextcut/sdk
```

## Quick Start

```typescript
import NextCut from '@nextcut/sdk';

const nc = new NextCut('your-api-key');

// Render a video from scenes
const video = await nc.render({
  scenes: [{
    startFrame: 0,
    endFrame: 300,
    layers: [
      { type: 'video', props: { src: 'https://example.com/bg.mp4' } },
      { type: 'text', props: { content: 'Hello World', fontSize: 64, color: '#ffffff' } },
    ],
  }],
  width: 1920,
  height: 1080,
  fps: 30,
});

console.log(video.outputUrl);
```

## API Reference

### `new NextCut(config)`

```typescript
// Simple — just an API key
const nc = new NextCut('your-api-key');

// Full config
const nc = new NextCut({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.nextcut.io',  // default
  timeout: 120_000,                    // default: 2 minutes
});
```

### `nc.render(options)` — Render from scenes

```typescript
const result = await nc.render({
  scenes: [{ startFrame: 0, endFrame: 150, layers: [...] }],
  width: 1920,
  height: 1080,
  fps: 30,
  webhookUrl: 'https://yourapp.com/webhook',
});
```

### `nc.renderTemplate(options)` — Render from a saved template

```typescript
const result = await nc.renderTemplate({
  template: 'template-uuid',
  fields: {
    headline: 'Summer Sale',
    logoUrl: 'https://example.com/logo.png',
  },
});
```

### `nc.stitch(options)` — Merge video clips

```typescript
const result = await nc.stitch({
  clips: [
    { src: 'https://example.com/intro.mp4' },
    { src: 'https://example.com/main.mp4' },
    { src: 'https://example.com/outro.mp4' },
  ],
  transition: { type: 'fade', durationInFrames: 15 },
});
```

### `nc.smartStitch(options)` — Auto-cut silence

```typescript
const result = await nc.smartStitch({
  clips: [{ src: 'https://example.com/recording.mp4' }],
  silenceThreshold: -30,
  minSilenceDuration: 0.5,
});
```

### `nc.trim(options)` — Extract a segment

```typescript
const result = await nc.trim({
  src: 'https://example.com/long-video.mp4',
  startSeconds: 10,
  endSeconds: 25,
});
```

### `nc.captions(options)` — Auto-caption a video

```typescript
const result = await nc.captions({
  videoUrl: 'https://example.com/interview.mp4',
  captionStyle: 'karaoke',
  position: 'bottom',
  highlightColor: '#FFD700',
});
```

### `nc.slideshow(options)` — Images to video

```typescript
const result = await nc.slideshow({
  images: [
    { src: 'https://example.com/1.jpg', durationInFrames: 90 },
    { src: 'https://example.com/2.jpg', durationInFrames: 90 },
  ],
  transition: { type: 'fade', durationInFrames: 15 },
  audioSrc: 'https://example.com/music.mp3',
});
```

### `nc.thumbnail(options)` — Export a frame

```typescript
const thumb = await nc.thumbnail({
  src: 'https://example.com/video.mp4',
  frame: 90,
  imageFormat: 'png',
});
console.log(thumb.outputUrl);
```

### `nc.probe(options)` — Get video metadata

```typescript
const info = await nc.probe({ src: 'https://example.com/video.mp4' });
console.log(`${info.width}x${info.height} @ ${info.fps}fps, ${info.duration}s`);
```

### `nc.htmlToImage(options)` — HTML to PNG

```typescript
const result = await nc.htmlToImage({
  pages: [{ html: '<h1>Hello</h1>', width: 1200, height: 630 }],
});
console.log(result.images[0].url);
```

## Webhooks

### Verify incoming webhook signatures

```typescript
import { verifyWebhook } from '@nextcut/sdk';

app.post('/webhook', async (req, res) => {
  const isValid = await verifyWebhook(
    req.body,                              // raw body string
    req.headers['x-nextcut-signature'],    // HMAC signature
    process.env.WEBHOOK_SECRET!            // your secret
  );

  if (!isValid) return res.status(401).send('Invalid signature');

  const payload = JSON.parse(req.body);
  console.log(payload.status, payload.outputUrl);
});
```

## Error Handling

```typescript
import { NextCutError } from '@nextcut/sdk';

try {
  await nc.render({ ... });
} catch (err) {
  if (err instanceof NextCutError) {
    console.error(`[${err.code}] ${err.message} (status: ${err.status})`);
    if (err.retryable) {
      // Safe to retry (rate limit, timeout, server error)
    }
  }
}
```

## License

MIT