@convertrilo/sdk 0.0.8 → 0.0.10

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
@@ -46,9 +46,16 @@ OAuth tokens, polling, and webhooks, see
46
46
  ```ts
47
47
  const job = await client.onDemandEncode({
48
48
  sourceUrl: "https://example.com/input.mp4",
49
+ externalId: "customer-video-123",
50
+ metadata: {
51
+ customerId: "cus_123",
52
+ workflow: "daily-compression",
53
+ },
49
54
  codec: "h264",
50
55
  resolution: "1080p",
51
56
  quality: "better",
57
+ }, {
58
+ idempotencyKey: "encode-customer-video-123",
52
59
  });
53
60
 
54
61
  let finalStatus;
@@ -117,6 +124,11 @@ Queue one job per video in an S3 prefix:
117
124
 
118
125
  ```ts
119
126
  const batch = await client.onDemandIngestFolder({
127
+ externalIdPrefix: "batch-2026-06-09",
128
+ metadata: {
129
+ customerId: "cus_123",
130
+ workflow: "folder-compression",
131
+ },
120
132
  sourceS3: {
121
133
  bucket: "customer-source-bucket",
122
134
  prefix: "incoming/",
@@ -134,10 +146,12 @@ const batch = await client.onDemandIngestFolder({
134
146
  },
135
147
  codec: "h264",
136
148
  resolution: "1080p",
149
+ }, {
150
+ idempotencyKey: "folder-batch-2026-06-09",
137
151
  });
138
152
 
139
153
  for (const job of batch.jobs || []) {
140
- console.log(job.jobId, job.fileName);
154
+ console.log(job.jobId, job.externalId, job.fileName);
141
155
  }
142
156
  ```
143
157
 
@@ -15,6 +15,9 @@ export type ClientConfig = {
15
15
  apiKey?: string;
16
16
  fetchImpl?: typeof fetch;
17
17
  };
18
+ export type RequestOptions = {
19
+ idempotencyKey?: string;
20
+ };
18
21
  export declare class ConvertriloClient {
19
22
  private baseUrl;
20
23
  private getToken?;
@@ -143,8 +146,12 @@ export declare class ConvertriloClient {
143
146
  };
144
147
  } ? B : any): Promise<unknown>;
145
148
  abortStream(id: string): Promise<unknown>;
146
- onDemandEncode(body: paths["/ondemand/encode"]["post"]["requestBody"]["content"]["application/json"]): Promise<{
149
+ onDemandEncode(body: paths["/ondemand/encode"]["post"]["requestBody"]["content"]["application/json"], options?: RequestOptions): Promise<{
147
150
  jobId: string;
151
+ externalId?: string | null;
152
+ metadata?: {
153
+ [key: string]: unknown;
154
+ } | null;
148
155
  status: string;
149
156
  estimatedDuration?: number;
150
157
  pricing?: {
@@ -157,15 +164,20 @@ export declare class ConvertriloClient {
157
164
  statusUrl: string;
158
165
  webhook?: string | null;
159
166
  }>;
160
- onDemandIngestFolder(body: paths["/ondemand/ingest/folder"]["post"]["requestBody"]["content"]["application/json"]): Promise<{
167
+ onDemandIngestFolder(body: paths["/ondemand/ingest/folder"]["post"]["requestBody"]["content"]["application/json"], options?: RequestOptions): Promise<{
161
168
  message?: string;
162
169
  jobs?: {
163
170
  jobId?: string;
171
+ externalId?: string | null;
164
172
  fileName?: string;
165
173
  }[];
166
174
  }>;
167
175
  onDemandStatus(jobId: string): Promise<{
168
176
  jobId?: string;
177
+ externalId?: string | null;
178
+ metadata?: {
179
+ [key: string]: unknown;
180
+ } | null;
169
181
  status?: string;
170
182
  progress?: number | null;
171
183
  encoder?: string | null;
package/dist/src/index.js CHANGED
@@ -170,16 +170,22 @@ export class ConvertriloClient {
170
170
  return this.request(`/jobs/${id}/stream/abort`, { method: "POST" });
171
171
  }
172
172
  // On-Demand Encoding
173
- async onDemandEncode(body) {
173
+ async onDemandEncode(body, options = {}) {
174
174
  return this.request(`/ondemand/encode`, {
175
175
  method: "POST",
176
176
  body: JSON.stringify(body),
177
+ headers: options.idempotencyKey
178
+ ? { "Idempotency-Key": options.idempotencyKey }
179
+ : undefined,
177
180
  });
178
181
  }
179
- async onDemandIngestFolder(body) {
182
+ async onDemandIngestFolder(body, options = {}) {
180
183
  return this.request(`/ondemand/ingest/folder`, {
181
184
  method: "POST",
182
185
  body: JSON.stringify(body),
186
+ headers: options.idempotencyKey
187
+ ? { "Idempotency-Key": options.idempotencyKey }
188
+ : undefined,
183
189
  });
184
190
  }
185
191
  async onDemandStatus(jobId) {
@@ -1224,11 +1224,15 @@ export interface paths {
1224
1224
  * Submit video for immediate on-demand encoding
1225
1225
  * @description Simplified API for immediate video encoding. Automatically probes, reserves tokens,
1226
1226
  * and starts encoding. Premium pricing (1.5x-2x) for on-demand convenience.
1227
+ * Send `Idempotency-Key` when retrying from your backend to avoid duplicate jobs.
1227
1228
  */
1228
1229
  post: {
1229
1230
  parameters: {
1230
1231
  query?: never;
1231
- header?: never;
1232
+ header?: {
1233
+ /** @description Optional key for safely retrying job creation requests. Reusing the same key with the same request body replays the original response; reusing it with a different body returns 409. */
1234
+ "Idempotency-Key"?: components["parameters"]["IdempotencyKey"];
1235
+ };
1232
1236
  path?: never;
1233
1237
  cookie?: never;
1234
1238
  };
@@ -1311,11 +1315,15 @@ export interface paths {
1311
1315
  * - Include `refreshToken` when jobs may outlive a short access token.
1312
1316
  *
1313
1317
  * Your users do not need to connect Google Drive inside the Convertrilo dashboard for API usage.
1318
+ * Send `Idempotency-Key` when retrying from your backend to avoid duplicate folder batches.
1314
1319
  */
1315
1320
  post: {
1316
1321
  parameters: {
1317
1322
  query?: never;
1318
- header?: never;
1323
+ header?: {
1324
+ /** @description Optional key for safely retrying job creation requests. Reusing the same key with the same request body replays the original response; reusing it with a different body returns 409. */
1325
+ "Idempotency-Key"?: components["parameters"]["IdempotencyKey"];
1326
+ };
1319
1327
  path?: never;
1320
1328
  cookie?: never;
1321
1329
  };
@@ -1812,6 +1820,12 @@ export interface components {
1812
1820
  OnDemandEncodeRequest: {
1813
1821
  /** Format: uri */
1814
1822
  sourceUrl: string;
1823
+ /** @description Your stable job identifier for reconciliation in status responses and webhooks. */
1824
+ externalId?: string;
1825
+ /** @description Integration-owned JSON object returned in status responses and webhooks. */
1826
+ metadata?: {
1827
+ [key: string]: unknown;
1828
+ };
1815
1829
  /**
1816
1830
  * @default h264
1817
1831
  * @enum {string}
@@ -1870,6 +1884,10 @@ export interface components {
1870
1884
  OnDemandEncodeResponse: {
1871
1885
  /** Format: uuid */
1872
1886
  jobId: string;
1887
+ externalId?: string | null;
1888
+ metadata?: {
1889
+ [key: string]: unknown;
1890
+ } | null;
1873
1891
  status: string;
1874
1892
  estimatedDuration?: number;
1875
1893
  pricing?: {
@@ -1885,6 +1903,10 @@ export interface components {
1885
1903
  OnDemandStatusResponse: {
1886
1904
  /** Format: uuid */
1887
1905
  jobId?: string;
1906
+ externalId?: string | null;
1907
+ metadata?: {
1908
+ [key: string]: unknown;
1909
+ } | null;
1888
1910
  status?: string;
1889
1911
  progress?: number | null;
1890
1912
  encoder?: string | null;
@@ -1913,6 +1935,12 @@ export interface components {
1913
1935
  failureMessage?: string | null;
1914
1936
  };
1915
1937
  OnDemandFolderIngestRequest: {
1938
+ /** @description Optional prefix used to generate one externalId per queued file as `${externalIdPrefix}:${fileName}`. */
1939
+ externalIdPrefix?: string;
1940
+ /** @description Integration-owned JSON object attached to every queued job and returned in webhooks/status responses. */
1941
+ metadata?: {
1942
+ [key: string]: unknown;
1943
+ };
1916
1944
  /**
1917
1945
  * @default h264
1918
1946
  * @enum {string}
@@ -1988,6 +2016,7 @@ export interface components {
1988
2016
  jobs?: {
1989
2017
  /** Format: uuid */
1990
2018
  jobId?: string;
2019
+ externalId?: string | null;
1991
2020
  fileName?: string;
1992
2021
  }[];
1993
2022
  };
@@ -2004,7 +2033,10 @@ export interface components {
2004
2033
  };
2005
2034
  };
2006
2035
  responses: never;
2007
- parameters: never;
2036
+ parameters: {
2037
+ /** @description Optional key for safely retrying job creation requests. Reusing the same key with the same request body replays the original response; reusing it with a different body returns 409. */
2038
+ IdempotencyKey: string;
2039
+ };
2008
2040
  requestBodies: never;
2009
2041
  headers: never;
2010
2042
  pathItems: never;
@@ -53,9 +53,16 @@ Use this when the source video is already available over HTTP(S), and you want C
53
53
  ```ts
54
54
  const job = await client.onDemandEncode({
55
55
  sourceUrl: "https://example.com/input.mp4",
56
+ externalId: "customer-video-123",
57
+ metadata: {
58
+ customerId: "cus_123",
59
+ workflow: "daily-compression",
60
+ },
56
61
  codec: "h264",
57
62
  resolution: "1080p",
58
63
  quality: "better",
64
+ }, {
65
+ idempotencyKey: "encode-customer-video-123",
59
66
  });
60
67
 
61
68
  console.log(job.jobId);
@@ -67,8 +74,14 @@ Equivalent curl:
67
74
  curl https://api.convertrilo.com/ondemand/encode \
68
75
  -H "Content-Type: application/json" \
69
76
  -H "X-API-Key: $CONVERTRILO_API_KEY" \
77
+ -H "Idempotency-Key: encode-customer-video-123" \
70
78
  -d '{
71
79
  "sourceUrl": "https://example.com/input.mp4",
80
+ "externalId": "customer-video-123",
81
+ "metadata": {
82
+ "customerId": "cus_123",
83
+ "workflow": "daily-compression"
84
+ },
72
85
  "codec": "h264",
73
86
  "resolution": "1080p",
74
87
  "quality": "better"
@@ -77,6 +90,10 @@ curl https://api.convertrilo.com/ondemand/encode \
77
90
 
78
91
  Poll `/ondemand/status/{jobId}` until the job reaches `success`, then read `downloadUrl`.
79
92
 
93
+ Use `externalId` and `metadata` to reconcile Convertrilo jobs with your own database. They are returned by status responses and managed webhook payloads.
94
+
95
+ Use `Idempotency-Key` on creation requests that your backend may retry. If the same key and request body are received again, Convertrilo returns the original response instead of queuing another job. If the same key is reused with a different body, the API returns `409`.
96
+
80
97
  ## Flow 2: URL Source To S3 Output
81
98
 
82
99
  Use this when your customer wants the encoded output in their own S3-compatible bucket.
@@ -110,6 +127,11 @@ Source credentials need permission to list the prefix and read objects. Output c
110
127
 
111
128
  ```ts
112
129
  const batch = await client.onDemandIngestFolder({
130
+ externalIdPrefix: "batch-2026-06-09",
131
+ metadata: {
132
+ customerId: "cus_123",
133
+ workflow: "folder-compression",
134
+ },
113
135
  sourceS3: {
114
136
  bucket: "customer-source-bucket",
115
137
  prefix: "incoming/",
@@ -131,13 +153,17 @@ const batch = await client.onDemandIngestFolder({
131
153
  },
132
154
  codec: "h264",
133
155
  resolution: "1080p",
156
+ }, {
157
+ idempotencyKey: "folder-batch-2026-06-09",
134
158
  });
135
159
 
136
160
  for (const job of batch.jobs || []) {
137
- console.log(job.jobId, job.fileName);
161
+ console.log(job.jobId, job.externalId, job.fileName);
138
162
  }
139
163
  ```
140
164
 
165
+ For folder ingest, Convertrilo generates each job `externalId` as `${externalIdPrefix}:${fileName}`.
166
+
141
167
  Only files with video extensions are queued. If no video files are found, the API returns `404`.
142
168
 
143
169
  ## Flow 4: Google Drive With BYO OAuth Tokens
package/openapi.yaml CHANGED
@@ -37,6 +37,15 @@ components:
37
37
  type: apiKey
38
38
  in: header
39
39
  name: X-API-Key
40
+ parameters:
41
+ IdempotencyKey:
42
+ in: header
43
+ name: Idempotency-Key
44
+ required: false
45
+ schema:
46
+ type: string
47
+ maxLength: 255
48
+ description: Optional key for safely retrying job creation requests. Reusing the same key with the same request body replays the original response; reusing it with a different body returns 409.
40
49
  schemas:
41
50
  AuthLoginRequest:
42
51
  type: object
@@ -457,6 +466,14 @@ components:
457
466
  required: [sourceUrl]
458
467
  properties:
459
468
  sourceUrl: { type: string, format: uri }
469
+ externalId:
470
+ type: string
471
+ maxLength: 255
472
+ description: Your stable job identifier for reconciliation in status responses and webhooks.
473
+ metadata:
474
+ type: object
475
+ additionalProperties: true
476
+ description: Integration-owned JSON object returned in status responses and webhooks.
460
477
  codec: { type: string, enum: [h264, h265, av1], default: h264 }
461
478
  resolution:
462
479
  {
@@ -493,6 +510,11 @@ components:
493
510
  required: [jobId, status, statusUrl]
494
511
  properties:
495
512
  jobId: { type: string, format: uuid }
513
+ externalId: { type: string, nullable: true }
514
+ metadata:
515
+ type: object
516
+ additionalProperties: true
517
+ nullable: true
496
518
  status: { type: string }
497
519
  estimatedDuration: { type: integer }
498
520
  pricing:
@@ -509,6 +531,11 @@ components:
509
531
  type: object
510
532
  properties:
511
533
  jobId: { type: string, format: uuid }
534
+ externalId: { type: string, nullable: true }
535
+ metadata:
536
+ type: object
537
+ additionalProperties: true
538
+ nullable: true
512
539
  status: { type: string }
513
540
  progress: { type: number, nullable: true }
514
541
  encoder: { type: string, nullable: true }
@@ -537,6 +564,14 @@ components:
537
564
  OnDemandFolderIngestRequest:
538
565
  type: object
539
566
  properties:
567
+ externalIdPrefix:
568
+ type: string
569
+ maxLength: 200
570
+ description: Optional prefix used to generate one externalId per queued file as `${externalIdPrefix}:${fileName}`.
571
+ metadata:
572
+ type: object
573
+ additionalProperties: true
574
+ description: Integration-owned JSON object attached to every queued job and returned in webhooks/status responses.
540
575
  codec: { type: string, enum: [h264, h265, av1], default: h264 }
541
576
  resolution:
542
577
  {
@@ -589,6 +624,7 @@ components:
589
624
  type: object
590
625
  properties:
591
626
  jobId: { type: string, format: uuid }
627
+ externalId: { type: string, nullable: true }
592
628
  fileName: { type: string }
593
629
 
594
630
  # Streaming
@@ -1162,6 +1198,9 @@ paths:
1162
1198
  description: |
1163
1199
  Simplified API for immediate video encoding. Automatically probes, reserves tokens,
1164
1200
  and starts encoding. Premium pricing (1.5x-2x) for on-demand convenience.
1201
+ Send `Idempotency-Key` when retrying from your backend to avoid duplicate jobs.
1202
+ parameters:
1203
+ - $ref: "#/components/parameters/IdempotencyKey"
1165
1204
  requestBody:
1166
1205
  required: true
1167
1206
  content:
@@ -1173,6 +1212,10 @@ paths:
1173
1212
  summary: URL source to CDN output
1174
1213
  value:
1175
1214
  sourceUrl: https://example.com/video.mp4
1215
+ externalId: customer-video-123
1216
+ metadata:
1217
+ customerId: cus_123
1218
+ workflow: daily-compression
1176
1219
  codec: h264
1177
1220
  resolution: 1080p
1178
1221
  quality: better
@@ -1244,6 +1287,9 @@ paths:
1244
1287
  - Include `refreshToken` when jobs may outlive a short access token.
1245
1288
 
1246
1289
  Your users do not need to connect Google Drive inside the Convertrilo dashboard for API usage.
1290
+ Send `Idempotency-Key` when retrying from your backend to avoid duplicate folder batches.
1291
+ parameters:
1292
+ - $ref: "#/components/parameters/IdempotencyKey"
1247
1293
  requestBody:
1248
1294
  required: true
1249
1295
  content:
@@ -1254,6 +1300,10 @@ paths:
1254
1300
  s3FolderToS3:
1255
1301
  summary: S3 folder source to S3 output
1256
1302
  value:
1303
+ externalIdPrefix: batch-2026-06-09
1304
+ metadata:
1305
+ customerId: cus_123
1306
+ workflow: folder-compression
1257
1307
  sourceS3:
1258
1308
  bucket: customer-source-bucket
1259
1309
  prefix: incoming/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@convertrilo/sdk",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "TypeScript client for the Convertrilo video encoding API",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -44,6 +44,12 @@
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
+ "scripts": {
48
+ "clean": "rimraf dist",
49
+ "generate": "openapi-typescript openapi.yaml -o src/types.ts --default-non-nullable false",
50
+ "build": "tsc -p tsconfig.json",
51
+ "prepack": "pnpm run clean && pnpm run generate && pnpm run build"
52
+ },
47
53
  "dependencies": {},
48
54
  "devDependencies": {
49
55
  "@types/node": "^20.11.30",
@@ -52,10 +58,5 @@
52
58
  "rimraf": "^5.0.5",
53
59
  "tsx": "^4.7.0",
54
60
  "typescript": "^5.4.0"
55
- },
56
- "scripts": {
57
- "clean": "rimraf dist",
58
- "generate": "openapi-typescript openapi.yaml -o src/types.ts --default-non-nullable false",
59
- "build": "tsc -p tsconfig.json"
60
61
  }
61
- }
62
+ }