@convertrilo/sdk 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,6 +37,10 @@ The `examples/` directory contains starter scripts for the main integration path
37
37
  Local SDK smoke tests use `.env`, but published SDK users should provide credentials through their
38
38
  own server environment. Do not put Convertrilo API keys or customer storage tokens in frontend code.
39
39
 
40
+ For a complete server-to-server walkthrough covering URL, S3, folder ingest, Google Drive BYO
41
+ OAuth tokens, polling, and webhooks, see
42
+ [`docs/API-INTEGRATION-GUIDE.md`](docs/API-INTEGRATION-GUIDE.md).
43
+
40
44
  ## URL Source To CDN Output
41
45
 
42
46
  ```ts
@@ -110,6 +110,9 @@ export declare class ConvertriloClient {
110
110
  events?: string[];
111
111
  secret?: string;
112
112
  isActive?: boolean;
113
+ failureCount?: number;
114
+ lastTriggeredAt?: string | null;
115
+ lastFailedAt?: string | null;
113
116
  createdAt?: string;
114
117
  }>;
115
118
  deleteWebhook(id: string): Promise<unknown>;
@@ -562,7 +562,10 @@ export interface paths {
562
562
  path?: never;
563
563
  cookie?: never;
564
564
  };
565
- /** List webhooks */
565
+ /**
566
+ * List webhooks
567
+ * @description List managed webhook subscriptions for the authenticated user. Managed webhook deliveries include HMAC-SHA256 signatures.
568
+ */
566
569
  get: {
567
570
  parameters: {
568
571
  query?: never;
@@ -584,7 +587,11 @@ export interface paths {
584
587
  };
585
588
  };
586
589
  put?: never;
587
- /** Create a webhook */
590
+ /**
591
+ * Create a webhook
592
+ * @description Create a managed webhook subscription. The response includes `secret` exactly once.
593
+ * Store it securely and use it to verify `X-Webhook-Signature`.
594
+ */
588
595
  post: {
589
596
  parameters: {
590
597
  query?: never;
@@ -624,7 +631,10 @@ export interface paths {
624
631
  };
625
632
  get?: never;
626
633
  put?: never;
627
- /** Test a webhook */
634
+ /**
635
+ * Test a webhook
636
+ * @description Sends a `webhook.test` event to the configured URL using the same HMAC signature header as managed deliveries.
637
+ */
628
638
  post: {
629
639
  parameters: {
630
640
  query?: never;
@@ -668,7 +678,33 @@ export interface paths {
668
678
  };
669
679
  options?: never;
670
680
  head?: never;
671
- patch?: never;
681
+ /** Update a webhook */
682
+ patch: {
683
+ parameters: {
684
+ query?: never;
685
+ header?: never;
686
+ path: {
687
+ id: string;
688
+ };
689
+ cookie?: never;
690
+ };
691
+ requestBody: {
692
+ content: {
693
+ "application/json": components["schemas"]["WebhookUpdateRequest"];
694
+ };
695
+ };
696
+ responses: {
697
+ /** @description Updated */
698
+ 200: {
699
+ headers: {
700
+ [name: string]: unknown;
701
+ };
702
+ content: {
703
+ "application/json": components["schemas"]["WebhookResponse"];
704
+ };
705
+ };
706
+ };
707
+ };
672
708
  trace?: never;
673
709
  };
674
710
  "/jobs/bulk": {
@@ -1212,8 +1248,12 @@ export interface paths {
1212
1248
  * @description Crawls an S3 prefix or Google Drive folder, queues one encode job per video file,
1213
1249
  * and optionally delivers outputs to CDN, S3, or Google Drive.
1214
1250
  *
1215
- * For API integrations, Google Drive can be used without dashboard OAuth by passing
1216
- * `accessToken` in `sourceGoogleDrive` and/or `outputGoogleDrive`.
1251
+ * For API integrations, use bring-your-own credentials:
1252
+ * - S3-compatible storage: pass `sourceS3` and/or `outputS3` credentials from your backend.
1253
+ * - Google Drive: pass customer OAuth `accessToken` values in `sourceGoogleDrive` and/or `outputGoogleDrive`.
1254
+ * - Include `refreshToken` when jobs may outlive a short access token.
1255
+ *
1256
+ * Your users do not need to connect Google Drive inside the Convertrilo dashboard for API usage.
1217
1257
  */
1218
1258
  post: {
1219
1259
  parameters: {
@@ -1590,6 +1630,12 @@ export interface components {
1590
1630
  url: string;
1591
1631
  events: ("job.created" | "job.queued" | "job.running" | "job.completed" | "job.failed" | "job.canceled")[];
1592
1632
  };
1633
+ WebhookUpdateRequest: {
1634
+ /** Format: uri */
1635
+ url?: string;
1636
+ events?: ("job.created" | "job.queued" | "job.running" | "job.completed" | "job.failed" | "job.canceled")[];
1637
+ isActive?: boolean;
1638
+ };
1593
1639
  WebhookResponse: {
1594
1640
  /** Format: uuid */
1595
1641
  id?: string;
@@ -1598,6 +1644,11 @@ export interface components {
1598
1644
  /** @description HMAC secret, only returned on creation */
1599
1645
  secret?: string;
1600
1646
  isActive?: boolean;
1647
+ failureCount?: number;
1648
+ /** Format: date-time */
1649
+ lastTriggeredAt?: string | null;
1650
+ /** Format: date-time */
1651
+ lastFailedAt?: string | null;
1601
1652
  /** Format: date-time */
1602
1653
  createdAt?: string;
1603
1654
  };
@@ -1615,45 +1666,63 @@ export interface components {
1615
1666
  secretAccessKey?: string;
1616
1667
  forcePathStyle?: boolean;
1617
1668
  };
1669
+ /** @description Customer-owned S3-compatible folder source. Credentials should allow listing the prefix and reading objects. */
1618
1670
  S3FolderSource: {
1619
1671
  bucket: string;
1620
- /** @default */
1672
+ /**
1673
+ * @description Prefix to crawl. Only files with video extensions are queued.
1674
+ * @default
1675
+ */
1621
1676
  prefix?: string;
1622
- /** Format: uri */
1677
+ /**
1678
+ * Format: uri
1679
+ * @description Optional S3-compatible endpoint, for example Cloudflare R2, MinIO, or object storage providers.
1680
+ */
1623
1681
  endpoint?: string;
1624
1682
  region?: string;
1683
+ /** @description Optional source access key. Omit only when your backend/runtime provides credentials another way. */
1625
1684
  accessKeyId?: string;
1626
1685
  /** Format: password */
1627
1686
  secretAccessKey?: string;
1628
1687
  /** @default true */
1629
1688
  forcePathStyle?: boolean;
1630
1689
  };
1690
+ /** @description Customer-owned S3-compatible output destination. Credentials should allow writing encoded objects. */
1631
1691
  S3FolderOutput: {
1632
1692
  bucket: string;
1633
- /** @default outputs/ */
1693
+ /**
1694
+ * @description Output key prefix. The source file name is appended to this prefix.
1695
+ * @default outputs/
1696
+ */
1634
1697
  prefix?: string;
1635
- /** Format: uri */
1698
+ /**
1699
+ * Format: uri
1700
+ * @description Optional S3-compatible endpoint, for example Cloudflare R2, MinIO, or object storage providers.
1701
+ */
1636
1702
  endpoint?: string;
1637
1703
  region?: string;
1704
+ /** @description Optional output access key. Omit only when your backend/runtime provides credentials another way. */
1638
1705
  accessKeyId?: string;
1639
1706
  /** Format: password */
1640
1707
  secretAccessKey?: string;
1641
1708
  /** @default true */
1642
1709
  forcePathStyle?: boolean;
1643
1710
  };
1711
+ /** @description Google Drive folder source for API integrations. Pass a customer-owned OAuth token instead of sending the user through the Convertrilo dashboard. */
1644
1712
  GoogleDriveFolderSource: {
1645
1713
  folderId: string;
1646
- /** @description Short-lived Google OAuth access token supplied by the API caller. */
1714
+ /** @description Short-lived Google OAuth access token supplied by the API caller. Must allow reading/listing files in the folder. */
1647
1715
  accessToken?: string;
1648
- /** @description Optional Google refresh token supplied by the API caller for long-running jobs. */
1716
+ /** @description Optional Google refresh token supplied by the API caller. Recommended for long-running folder jobs so workers can refresh expired access tokens. */
1649
1717
  refreshToken?: string;
1650
1718
  };
1719
+ /** @description Google Drive output destination for API integrations. Pass a customer-owned OAuth token with upload access to the destination folder. */
1651
1720
  GoogleDriveOutput: {
1652
1721
  folderId: string;
1653
1722
  fileName?: string;
1654
- /** @description Short-lived Google OAuth access token supplied by the API caller. */
1723
+ /** @description Short-lived Google OAuth access token supplied by the API caller. Must allow uploading to the destination folder. */
1655
1724
  accessToken?: string;
1656
- /** @description Optional Google refresh token supplied by the API caller for long-running jobs. */
1725
+ /** @description Optional Google refresh token supplied by the API caller. Recommended for long-running jobs so workers can refresh expired access tokens. */
1657
1726
  refreshToken?: string;
1658
1727
  };
1659
1728
  OnDemandEncodeRequest: {
@@ -1698,7 +1767,10 @@ export interface components {
1698
1767
  priority?: "normal" | "high";
1699
1768
  /** @default 86400 */
1700
1769
  outputExpiry?: number;
1701
- /** Format: uri */
1770
+ /**
1771
+ * Format: uri
1772
+ * @description Optional one-off terminal callback URL for this job. Best-effort and unsigned. Use managed webhooks for signed HMAC delivery.
1773
+ */
1702
1774
  webhook?: string;
1703
1775
  outputS3?: components["schemas"]["S3Output"];
1704
1776
  outputGoogleDrive?: components["schemas"]["GoogleDriveOutput"];
@@ -0,0 +1,218 @@
1
+ # API Integration Guide
2
+
3
+ This guide is for server-to-server integrations that want to use Convertrilo as a low-cost video encoding backend.
4
+
5
+ Do not call Convertrilo directly from browser or mobile apps. Keep Convertrilo API keys, S3 credentials, and Google OAuth tokens on your backend.
6
+
7
+ ## Core Model
8
+
9
+ 1. Your app authenticates your user.
10
+ 2. Your backend collects or owns the source video location.
11
+ 3. Your backend calls Convertrilo with an API key.
12
+ 4. Convertrilo queues one or more encode jobs.
13
+ 5. Your backend tracks completion by polling job status or receiving managed webhooks.
14
+
15
+ API users do not need to connect Google Drive in the Convertrilo dashboard. For Google Drive integrations, your app should run its own Google OAuth flow and pass customer-owned `accessToken` and optional `refreshToken` values to Convertrilo.
16
+
17
+ ## Authentication
18
+
19
+ Create an API key in the dashboard Developer page and send it with every request:
20
+
21
+ ```bash
22
+ curl https://api.convertrilo.com/tokens/balance \
23
+ -H "X-API-Key: $CONVERTRILO_API_KEY"
24
+ ```
25
+
26
+ Use API keys with the minimum scopes needed by your integration. Most encode integrations need:
27
+
28
+ - `jobs:create`
29
+ - `jobs:read`
30
+ - `jobs:cancel` if you expose cancellation
31
+
32
+ ## TypeScript SDK
33
+
34
+ ```bash
35
+ pnpm add @convertrilo/sdk
36
+ ```
37
+
38
+ ```ts
39
+ import { ConvertriloClient } from "@convertrilo/sdk";
40
+
41
+ const client = new ConvertriloClient({
42
+ baseUrl: "https://api.convertrilo.com",
43
+ apiKey: process.env.CONVERTRILO_API_KEY,
44
+ });
45
+ ```
46
+
47
+ SDK source and examples: https://github.com/serkandrgn/convertrilo-js
48
+
49
+ ## Flow 1: URL Source To CDN Output
50
+
51
+ Use this when the source video is already available over HTTP(S), and you want Convertrilo to return a signed CDN download URL.
52
+
53
+ ```ts
54
+ const job = await client.onDemandEncode({
55
+ sourceUrl: "https://example.com/input.mp4",
56
+ codec: "h264",
57
+ resolution: "1080p",
58
+ quality: "better",
59
+ });
60
+
61
+ console.log(job.jobId);
62
+ ```
63
+
64
+ Equivalent curl:
65
+
66
+ ```bash
67
+ curl https://api.convertrilo.com/ondemand/encode \
68
+ -H "Content-Type: application/json" \
69
+ -H "X-API-Key: $CONVERTRILO_API_KEY" \
70
+ -d '{
71
+ "sourceUrl": "https://example.com/input.mp4",
72
+ "codec": "h264",
73
+ "resolution": "1080p",
74
+ "quality": "better"
75
+ }'
76
+ ```
77
+
78
+ Poll `/ondemand/status/{jobId}` until the job reaches `success`, then read `downloadUrl`.
79
+
80
+ ## Flow 2: URL Source To S3 Output
81
+
82
+ Use this when your customer wants the encoded output in their own S3-compatible bucket.
83
+
84
+ The output credentials need permission to write the final object.
85
+
86
+ ```ts
87
+ const job = await client.onDemandEncode({
88
+ sourceUrl: "https://example.com/input.mp4",
89
+ codec: "h264",
90
+ resolution: "1080p",
91
+ outputS3: {
92
+ bucket: "customer-output-bucket",
93
+ key: "encoded/input-1080p.mp4",
94
+ region: "us-east-1",
95
+ endpoint: process.env.CUSTOMER_S3_ENDPOINT,
96
+ accessKeyId: process.env.CUSTOMER_S3_ACCESS_KEY_ID,
97
+ secretAccessKey: process.env.CUSTOMER_S3_SECRET_ACCESS_KEY,
98
+ forcePathStyle: true,
99
+ },
100
+ });
101
+ ```
102
+
103
+ For AWS S3, `endpoint` is usually unnecessary. For S3-compatible providers such as Cloudflare R2, MinIO, or object storage providers, pass `endpoint` and usually `forcePathStyle: true`.
104
+
105
+ ## Flow 3: S3 Folder To S3 Output
106
+
107
+ Use this for batch compression. Convertrilo lists a source prefix, filters video files, and queues one encode job per video.
108
+
109
+ Source credentials need permission to list the prefix and read objects. Output credentials need permission to write encoded objects.
110
+
111
+ ```ts
112
+ const batch = await client.onDemandIngestFolder({
113
+ sourceS3: {
114
+ bucket: "customer-source-bucket",
115
+ prefix: "incoming/",
116
+ region: "us-east-1",
117
+ endpoint: process.env.CUSTOMER_S3_ENDPOINT,
118
+ accessKeyId: process.env.CUSTOMER_S3_ACCESS_KEY_ID,
119
+ secretAccessKey: process.env.CUSTOMER_S3_SECRET_ACCESS_KEY,
120
+ forcePathStyle: true,
121
+ },
122
+ outputDestination: "s3",
123
+ outputS3: {
124
+ bucket: "customer-output-bucket",
125
+ prefix: "encoded/",
126
+ region: "us-east-1",
127
+ endpoint: process.env.CUSTOMER_S3_ENDPOINT,
128
+ accessKeyId: process.env.CUSTOMER_S3_ACCESS_KEY_ID,
129
+ secretAccessKey: process.env.CUSTOMER_S3_SECRET_ACCESS_KEY,
130
+ forcePathStyle: true,
131
+ },
132
+ codec: "h264",
133
+ resolution: "1080p",
134
+ });
135
+
136
+ for (const job of batch.jobs || []) {
137
+ console.log(job.jobId, job.fileName);
138
+ }
139
+ ```
140
+
141
+ Only files with video extensions are queued. If no video files are found, the API returns `404`.
142
+
143
+ ## Flow 4: Google Drive With BYO OAuth Tokens
144
+
145
+ Use this when your app already owns the customer relationship and can run Google OAuth itself.
146
+
147
+ Do not send customers to the Convertrilo dashboard OAuth flow for API usage. Your app should request the Google scopes it needs, store tokens on your backend, and pass those tokens to Convertrilo per request.
148
+
149
+ For output-only jobs:
150
+
151
+ ```ts
152
+ const job = await client.onDemandEncode({
153
+ sourceUrl: "https://example.com/input.mp4",
154
+ codec: "h264",
155
+ resolution: "1080p",
156
+ outputGoogleDrive: {
157
+ folderId: "GOOGLE_DRIVE_OUTPUT_FOLDER_ID",
158
+ fileName: "input-1080p.mp4",
159
+ accessToken: customerGoogleAccessToken,
160
+ refreshToken: customerGoogleRefreshToken,
161
+ },
162
+ });
163
+ ```
164
+
165
+ For folder ingest from Google Drive to Google Drive:
166
+
167
+ ```ts
168
+ const batch = await client.onDemandIngestFolder({
169
+ sourceGoogleDrive: {
170
+ folderId: "SOURCE_FOLDER_ID",
171
+ accessToken: customerGoogleAccessToken,
172
+ refreshToken: customerGoogleRefreshToken,
173
+ },
174
+ outputDestination: "google-drive",
175
+ outputGoogleDrive: {
176
+ folderId: "OUTPUT_FOLDER_ID",
177
+ accessToken: customerGoogleAccessToken,
178
+ refreshToken: customerGoogleRefreshToken,
179
+ },
180
+ codec: "h264",
181
+ resolution: "1080p",
182
+ });
183
+ ```
184
+
185
+ Include `refreshToken` when jobs may outlive a short-lived access token. Without a valid access token or refresh token, Google Drive folder ingest returns `401`.
186
+
187
+ ## Tracking Completion
188
+
189
+ For simple integrations, poll status:
190
+
191
+ ```ts
192
+ async function waitForOnDemandJob(jobId: string) {
193
+ while (true) {
194
+ const status = await client.onDemandStatus(jobId);
195
+
196
+ if (status.status === "success") return status;
197
+ if (status.status === "failed" || status.status === "canceled") {
198
+ throw new Error(status.failureMessage || `Job ${status.status}`);
199
+ }
200
+
201
+ await new Promise((resolve) => setTimeout(resolve, 5000));
202
+ }
203
+ }
204
+ ```
205
+
206
+ For production workflows, prefer managed webhooks. Managed webhooks are HMAC signed and are better for async pipelines. See [WEBHOOKS.md](WEBHOOKS.md).
207
+
208
+ ## Error Handling
209
+
210
+ Common responses:
211
+
212
+ - `400`: invalid request payload
213
+ - `401`: missing API auth or missing/expired Google Drive token
214
+ - `403`: API key does not have the required scope
215
+ - `404`: folder ingest found no video files
216
+ - `410`: Dropbox source or destination was requested; Dropbox is deprecated
217
+
218
+ Treat encode job failure separately from request failure. A request can return `200` because the job was queued, then the job can later fail during download, encode, upload, or token refresh.
@@ -0,0 +1,138 @@
1
+ # Webhooks
2
+
3
+ Convertrilo supports managed webhook subscriptions for job lifecycle events.
4
+
5
+ Create managed webhooks in the dashboard Developer page or with `POST /webhooks`.
6
+ Managed webhook deliveries are signed with HMAC-SHA256.
7
+
8
+ ## Events
9
+
10
+ - `job.created`
11
+ - `job.queued`
12
+ - `job.running`
13
+ - `job.completed`
14
+ - `job.failed`
15
+ - `job.canceled`
16
+ - `webhook.test` for manual test deliveries
17
+
18
+ ## Headers
19
+
20
+ Managed webhook deliveries include:
21
+
22
+ ```txt
23
+ Content-Type: application/json
24
+ X-Webhook-Signature: <hex hmac sha256>
25
+ X-Webhook-Event: job.completed
26
+ X-Webhook-Id: <webhook id>
27
+ ```
28
+
29
+ The signature is:
30
+
31
+ ```txt
32
+ hex(hmac_sha256(raw_request_body, webhook_secret))
33
+ ```
34
+
35
+ Use the raw request body exactly as received. Do not parse and stringify JSON before verifying.
36
+
37
+ ## Payload
38
+
39
+ ```json
40
+ {
41
+ "event": "job.completed",
42
+ "timestamp": "2026-06-05T00:00:00.000Z",
43
+ "data": {
44
+ "jobId": "550e8400-e29b-41d4-a716-446655440000",
45
+ "userId": "9c38f5dd-d9d6-4d08-a514-41e166dfbb8b",
46
+ "status": "success",
47
+ "encoder": "h264_nvenc",
48
+ "durationSec": 42,
49
+ "finalNeu": 2.5
50
+ }
51
+ }
52
+ ```
53
+
54
+ Failure events include `error` and `failureCode` when available.
55
+
56
+ ## Verify In Node / Express
57
+
58
+ ```ts
59
+ import crypto from "node:crypto";
60
+ import express from "express";
61
+
62
+ const app = express();
63
+ const webhookSecret = process.env.CONVERTRILO_WEBHOOK_SECRET!;
64
+
65
+ app.post(
66
+ "/webhooks/convertrilo",
67
+ express.raw({ type: "application/json" }),
68
+ (req, res) => {
69
+ const signature = req.header("X-Webhook-Signature") || "";
70
+ const expected = crypto
71
+ .createHmac("sha256", webhookSecret)
72
+ .update(req.body)
73
+ .digest("hex");
74
+
75
+ const valid =
76
+ signature.length === expected.length &&
77
+ crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
78
+
79
+ if (!valid) {
80
+ return res.status(401).send("Invalid signature");
81
+ }
82
+
83
+ const payload = JSON.parse(req.body.toString("utf8"));
84
+ console.log(payload.event, payload.data.jobId);
85
+
86
+ return res.sendStatus(204);
87
+ }
88
+ );
89
+ ```
90
+
91
+ ## Verify In Next.js Route Handler
92
+
93
+ ```ts
94
+ import crypto from "node:crypto";
95
+ import { NextRequest, NextResponse } from "next/server";
96
+
97
+ export async function POST(req: NextRequest) {
98
+ const rawBody = await req.text();
99
+ const signature = req.headers.get("x-webhook-signature") || "";
100
+ const secret = process.env.CONVERTRILO_WEBHOOK_SECRET!;
101
+
102
+ const expected = crypto
103
+ .createHmac("sha256", secret)
104
+ .update(rawBody)
105
+ .digest("hex");
106
+
107
+ const valid =
108
+ signature.length === expected.length &&
109
+ crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
110
+
111
+ if (!valid) {
112
+ return new NextResponse("Invalid signature", { status: 401 });
113
+ }
114
+
115
+ const payload = JSON.parse(rawBody);
116
+ console.log(payload.event, payload.data.jobId);
117
+
118
+ return new NextResponse(null, { status: 204 });
119
+ }
120
+ ```
121
+
122
+ ## Delivery Behavior
123
+
124
+ - Timeout: 15 seconds
125
+ - Success: any `2xx` response
126
+ - Failure: non-`2xx`, network error, or timeout
127
+ - A webhook is automatically disabled after 10 consecutive failures
128
+ - Re-enable it with `PATCH /webhooks/{id}` and `{ "isActive": true }`
129
+
130
+ Current deliveries are best-effort. There is not yet a durable retry queue or delivery history API.
131
+
132
+ ## One-Off On-Demand Webhook URL
133
+
134
+ `POST /ondemand/encode` also accepts a `webhook` URL. That URL receives one terminal callback for
135
+ `job.completed`, `job.failed`, or `job.canceled`.
136
+
137
+ This one-off URL is best-effort and unsigned because it has no stored secret. For production
138
+ workflow integrations, prefer managed webhooks.
package/openapi.yaml CHANGED
@@ -5,6 +5,16 @@ info:
5
5
  description: |
6
6
  JWT-protected API for creating and managing encode jobs. Supports browser-upload, direct URL ingest, or S3 source.
7
7
  Public endpoints are limited and rate-limited.
8
+
9
+ Swagger auth:
10
+ 1. Create an API key in Dashboard -> Developer.
11
+ 2. Click Authorize in these docs.
12
+ 3. Paste the raw API key into ApiKeyAuth.
13
+ 4. Protected endpoints can then be executed from Swagger.
14
+
15
+ API integrations should keep Convertrilo API keys and customer storage/OAuth tokens on the server.
16
+ For storage integrations, pass customer-owned S3 credentials or Google OAuth access/refresh tokens directly in the API request.
17
+ Convertrilo does not require your API users to visit the dashboard OAuth flow.
8
18
 
9
19
  Official TypeScript SDK: https://www.npmjs.com/package/@convertrilo/sdk
10
20
  SDK source and examples: https://github.com/serkandrgn/convertrilo-js
@@ -292,6 +302,24 @@ components:
292
302
  job.failed,
293
303
  job.canceled,
294
304
  ]
305
+ WebhookUpdateRequest:
306
+ type: object
307
+ properties:
308
+ url: { type: string, format: uri }
309
+ events:
310
+ type: array
311
+ items:
312
+ type: string
313
+ enum:
314
+ [
315
+ job.created,
316
+ job.queued,
317
+ job.running,
318
+ job.completed,
319
+ job.failed,
320
+ job.canceled,
321
+ ]
322
+ isActive: { type: boolean }
295
323
  WebhookResponse:
296
324
  type: object
297
325
  properties:
@@ -306,6 +334,9 @@ components:
306
334
  description: "HMAC secret, only returned on creation",
307
335
  }
308
336
  isActive: { type: boolean }
337
+ failureCount: { type: integer }
338
+ lastTriggeredAt: { type: string, format: date-time, nullable: true }
339
+ lastFailedAt: { type: string, format: date-time, nullable: true }
309
340
  createdAt: { type: string, format: date-time }
310
341
  WebhookListResponse:
311
342
  type: object
@@ -329,49 +360,69 @@ components:
329
360
  forcePathStyle: { type: boolean }
330
361
  S3FolderSource:
331
362
  type: object
363
+ description: Customer-owned S3-compatible folder source. Credentials should allow listing the prefix and reading objects.
332
364
  required: [bucket]
333
365
  properties:
334
366
  bucket: { type: string }
335
- prefix: { type: string, default: "" }
336
- endpoint: { type: string, format: uri }
367
+ prefix:
368
+ type: string
369
+ default: ""
370
+ description: Prefix to crawl. Only files with video extensions are queued.
371
+ endpoint:
372
+ type: string
373
+ format: uri
374
+ description: Optional S3-compatible endpoint, for example Cloudflare R2, MinIO, or object storage providers.
337
375
  region: { type: string }
338
- accessKeyId: { type: string }
376
+ accessKeyId:
377
+ type: string
378
+ description: Optional source access key. Omit only when your backend/runtime provides credentials another way.
339
379
  secretAccessKey: { type: string, format: password }
340
380
  forcePathStyle: { type: boolean, default: true }
341
381
  S3FolderOutput:
342
382
  type: object
383
+ description: Customer-owned S3-compatible output destination. Credentials should allow writing encoded objects.
343
384
  required: [bucket]
344
385
  properties:
345
386
  bucket: { type: string }
346
- prefix: { type: string, default: outputs/ }
347
- endpoint: { type: string, format: uri }
387
+ prefix:
388
+ type: string
389
+ default: outputs/
390
+ description: Output key prefix. The source file name is appended to this prefix.
391
+ endpoint:
392
+ type: string
393
+ format: uri
394
+ description: Optional S3-compatible endpoint, for example Cloudflare R2, MinIO, or object storage providers.
348
395
  region: { type: string }
349
- accessKeyId: { type: string }
396
+ accessKeyId:
397
+ type: string
398
+ description: Optional output access key. Omit only when your backend/runtime provides credentials another way.
350
399
  secretAccessKey: { type: string, format: password }
351
400
  forcePathStyle: { type: boolean, default: true }
352
401
  GoogleDriveFolderSource:
353
402
  type: object
403
+ description: Google Drive folder source for API integrations. Pass a customer-owned OAuth token instead of sending the user through the Convertrilo dashboard.
354
404
  required: [folderId]
355
405
  properties:
356
406
  folderId: { type: string }
357
407
  accessToken:
358
408
  type: string
359
- description: Short-lived Google OAuth access token supplied by the API caller.
409
+ description: Short-lived Google OAuth access token supplied by the API caller. Must allow reading/listing files in the folder.
360
410
  refreshToken:
361
411
  type: string
362
- description: Optional Google refresh token supplied by the API caller for long-running jobs.
412
+ description: Optional Google refresh token supplied by the API caller. Recommended for long-running folder jobs so workers can refresh expired access tokens.
363
413
  GoogleDriveOutput:
364
414
  type: object
415
+ description: Google Drive output destination for API integrations. Pass a customer-owned OAuth token with upload access to the destination folder.
365
416
  required: [folderId]
366
417
  properties:
367
418
  folderId: { type: string }
368
419
  fileName: { type: string }
369
420
  accessToken:
370
421
  type: string
371
- description: Short-lived Google OAuth access token supplied by the API caller.
422
+ description: Short-lived Google OAuth access token supplied by the API caller. Must allow uploading to the destination folder.
372
423
  refreshToken:
373
424
  type: string
374
- description: Optional Google refresh token supplied by the API caller for long-running jobs.
425
+ description: Optional Google refresh token supplied by the API caller. Recommended for long-running jobs so workers can refresh expired access tokens.
375
426
  OnDemandEncodeRequest:
376
427
  type: object
377
428
  required: [sourceUrl]
@@ -393,7 +444,10 @@ components:
393
444
  priority: { type: string, enum: [normal, high], default: normal }
394
445
  outputExpiry:
395
446
  { type: integer, minimum: 3600, maximum: 604800, default: 86400 }
396
- webhook: { type: string, format: uri }
447
+ webhook:
448
+ type: string
449
+ format: uri
450
+ description: Optional one-off terminal callback URL for this job. Best-effort and unsigned. Use managed webhooks for signed HMAC delivery.
397
451
  outputS3:
398
452
  $ref: "#/components/schemas/S3Output"
399
453
  outputGoogleDrive:
@@ -758,6 +812,7 @@ paths:
758
812
  get:
759
813
  security: [{ BearerAuth: [] }]
760
814
  summary: List webhooks
815
+ description: List managed webhook subscriptions for the authenticated user. Managed webhook deliveries include HMAC-SHA256 signatures.
761
816
  responses:
762
817
  "200":
763
818
  description: List of webhooks
@@ -768,12 +823,21 @@ paths:
768
823
  post:
769
824
  security: [{ BearerAuth: [] }]
770
825
  summary: Create a webhook
826
+ description: |
827
+ Create a managed webhook subscription. The response includes `secret` exactly once.
828
+ Store it securely and use it to verify `X-Webhook-Signature`.
771
829
  requestBody:
772
830
  required: true
773
831
  content:
774
832
  application/json:
775
833
  schema:
776
834
  $ref: "#/components/schemas/WebhookCreateRequest"
835
+ examples:
836
+ jobCompletionWebhook:
837
+ summary: Completion and failure notifications
838
+ value:
839
+ url: https://your-app.com/webhooks/convertrilo
840
+ events: [job.completed, job.failed, job.canceled]
777
841
  responses:
778
842
  "200":
779
843
  description: Created
@@ -782,6 +846,36 @@ paths:
782
846
  schema:
783
847
  $ref: "#/components/schemas/WebhookResponse"
784
848
  /webhooks/{id}:
849
+ patch:
850
+ security: [{ BearerAuth: [] }]
851
+ summary: Update a webhook
852
+ parameters:
853
+ - in: path
854
+ name: id
855
+ required: true
856
+ schema: { type: string, format: uuid }
857
+ requestBody:
858
+ required: true
859
+ content:
860
+ application/json:
861
+ schema:
862
+ $ref: "#/components/schemas/WebhookUpdateRequest"
863
+ examples:
864
+ reEnableWebhook:
865
+ summary: Re-enable a disabled webhook
866
+ value:
867
+ isActive: true
868
+ changeEvents:
869
+ summary: Receive only terminal job events
870
+ value:
871
+ events: [job.completed, job.failed, job.canceled]
872
+ responses:
873
+ "200":
874
+ description: Updated
875
+ content:
876
+ application/json:
877
+ schema:
878
+ $ref: "#/components/schemas/WebhookResponse"
785
879
  delete:
786
880
  security: [{ BearerAuth: [] }]
787
881
  summary: Delete a webhook
@@ -795,6 +889,7 @@ paths:
795
889
  post:
796
890
  security: [{ BearerAuth: [] }]
797
891
  summary: Test a webhook
892
+ description: Sends a `webhook.test` event to the configured URL using the same HMAC signature header as managed deliveries.
798
893
  parameters:
799
894
  - in: path
800
895
  name: id
@@ -1018,6 +1113,37 @@ paths:
1018
1113
  application/json:
1019
1114
  schema:
1020
1115
  $ref: "#/components/schemas/OnDemandEncodeRequest"
1116
+ examples:
1117
+ urlToCdn:
1118
+ summary: URL source to CDN output
1119
+ value:
1120
+ sourceUrl: https://example.com/video.mp4
1121
+ codec: h264
1122
+ resolution: 1080p
1123
+ quality: better
1124
+ urlToS3:
1125
+ summary: URL source to S3 output
1126
+ value:
1127
+ sourceUrl: https://example.com/video.mp4
1128
+ codec: h264
1129
+ resolution: 1080p
1130
+ outputS3:
1131
+ bucket: customer-output-bucket
1132
+ key: encoded/video-1080p.mp4
1133
+ region: us-east-1
1134
+ accessKeyId: AKIA...
1135
+ secretAccessKey: replace-with-secret
1136
+ urlToGoogleDrive:
1137
+ summary: URL source to Google Drive output with BYO token
1138
+ value:
1139
+ sourceUrl: https://example.com/video.mp4
1140
+ codec: h264
1141
+ resolution: 1080p
1142
+ outputGoogleDrive:
1143
+ folderId: GOOGLE_DRIVE_FOLDER_ID
1144
+ fileName: video-1080p.mp4
1145
+ accessToken: ya29...
1146
+ refreshToken: optional-refresh-token
1021
1147
  responses:
1022
1148
  "200":
1023
1149
  description: Job created and queued
@@ -1057,14 +1183,51 @@ paths:
1057
1183
  Crawls an S3 prefix or Google Drive folder, queues one encode job per video file,
1058
1184
  and optionally delivers outputs to CDN, S3, or Google Drive.
1059
1185
 
1060
- For API integrations, Google Drive can be used without dashboard OAuth by passing
1061
- `accessToken` in `sourceGoogleDrive` and/or `outputGoogleDrive`.
1186
+ For API integrations, use bring-your-own credentials:
1187
+ - S3-compatible storage: pass `sourceS3` and/or `outputS3` credentials from your backend.
1188
+ - Google Drive: pass customer OAuth `accessToken` values in `sourceGoogleDrive` and/or `outputGoogleDrive`.
1189
+ - Include `refreshToken` when jobs may outlive a short access token.
1190
+
1191
+ Your users do not need to connect Google Drive inside the Convertrilo dashboard for API usage.
1062
1192
  requestBody:
1063
1193
  required: true
1064
1194
  content:
1065
1195
  application/json:
1066
1196
  schema:
1067
1197
  $ref: "#/components/schemas/OnDemandFolderIngestRequest"
1198
+ examples:
1199
+ s3FolderToS3:
1200
+ summary: S3 folder source to S3 output
1201
+ value:
1202
+ sourceS3:
1203
+ bucket: customer-source-bucket
1204
+ prefix: incoming/
1205
+ region: us-east-1
1206
+ accessKeyId: AKIA...
1207
+ secretAccessKey: replace-with-secret
1208
+ outputDestination: s3
1209
+ outputS3:
1210
+ bucket: customer-output-bucket
1211
+ prefix: encoded/
1212
+ region: us-east-1
1213
+ accessKeyId: AKIA...
1214
+ secretAccessKey: replace-with-secret
1215
+ codec: h264
1216
+ resolution: 1080p
1217
+ googleDriveFolderToGoogleDrive:
1218
+ summary: Google Drive folder source to Google Drive output
1219
+ value:
1220
+ sourceGoogleDrive:
1221
+ folderId: SOURCE_FOLDER_ID
1222
+ accessToken: ya29...
1223
+ refreshToken: optional-refresh-token
1224
+ outputDestination: google-drive
1225
+ outputGoogleDrive:
1226
+ folderId: OUTPUT_FOLDER_ID
1227
+ accessToken: ya29...
1228
+ refreshToken: optional-refresh-token
1229
+ codec: h264
1230
+ resolution: 1080p
1068
1231
  responses:
1069
1232
  "200":
1070
1233
  description: Folder jobs queued
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@convertrilo/sdk",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "TypeScript client for the Convertrilo video encoding API",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -35,6 +35,7 @@
35
35
  "files": [
36
36
  "dist/src",
37
37
  "examples",
38
+ "docs",
38
39
  "openapi.yaml",
39
40
  "README.md",
40
41
  "LICENSE"