transcodely 0.2.0__tar.gz

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.
Files changed (87) hide show
  1. transcodely-0.2.0/.gitignore +46 -0
  2. transcodely-0.2.0/LICENSE +21 -0
  3. transcodely-0.2.0/PKG-INFO +349 -0
  4. transcodely-0.2.0/README.md +312 -0
  5. transcodely-0.2.0/pyproject.toml +70 -0
  6. transcodely-0.2.0/src/buf/__init__.py +0 -0
  7. transcodely-0.2.0/src/buf/validate/__init__.py +0 -0
  8. transcodely-0.2.0/src/buf/validate/validate_pb2.py +469 -0
  9. transcodely-0.2.0/src/buf/validate/validate_pb2.pyi +651 -0
  10. transcodely-0.2.0/src/transcodely/__init__.py +175 -0
  11. transcodely-0.2.0/src/transcodely/_codec/__init__.py +0 -0
  12. transcodely-0.2.0/src/transcodely/_codec/json_codec.py +193 -0
  13. transcodely-0.2.0/src/transcodely/_transport/__init__.py +0 -0
  14. transcodely-0.2.0/src/transcodely/_transport/error_mapping.py +102 -0
  15. transcodely-0.2.0/src/transcodely/_transport/headers.py +31 -0
  16. transcodely-0.2.0/src/transcodely/_transport/transport.py +312 -0
  17. transcodely-0.2.0/src/transcodely/client.py +160 -0
  18. transcodely-0.2.0/src/transcodely/errors.py +115 -0
  19. transcodely-0.2.0/src/transcodely/pagination.py +53 -0
  20. transcodely-0.2.0/src/transcodely/py.typed +0 -0
  21. transcodely-0.2.0/src/transcodely/resources/__init__.py +0 -0
  22. transcodely-0.2.0/src/transcodely/resources/_helpers.py +29 -0
  23. transcodely-0.2.0/src/transcodely/resources/api_keys.py +48 -0
  24. transcodely-0.2.0/src/transcodely/resources/apps.py +59 -0
  25. transcodely-0.2.0/src/transcodely/resources/events.py +118 -0
  26. transcodely-0.2.0/src/transcodely/resources/health.py +19 -0
  27. transcodely-0.2.0/src/transcodely/resources/jobs.py +120 -0
  28. transcodely-0.2.0/src/transcodely/resources/memberships.py +54 -0
  29. transcodely-0.2.0/src/transcodely/resources/organizations.py +73 -0
  30. transcodely-0.2.0/src/transcodely/resources/origins.py +55 -0
  31. transcodely-0.2.0/src/transcodely/resources/presets.py +63 -0
  32. transcodely-0.2.0/src/transcodely/resources/users.py +46 -0
  33. transcodely-0.2.0/src/transcodely/resources/videos.py +114 -0
  34. transcodely-0.2.0/src/transcodely/resources/webhook_endpoints.py +242 -0
  35. transcodely-0.2.0/src/transcodely/streaming.py +47 -0
  36. transcodely-0.2.0/src/transcodely/types.py +570 -0
  37. transcodely-0.2.0/src/transcodely/v1/api_key_pb2.py +69 -0
  38. transcodely-0.2.0/src/transcodely/v1/api_key_pb2.pyi +97 -0
  39. transcodely-0.2.0/src/transcodely/v1/app_pb2.py +107 -0
  40. transcodely-0.2.0/src/transcodely/v1/app_pb2.pyi +219 -0
  41. transcodely-0.2.0/src/transcodely/v1/codec_av1_pb2.py +55 -0
  42. transcodely-0.2.0/src/transcodely/v1/codec_av1_pb2.pyi +34 -0
  43. transcodely-0.2.0/src/transcodely/v1/codec_h264_pb2.py +71 -0
  44. transcodely-0.2.0/src/transcodely/v1/codec_h264_pb2.pyi +44 -0
  45. transcodely-0.2.0/src/transcodely/v1/codec_h265_pb2.py +69 -0
  46. transcodely-0.2.0/src/transcodely/v1/codec_h265_pb2.pyi +42 -0
  47. transcodely-0.2.0/src/transcodely/v1/codec_vp9_pb2.py +57 -0
  48. transcodely-0.2.0/src/transcodely/v1/codec_vp9_pb2.pyi +30 -0
  49. transcodely-0.2.0/src/transcodely/v1/common_pb2.py +67 -0
  50. transcodely-0.2.0/src/transcodely/v1/common_pb2.pyi +171 -0
  51. transcodely-0.2.0/src/transcodely/v1/content_aware_pb2.py +56 -0
  52. transcodely-0.2.0/src/transcodely/v1/content_aware_pb2.pyi +51 -0
  53. transcodely-0.2.0/src/transcodely/v1/drm_pb2.py +65 -0
  54. transcodely-0.2.0/src/transcodely/v1/drm_pb2.pyi +68 -0
  55. transcodely-0.2.0/src/transcodely/v1/hdr_pb2.py +57 -0
  56. transcodely-0.2.0/src/transcodely/v1/hdr_pb2.pyi +64 -0
  57. transcodely-0.2.0/src/transcodely/v1/health_pb2.py +44 -0
  58. transcodely-0.2.0/src/transcodely/v1/health_pb2.pyi +44 -0
  59. transcodely-0.2.0/src/transcodely/v1/job_pb2.py +201 -0
  60. transcodely-0.2.0/src/transcodely/v1/job_pb2.pyi +546 -0
  61. transcodely-0.2.0/src/transcodely/v1/media_pb2.py +43 -0
  62. transcodely-0.2.0/src/transcodely/v1/media_pb2.pyi +100 -0
  63. transcodely-0.2.0/src/transcodely/v1/membership_pb2.py +71 -0
  64. transcodely-0.2.0/src/transcodely/v1/membership_pb2.pyi +122 -0
  65. transcodely-0.2.0/src/transcodely/v1/organization_pb2.py +81 -0
  66. transcodely-0.2.0/src/transcodely/v1/organization_pb2.pyi +121 -0
  67. transcodely-0.2.0/src/transcodely/v1/origin_pb2.py +157 -0
  68. transcodely-0.2.0/src/transcodely/v1/origin_pb2.pyi +317 -0
  69. transcodely-0.2.0/src/transcodely/v1/preset_pb2.py +192 -0
  70. transcodely-0.2.0/src/transcodely/v1/preset_pb2.pyi +290 -0
  71. transcodely-0.2.0/src/transcodely/v1/streaming_pb2.py +59 -0
  72. transcodely-0.2.0/src/transcodely/v1/streaming_pb2.pyi +56 -0
  73. transcodely-0.2.0/src/transcodely/v1/subtitles_pb2.py +69 -0
  74. transcodely-0.2.0/src/transcodely/v1/subtitles_pb2.pyi +75 -0
  75. transcodely-0.2.0/src/transcodely/v1/thumbnails_pb2.py +63 -0
  76. transcodely-0.2.0/src/transcodely/v1/thumbnails_pb2.pyi +74 -0
  77. transcodely-0.2.0/src/transcodely/v1/user_pb2.py +72 -0
  78. transcodely-0.2.0/src/transcodely/v1/user_pb2.pyi +137 -0
  79. transcodely-0.2.0/src/transcodely/v1/video_pb2.py +166 -0
  80. transcodely-0.2.0/src/transcodely/v1/video_pb2.pyi +367 -0
  81. transcodely-0.2.0/src/transcodely/v1/webhook_pb2.py +151 -0
  82. transcodely-0.2.0/src/transcodely/v1/webhook_pb2.pyi +336 -0
  83. transcodely-0.2.0/src/transcodely/version.py +11 -0
  84. transcodely-0.2.0/src/transcodely/webhooks/__init__.py +44 -0
  85. transcodely-0.2.0/src/transcodely/webhooks/construct_event.py +111 -0
  86. transcodely-0.2.0/src/transcodely/webhooks/signature.py +110 -0
  87. transcodely-0.2.0/src/transcodely/webhooks/types.py +115 -0
@@ -0,0 +1,46 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ *.egg
21
+ .venv/
22
+ venv/
23
+ ENV/
24
+ .tox/
25
+ .pytest_cache/
26
+ .mypy_cache/
27
+ .ruff_cache/
28
+ .build-venv/
29
+
30
+ # Editors
31
+ .idea/
32
+ .vscode/
33
+ *.swp
34
+ *.swo
35
+ *~
36
+ .DS_Store
37
+
38
+ # Logs
39
+ *.log
40
+
41
+ # Env
42
+ .env
43
+ .env.local
44
+
45
+ # Buf
46
+ buf.lock.bak
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Transcodely
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,349 @@
1
+ Metadata-Version: 2.4
2
+ Name: transcodely
3
+ Version: 0.2.0
4
+ Summary: Official Python SDK for the Transcodely video transcoding API
5
+ Project-URL: Homepage, https://transcodely.com
6
+ Project-URL: Documentation, https://transcodely.com/docs
7
+ Project-URL: Repository, https://github.com/transcodely/transcodely-python
8
+ Project-URL: Issues, https://github.com/transcodely/transcodely-python/issues
9
+ Author: Transcodely
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: connect-rpc,dash,encoding,hls,streaming,transcodely,transcoding,video
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Multimedia :: Video :: Conversion
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: protobuf>=5.0
28
+ Requires-Dist: typing-extensions>=4.10
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy>=1.10; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.5; extra == 'dev'
34
+ Provides-Extra: fast
35
+ Requires-Dist: orjson>=3.10; extra == 'fast'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # transcodely
39
+
40
+ Official Python SDK for the [Transcodely](https://transcodely.com) video transcoding API.
41
+
42
+ ```bash
43
+ pip install transcodely
44
+ ```
45
+
46
+ ## Quick start
47
+
48
+ ```python
49
+ import os
50
+ from transcodely import Transcodely
51
+
52
+ with Transcodely(api_key=os.environ["TRANSCODELY_API_KEY"]) as client:
53
+ job = client.jobs.create(
54
+ input_url="https://example.com/source.mp4",
55
+ outputs=[{
56
+ "type": "hls",
57
+ "video": [
58
+ {"codec": "h264", "resolution": "1080p"},
59
+ {"codec": "h264", "resolution": "720p"},
60
+ ],
61
+ }],
62
+ )
63
+ print(job.id) # "job_a1b2c3d4e5f6"
64
+
65
+ for event in client.jobs.watch(job.id):
66
+ print(event.job.status, event.job.progress)
67
+ if event.job.status == 4: # JOB_STATUS_COMPLETED
68
+ break
69
+ ```
70
+
71
+ The simplified-string form (`"hls"`, `"h264"`, `"1080p"`) is what the API actually emits over the wire — the SDK round-trips it transparently to and from the proto enum integers.
72
+
73
+ ## Authentication
74
+
75
+ ```python
76
+ client = Transcodely(api_key=os.environ["TRANSCODELY_API_KEY"])
77
+ ```
78
+
79
+ API keys are opaque `ak_`-prefixed secrets — pass the full value shown once at creation time.
80
+
81
+ ## Resources
82
+
83
+ ```python
84
+ client.jobs # create / get / list / cancel / confirm / watch
85
+ client.videos # upload helpers, multipart, get / list / update / delete / watch
86
+ client.presets # create / get / get_by_slug / list / update / duplicate / archive
87
+ client.origins # create / get / list / update / validate / archive
88
+ client.apps # create / get / list / update / archive / enable_hosting
89
+ client.api_keys # create / get / list / revoke
90
+ client.organizations # create / get / list / update / check_slug
91
+ client.memberships # list / get / update_role / remove
92
+ client.users # get_me / get / list / update_me
93
+ client.health # check
94
+ client.webhook_endpoints # create / retrieve / update / delete / list / rotate_secret / send_test / list_deliveries / get_health
95
+ client.events # retrieve / list / resend
96
+ client.webhooks # construct_event / verify_signature (signature-verification helpers)
97
+ ```
98
+
99
+ ## Origins
100
+
101
+ An origin tells Transcodely where to read source media from and where to write outputs. Every origin belongs to a single provider; pass exactly one provider-config field (`s3`, `gcs`, `http`, or `r2`) on create.
102
+
103
+ ### Create an S3 origin
104
+
105
+ ```python
106
+ origin = client.origins.create(
107
+ name="Production S3",
108
+ permissions=["read", "write"],
109
+ s3={
110
+ "bucket": "my-bucket",
111
+ "region": "us-east-1",
112
+ "credentials": {
113
+ "access_key_id": os.environ["S3_ACCESS_KEY"],
114
+ "secret_access_key": os.environ["S3_SECRET_KEY"],
115
+ },
116
+ # "endpoint": "https://s3.custom.example.com", # for MinIO, Wasabi, etc.
117
+ },
118
+ )
119
+ ```
120
+
121
+ ### Create a GCS origin
122
+
123
+ ```python
124
+ origin = client.origins.create(
125
+ name="Production GCS",
126
+ permissions=["read", "write"],
127
+ gcs={
128
+ "bucket": "my-gcs-bucket",
129
+ "credentials": {
130
+ "service_account_json": os.environ["GCS_SERVICE_ACCOUNT_JSON"],
131
+ },
132
+ },
133
+ )
134
+ ```
135
+
136
+ ### Create an HTTP origin
137
+
138
+ ```python
139
+ origin = client.origins.create(
140
+ name="Public CDN",
141
+ permissions=["read"], # HTTP origins are read-only
142
+ http={
143
+ "base_url": "https://media.example.com",
144
+ "credentials": {
145
+ "headers": {"Authorization": f"Bearer {os.environ['MEDIA_TOKEN']}"},
146
+ },
147
+ },
148
+ )
149
+ ```
150
+
151
+ ### Create an R2 origin
152
+
153
+ R2 supports two forms. With `account_id` (32-char hex) the endpoint is derived for you, optionally with a data-residency jurisdiction:
154
+
155
+ ```python
156
+ origin = client.origins.create(
157
+ name="Production R2",
158
+ permissions=["read", "write"],
159
+ r2={
160
+ "bucket": "media",
161
+ "account_id": os.environ["R2_ACCOUNT_ID"],
162
+ "jurisdiction": "default", # or "eu", "fedramp"
163
+ "credentials": {
164
+ "access_key_id": os.environ["R2_ACCESS_KEY"],
165
+ "secret_access_key": os.environ["R2_SECRET_KEY"],
166
+ },
167
+ },
168
+ )
169
+ ```
170
+
171
+ Or, with an explicit `endpoint` (custom domain bound to a bucket, or a jurisdiction not yet enumerated):
172
+
173
+ ```python
174
+ r2 = {
175
+ "bucket": "media",
176
+ "endpoint": "https://media.example.com",
177
+ "credentials": {
178
+ "access_key_id": os.environ["R2_ACCESS_KEY"],
179
+ "secret_access_key": os.environ["R2_SECRET_KEY"],
180
+ },
181
+ }
182
+ ```
183
+
184
+ Provide either `account_id` or `endpoint`, never both. `jurisdiction` only applies when `account_id` is set.
185
+
186
+ ## Errors
187
+
188
+ All exceptions inherit from `TranscodelyError`:
189
+
190
+ ```python
191
+ from transcodely import (
192
+ Transcodely,
193
+ TranscodelyError,
194
+ InvalidRequestError,
195
+ NotFoundError,
196
+ RateLimitError,
197
+ )
198
+
199
+ try:
200
+ client.jobs.create(input_url=..., outputs=[...])
201
+ except InvalidRequestError as err:
202
+ for v in err.errors:
203
+ print(f"{v.field}: {v.description}")
204
+ except RateLimitError as err:
205
+ time.sleep((err.retry_after_ms or 1000) / 1000)
206
+ except TranscodelyError as err:
207
+ print(f"[{err.request_id}] {err.code}: {err}")
208
+ ```
209
+
210
+ | Class | Status | When |
211
+ |---|---|---|
212
+ | `APIConnectionError` | — | Network / DNS / TLS failure |
213
+ | `APIError` | 5xx | Server-side error |
214
+ | `AuthenticationError` | 401 | Bad / missing / revoked key |
215
+ | `PermissionError` | 403 | Authenticated but forbidden |
216
+ | `NotFoundError` | 404 | Resource doesn't exist |
217
+ | `ConflictError` | 409 | Idempotency conflict, slug taken |
218
+ | `RateLimitError` | 429 | Carries `retry_after_ms` |
219
+ | `InvalidRequestError` | 400 | Carries `errors: list[FieldViolation]` |
220
+ | `PreconditionError` | 412 | Wrong state (e.g. job not cancelable) |
221
+
222
+ Every error carries `request_id`, `code`, `http_status`, and `raw` for debugging.
223
+
224
+ Webhook verification raises `WebhookError` (or a subclass) — see [Webhooks](#webhooks).
225
+
226
+ ## Pagination
227
+
228
+ ```python
229
+ # One page
230
+ page = client.jobs.list(limit=50)
231
+ print(page.items, page.next_cursor)
232
+
233
+ # All items, automatically across pages
234
+ for job in client.jobs.list(limit=50).auto_paging_iter():
235
+ print(job.id)
236
+ ```
237
+
238
+ ## Idempotency
239
+
240
+ `jobs.create` accepts `idempotency_key`. If you don't pass one, the SDK generates a UUID v4 so retries are safe by default. For cross-process safety, pass your own:
241
+
242
+ ```python
243
+ client.jobs.create(
244
+ input_url="...",
245
+ outputs=[...],
246
+ idempotency_key="create-job-for-asset-12345",
247
+ )
248
+ ```
249
+
250
+ For all other write methods, the SDK ships an `Idempotency-Key` HTTP header automatically.
251
+
252
+ ## Streaming watch
253
+
254
+ ```python
255
+ for event in client.jobs.watch(job.id):
256
+ print(event.event, event.job.status, event.job.progress)
257
+ ```
258
+
259
+ The SDK auto-reconnects on transient network failures — Watch is read-only and re-emits a SNAPSHOT on every reconnect. HEARTBEAT events are filtered by default.
260
+
261
+ ## Webhooks
262
+
263
+ Verify a signed delivery and get back a typed `Event`. Pass the **raw** request body (bytes or str — do not re-serialize) and the `Transcodely-Signature` header:
264
+
265
+ ```python
266
+ from transcodely import construct_event, WebhookSignatureError
267
+
268
+ try:
269
+ event = construct_event(
270
+ request.body, # raw bytes/str, exactly as received
271
+ request.headers["transcodely-signature"],
272
+ "whsec_...", # your endpoint's signing secret
273
+ )
274
+ except WebhookSignatureError:
275
+ return Response(status_code=400)
276
+
277
+ # `event.data` is the decoded resource (a Job, JobOutput, Video, or App).
278
+ if event.type == "job.succeeded":
279
+ print("job done:", event.data.id)
280
+ elif event.type == "video.uploaded":
281
+ print("new video:", event.data.id)
282
+ ```
283
+
284
+ `construct_event` also accepts a **list** of secrets so deliveries keep verifying during a secret rotation's overlap window:
285
+
286
+ ```python
287
+ event = construct_event(body, sig_header, ["whsec_previous", "whsec_current"])
288
+ ```
289
+
290
+ Tuning and errors:
291
+
292
+ - `tolerance` (default `300` seconds) bounds clock skew / replay; widen or narrow it per call.
293
+ - `WebhookSignatureError` — header malformed or no signature matched.
294
+ - `WebhookTimestampError` — timestamp outside the tolerance window.
295
+ - `WebhookPayloadError` — body isn't valid JSON or doesn't match the event envelope.
296
+
297
+ All three inherit from `WebhookError`. `client.webhooks.construct_event(...)` is an alias for the module-level function.
298
+
299
+ Manage endpoints and replay events via the API:
300
+
301
+ ```python
302
+ endpoint = client.webhook_endpoints.create(
303
+ app_id="app_123",
304
+ url="https://example.com/hooks/transcodely",
305
+ enabled_events=["job.succeeded", "job.failed"], # or ["*"] for all
306
+ )
307
+ print(endpoint.secret) # shown only on create + rotate_secret — store it now
308
+
309
+ # The same typed Event, fetched from the API instead of an HTTP delivery:
310
+ event = client.events.retrieve("evt_123")
311
+ for event in client.events.list(app_id="app_123").auto_paging_iter():
312
+ print(event.type, event.id)
313
+
314
+ client.events.resend("evt_123") # re-queue delivery to all subscribed endpoints
315
+ ```
316
+
317
+ The 13 event types are `job.created`, `job.succeeded`, `job.failed`, `job.canceled`, `job.progress`, `output.created`, `output.ready`, `output.failed`, `output.progress`, `video.uploaded`, `video.deleted`, `app.created`, and `app.updated`. Subscribe to `"*"` to receive all of them (including ones added later). An unrecognized future type still verifies; its `event.data` is left as a plain `dict`.
318
+
319
+ ## Configuration
320
+
321
+ ```python
322
+ Transcodely(
323
+ api_key, # required
324
+ base_url=None, # default: https://api.transcodely.com
325
+ timeout=30.0, # seconds
326
+ max_retries=3,
327
+ api_version=None, # override the pinned API version
328
+ default_headers=None, # dict, sent on every request
329
+ http_client=None, # custom httpx.Client
330
+ logger=None, # callable(LogEvent)
331
+ )
332
+ ```
333
+
334
+ ## Request IDs
335
+
336
+ ```python
337
+ client.jobs.get("job_x")
338
+ print(client.last_request_id) # "req_*"
339
+ ```
340
+
341
+ Errors also carry the request ID via `err.request_id` for log correlation.
342
+
343
+ ## Versioning
344
+
345
+ The SDK follows semver, starting at `0.1.0`. Breaking changes are allowed on minor bumps until `1.0.0`. Each release pins a specific calendar-versioned API (`Transcodely.API_VERSION`) and sends `Transcodely-Version` on every request.
346
+
347
+ ## License
348
+
349
+ [MIT](LICENSE).