transloadit.mdx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. ---
  2. sidebar_position: 1
  3. slug: /transloadit
  4. ---
  5. import Tabs from '@theme/Tabs';
  6. import TabItem from '@theme/TabItem';
  7. import UppyCdnExample from '/src/components/UppyCdnExample';
  8. # Transloadit
  9. The `@uppy/transloadit` plugin can be used to upload files directly to
  10. [Transloadit](https://transloadit.com/) for all kinds of processing, such as
  11. transcoding video, resizing images, zipping/unzipping, [and much
  12. more][transloadit-services].
  13. ## When should I use it?
  14. :::tip
  15. Not sure which uploader is best for you? Read
  16. “[Choosing the uploader you need](/docs/guides/choosing-uploader)”.
  17. :::
  18. Transloadit’s strength is versatility. By doing video, audio, images, documents,
  19. and more, you only need one vendor for [all your file processing
  20. needs][transloadit-services]. The `@uppy/transloadit` plugin directly uploads to
  21. Transloadit so you only have to worry about creating a
  22. [Template][transloadit-concepts]. Transloadit accepts the files, processes
  23. according to the instructions in the Template, and stores the results in storage
  24. of your choosing, such as a self-owned S3 bucket. The Transloadit plugin uses
  25. [Tus](/docs/tus) under the hood so you don’t have to sacrifice reliable,
  26. resumable uploads.
  27. You should use `@uppy/transloadit` if you don’t want to host your own Tus or
  28. Companion servers, (optionally) need file processing, and store it in the
  29. service (such as S3 or GCS) of your liking. All with minimal effort.
  30. ## Install
  31. <Tabs>
  32. <TabItem value="npm" label="NPM" default>
  33. ```shell
  34. npm install @uppy/transloadit
  35. ```
  36. </TabItem>
  37. <TabItem value="yarn" label="Yarn">
  38. ```shell
  39. yarn add @uppy/transloadit
  40. ```
  41. </TabItem>
  42. <TabItem value="cdn" label="CDN">
  43. <UppyCdnExample>
  44. {`
  45. import { Uppy, Transloadit } from "{{UPPY_JS_URL}}"
  46. new Uppy().use(Transloadit, { /* see options */ })
  47. `}
  48. </UppyCdnExample>
  49. </TabItem>
  50. </Tabs>
  51. ## Use
  52. A quick overview of the complete API.
  53. ```js {10-17} showLineNumbers
  54. import Uppy from '@uppy/core';
  55. import Dashboard from '@uppy/dashboard';
  56. import Transloadit from '@uppy/transloadit';
  57. import '@uppy/core/dist/style.min.css';
  58. import '@uppy/dashboard/dist/style.min.css';
  59. const uppy = new Uppy()
  60. .use(Dashboard, { inline: true, target: 'body' })
  61. .use(Transloadit, {
  62. assemblyOptions: {
  63. params: {
  64. auth: { key: 'your-transloadit-key' },
  65. template_id: 'your-template-id',
  66. },
  67. },
  68. });
  69. // Optionally listen to events
  70. uppy.on('transloadit:assembly-created', (assembly, fileIDs) => {});
  71. uppy.on('transloadit:upload', (file, assembly) => {});
  72. uppy.on('transloadit:assembly-executing', (assembly) => {});
  73. uppy.on('transloadit:result', (stepName, result, assembly) => {});
  74. uppy.on('transloadit:complete', (assembly) => {});
  75. ```
  76. ### Use with Companion
  77. :::note
  78. All [Transloadit plans](https://transloadit.com/pricing/) come with a hosted
  79. version of Companion.
  80. :::
  81. You can use this plugin together with Transloadit’s hosted Companion service to
  82. let your users import files from third party sources across the web. To do so
  83. each provider plugin must be configured with Transloadit’s Companion URLs:
  84. ```js
  85. import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit';
  86. import Dropbox from '@uppy/dropbox';
  87. uppy.use(Dropbox, {
  88. companionUrl: COMPANION_URL,
  89. companionAllowedHosts: COMPANION_ALLOWED_HOSTS,
  90. });
  91. ```
  92. This will already work. Transloadit’s OAuth applications are used to
  93. authenticate your users by default. Your users will be asked to provide
  94. Transloadit access to their files. Since your users are probably not aware of
  95. Transloadit, this may be confusing or decrease trust. You may also hit rate
  96. limits, because the OAuth application is shared between everyone using
  97. Transloadit.
  98. To solve that, you can use your own OAuth keys with Transloadit’s hosted
  99. Companion servers by using Transloadit Template Credentials. [Create a Template
  100. Credential][template-credentials] on the Transloadit site. Select “Companion
  101. OAuth” for the service, and enter the key and secret for the provider you want
  102. to use. Then you can pass the name of the new credentials to that provider:
  103. ```js
  104. import { COMPANION_URL, COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit';
  105. import Dropbox from '@uppy/dropbox';
  106. uppy.use(Dropbox, {
  107. companionUrl: COMPANION_URL,
  108. companionAllowedHosts: COMPANION_ALLOWED_HOSTS,
  109. companionKeysParams: {
  110. key: 'YOUR_TRANSLOADIT_API_KEY',
  111. credentialsName: 'my_companion_dropbox_creds',
  112. },
  113. });
  114. ```
  115. ## API
  116. ### Options
  117. #### `id`
  118. A unique identifier for this plugin (`string`, default: `'Transloadit'`).
  119. #### `service`
  120. The Transloadit API URL to use (`string`, default:
  121. `https://api2.transloadit.com`).
  122. The default will try to route traffic efficiently based on the location of your
  123. users. You could for instance set it to `https://api2-us-east-1.transloadit.com`
  124. if you need the traffic to stay inside a particular region.
  125. #### `limit`
  126. Limit the amount of uploads going on at the same time (`number`, default: `20`).
  127. Setting this to `0` means no limit on concurrent uploads, but we recommend a
  128. value between `5` and `20`. This option is passed through to the
  129. [`@uppy/tus`](/docs/tus) plugin, which this plugin uses internally.
  130. #### `assemblyOptions`
  131. Configure the
  132. [Assembly Instructions](https://transloadit.com/docs/topics/assembly-instructions/),
  133. the fields to send along to the assembly, and authentication
  134. (`object | function`, default: `null`).
  135. The object you can pass or return from a function has this structure:
  136. ```js
  137. {
  138. params: {
  139. auth: { key: 'key-from-transloadit' },
  140. template_id: 'id-from-transloadit',
  141. steps: {
  142. // Overruling Template at runtime
  143. },
  144. notify_url: 'https://your-domain.com/assembly-status',
  145. },
  146. signature: 'generated-signature',
  147. fields: {
  148. // Dynamic or static fields to send along
  149. },
  150. }
  151. ```
  152. - `params` is used to authenticate with Transloadit and using your desired
  153. [template](https://transloadit.com/docs/topics/templates/).
  154. - `auth.key` _(required)_ is your authentication key which you can find on the
  155. “Credentials” page of your account.
  156. - `template_id` _(required)_ is the unique identifier to use the right
  157. template from your account.
  158. - `steps` _(optional)_ can be used to
  159. [overrule Templates at runtime](https://transloadit.com/docs/topics/templates/#overruling-templates-at-runtime).
  160. A typical use case might be changing the storage path on the fly based on
  161. the session user id. For most use cases, we recommend to let your Templates
  162. handle dynamic cases (they can accept `fields` and execute arbitrary
  163. JavaScript as well), and not pass in `steps` from a browser. The template
  164. editor also has extra validations and context.
  165. - `notify_url` _(optional)_ is a pingback with the assembly status as JSON.
  166. For instance, if you don’t want to block the user experience by letting them
  167. wait for your template to complete with
  168. [`waitForEncoding`](#waitForEncoding), but you do want to want to
  169. asynchrounously have an update, you can provide an URL which will be
  170. “pinged” with the assembly status.
  171. - `signature` _(optional, but recommended)_ is a cryptographic signature to
  172. provide further trust in unstrusted environments. Refer to
  173. “[Signature Authentication”](https://transloadit.com/docs/topics/signature-authentication/)
  174. for more information.
  175. - `fields` _(optional)_ can be used to to send along key/value pairs, which can
  176. be
  177. [used dynamically in your template](https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions).
  178. <details>
  179. <summary>Examples</summary>
  180. **As a function**
  181. A custom `assemblyOptions()` option should return an object or a promise for an
  182. object.
  183. ```js
  184. uppy.use(Transloadit, {
  185. assemblyOptions(file) {
  186. return {
  187. params: {
  188. auth: { key: 'TRANSLOADIT_AUTH_KEY_HERE' },
  189. template_id: 'xyz',
  190. },
  191. fields: {
  192. caption: file.meta.caption,
  193. },
  194. };
  195. },
  196. });
  197. ```
  198. The `${fields.caption}` variable will be available in the Assembly spawned from
  199. Template `xyz`. You can use this to dynamically watermark images for example.
  200. `assemblyOptions()` may also return a Promise, so it could retrieve signed
  201. Assembly parameters from a server. For example, assuming an endpoint
  202. `/transloadit-params` that responds with a JSON object with
  203. `{ params, signature }` properties:
  204. ```js
  205. uppy.use(Transloadit, {
  206. async assemblyOptions(file) {
  207. const res = await fetch('/transloadit-params');
  208. return response.json();
  209. },
  210. });
  211. ```
  212. **As an object**
  213. If you don’t need to change anything dynamically, you can also pass an object
  214. directly.
  215. ```js
  216. uppy.use(Transloadit, {
  217. assemblyOptions: {
  218. params: { auth: { key: 'transloadit-key' } },
  219. },
  220. });
  221. ```
  222. **Use with @uppy/form**
  223. Combine the `assemblyOptions()` option with the [Form](/docs/form) plugin to
  224. pass user input from a `<form>` to a Transloadit Assembly:
  225. ```js
  226. // This will add form field values to each file's `.meta` object:
  227. uppy.use(Form, { getMetaFromForm: true });
  228. uppy.use(Transloadit, {
  229. getAssemblyOptions(file) {
  230. return {
  231. params: {
  232. /* ... */
  233. },
  234. // Pass through the fields you need:
  235. fields: {
  236. message: file.meta.message,
  237. },
  238. };
  239. },
  240. });
  241. ```
  242. </details>
  243. :::caution
  244. When you go to production always make sure to set the `signature`. **Not using
  245. [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/)
  246. can be a security risk**. Signature Authentication is a security measure that
  247. can prevent outsiders from tampering with your Assembly Instructions. While
  248. Signature Authentication is not implemented (yet), we recommend to disable
  249. `allow_steps_override` in your Templates to avoid outsiders being able to pass
  250. in any Instructions and storage targets on your behalf.
  251. :::
  252. #### `waitForEncoding`
  253. Wait for the template to finish, rather than only the upload, before marking the
  254. upload complete (`boolean`, default: `false`).
  255. - When `false`, the Assemblies will complete (or error) in the background but
  256. Uppy won’t know or care about it. You may have to let Transloadit ping you via
  257. a `notify_url` and asynchronously inform your user (email, in-app
  258. notification).
  259. - When `true`, the Transloadit plugin waits for Assemblies to complete before
  260. the files are marked as completed. This means users have to wait for a
  261. potentially long time, depending on how complicated your Assembly instructions
  262. are. But, you can receive the final status and transcoding results on the
  263. client side with less effort.
  264. When this is enabled, you can listen for the
  265. [`transloadit:result`](#transloaditresult) and
  266. [`transloadit:complete`](#transloaditcomplete) events.
  267. #### `waitForMetadata`
  268. Wait for Transloadit’s backend to catch early errors, not the entire Assembly to
  269. complete. (`boolean`, default: `false`)
  270. When set to `true`, the Transloadit plugin waits for Transloadit’s backend to
  271. extract metadata from all the uploaded files. This is mostly handy if you want
  272. to have a quick user experience (so your users don’t necessarily need to wait
  273. for all the encoding to complete), but you do want to let users know about some
  274. types of errors that can be caught early on, like file format issues.
  275. You you can listen for the [`transloadit:upload`](#transloaditupload) event when
  276. this or `waitForEncoding` is enabled.
  277. #### `importFromUploadURLs`
  278. Allow another plugin to upload files, and then import those files into the
  279. Transloadit Assembly (`boolean`, default: `false`).
  280. When enabling this option, Transloadit will _not_ configure the Tus plugin to
  281. upload to Transloadit. Instead, a separate upload plugin must be used. Once the
  282. upload completes, the Transloadit plugin adds the uploaded file to the Assembly.
  283. For example, to upload files to an S3 bucket and then transcode them:
  284. ```js
  285. uppy.use(AwsS3, {
  286. getUploadParameters(file) {
  287. return {
  288. /* upload parameters */
  289. };
  290. },
  291. });
  292. uppy.use(Transloadit, {
  293. importFromUploadURLs: true,
  294. assemblyOptions: {
  295. params: {
  296. auth: { key: 'YOUR_API_KEY' },
  297. template_id: 'YOUR_TEMPLATE_ID',
  298. },
  299. },
  300. });
  301. ```
  302. Tranloadit will download the files and expose them to your Template as
  303. `:original`, as if they were directly uploaded from the Uppy client.
  304. :::note
  305. For this to work, the upload plugin must assign a publicly accessible
  306. `uploadURL` property to the uploaded file object. The Tus and S3 plugins both do
  307. this automatically, but you must configure your S3 bucket to have publicly
  308. readable objects. For the XHRUpload plugin, you may have to specify a custom
  309. `getResponseData` function.
  310. :::
  311. #### `alwaysRunAssembly`
  312. Always create and run an Assembly when `uppy.upload()` is called, even if no
  313. files were selected (`boolean`, default: `false`).
  314. This allows running Assemblies that do not receive files, but instead use a
  315. robot like [`/s3/import`](https://transloadit.com/docs/transcoding/#s3-import)
  316. to download the files from elsewhere, for example, for a bulk transcoding job.
  317. #### `locale`
  318. ```js
  319. export default {
  320. strings: {
  321. // Shown while Assemblies are being created for an upload.
  322. creatingAssembly: 'Preparing upload...',
  323. // Shown if an Assembly could not be created.
  324. creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
  325. // Shown after uploads have succeeded, but when the Assembly is still executing.
  326. // This only shows if `waitForMetadata` or `waitForEncoding` was enabled.
  327. encoding: 'Encoding...',
  328. },
  329. };
  330. ```
  331. #### `clientName`
  332. Append a custom client name to the `Transloadit-Client` header field when
  333. creating an Assembly (`string`, default: `null`).
  334. The `Transloadit-Client` header includes by default information about the used
  335. SDK and is included in the Assembly Status under the `transloadit_client`
  336. property. By providing a value, such as `homepage-file-uploader`, you can
  337. identify the client and SDK that created a given Assembly.
  338. <details>
  339. <summary>Deprecated options</summary>
  340. These options have been deprecated in favor of
  341. [`assemblyOptions`](#assemblyoptions), which we now recommend for all use cases.
  342. You can still use these options, but they will be removed in the next major
  343. version.
  344. #### `getAssemblyOptions`
  345. This function behaves the same as passing a function to
  346. [`assemblyOptions`](#assemblyoptions).
  347. #### `params`
  348. The Assembly parameters to use for the upload (`object`, default: `null`) See
  349. the Transloadit documentation on
  350. [Assembly Instructions](https://transloadit.com/docs/#14-assembly-instructions)
  351. for further information.
  352. The `auth.key` Assembly parameter is required. You can also use the `steps` or
  353. `template_id` options here as described in the Transloadit documentation.
  354. ```js
  355. uppy.use(Transloadit, {
  356. params: {
  357. auth: { key: 'YOUR_TRANSLOADIT_KEY' },
  358. steps: {
  359. encode: {
  360. robot: '/video/encode',
  361. use: {
  362. steps: [':original'],
  363. fields: ['file_input_field2'],
  364. },
  365. preset: 'iphone',
  366. },
  367. },
  368. },
  369. });
  370. ```
  371. #### `signature`
  372. An optional signature for the Assembly parameters. See the Transloadit
  373. documentation on
  374. [Signature Authentication](https://transloadit.com/docs/#26-signature-authentication)
  375. for further information.
  376. If a `signature` is provided, `params` should be a JSON string instead of a
  377. JavaScript object, as otherwise the generated JSON in the browser may be
  378. different from the JSON string that was used to generate the signature.
  379. #### `fields`
  380. An object of form fields to send along to the Assembly. Keys are field names,
  381. and values are field values. See also the Transloadit documentation on
  382. [Form Fields In Instructions](https://transloadit.com/docs/#23-form-fields-in-instructions).
  383. ```js
  384. uppy.use(Transloadit, {
  385. // ...
  386. fields: {
  387. message: 'This is a form field',
  388. },
  389. });
  390. ```
  391. You can also pass an array of field names to send global or file metadata along
  392. to the Assembly. Global metadata is set using the
  393. [`meta` option](/docs/uppy/#meta) in the Uppy constructor, or using the
  394. [`setMeta` method](/docs/uppy/#uppy-setMeta-data). File metadata is set using
  395. the [`setFileMeta`](/docs/uppy/#uppy-setFileMeta-fileID-data) method. The
  396. [Form](/docs/form) plugin also sets global metadata based on the values of
  397. `<input />`s in the form, providing a handy way to use values from HTML form
  398. fields:
  399. ```js
  400. uppy.use(Form, { target: 'form#upload-form', getMetaFromForm: true });
  401. uppy.use(Transloadit, {
  402. fields: ['field_name', 'other_field_name'],
  403. params: {
  404. /* ... */
  405. },
  406. });
  407. ```
  408. Form fields can also be computed dynamically using custom logic, by using the
  409. [`getAssemblyOptions(file)`](/docs/transloadit/#getAssemblyOptions-file) option.
  410. </details>
  411. ### Static exports
  412. #### `COMPANION_URL`
  413. The main endpoint for Transloadit’s hosted companions. You can use this constant
  414. in remote provider options, like so:
  415. ```js
  416. import Dropbox from '@uppy/dropbox';
  417. import { COMPANION_URL } from '@uppy/transloadit';
  418. uppy.use(Dropbox, {
  419. companionUrl: COMPANION_URL,
  420. });
  421. ```
  422. When using `COMPANION_URL`, you should also configure
  423. [`companionAllowedHosts`](#companion_allowed_hosts).
  424. The value of this constant is `https://api2.transloadit.com/companion`. If you
  425. are using a custom [`service`](#service) option, you should also set a custom
  426. host option in your provider plugins, by taking a Transloadit API url and
  427. appending `/companion`:
  428. ```js
  429. uppy.use(Dropbox, {
  430. companionUrl: 'https://api2-us-east-1.transloadit.com/companion',
  431. });
  432. ```
  433. #### `COMPANION_ALLOWED_HOSTS`
  434. A RegExp pattern matching Transloadit’s hosted companion endpoints. The pattern
  435. is used in remote provider `companionAllowedHosts` options, to make sure that
  436. third party authentication messages cannot be faked by an attacker’s page but
  437. can only originate from Transloadit’s servers.
  438. Use it whenever you use `companionUrl: COMPANION_URL`, like so:
  439. ```js
  440. import Dropbox from '@uppy/dropbox';
  441. import { COMPANION_ALLOWED_HOSTS } from '@uppy/transloadit';
  442. uppy.use(Dropbox, {
  443. companionAllowedHosts: COMPANION_ALLOWED_HOSTS,
  444. });
  445. ```
  446. The value of this constant covers _all_ Transloadit’s Companion servers, so it
  447. does not need to be changed if you are using a custom [`service`](#service)
  448. option. But, if you are not using the Transloadit Companion servers at
  449. `*.transloadit.com`, make sure to set the `companionAllowedHosts` option to
  450. something that matches what you do use.
  451. ### Events
  452. #### `transloadit:assembly-created`
  453. Fired when an Assembly is created.
  454. **Parameters**
  455. - `assembly` - The initial [Assembly Status][assembly-status].
  456. - `fileIDs` - The IDs of the files that will be uploaded to this Assembly.
  457. ```js
  458. uppy.on('transloadit:assembly-created', (assembly, fileIDs) => {
  459. console.group('Created', assembly.assembly_id, 'for files:');
  460. for (const id of fileIDs) {
  461. console.log(uppy.getFile(id).name);
  462. }
  463. console.groupEnd();
  464. });
  465. ```
  466. #### `transloadit:upload`
  467. Fired when Transloadit has received an upload. Requires
  468. [`waitForMetadata`](#waitformetadata) to be set.
  469. **Parameters**
  470. - `file` - The Transloadit file object that was uploaded.
  471. - `assembly` - The [Assembly Status][assembly-status] of the Assembly to which
  472. the file was uploaded.
  473. #### `transloadit:assembly-executing`
  474. Fired when Transloadit has received all uploads, and is executing the Assembly.
  475. **Parameters**
  476. - `assembly` - The
  477. [Assembly Status](https://transloadit.com/docs/api/#assembly-status-response)
  478. of the Assembly that is executing.
  479. #### `transloadit:result`
  480. Fired when a result came in from an Assembly. Requires
  481. [`waitForEncoding`](#waitforencoding) to be set.
  482. **Parameters**
  483. - `stepName` - The name of the Assembly step that generated this result.
  484. - `result` - The result object from Transloadit. This result object has one more
  485. property, namely `localId`. This is the ID of the file in Uppy’s local state,
  486. and can be used with `uppy.getFile(id)`.
  487. - `assembly` - The [Assembly Status][assembly-status] of the Assembly that
  488. generated this result.
  489. ```js
  490. uppy.on('transloadit:result', (stepName, result) => {
  491. const file = uppy.getFile(result.localId);
  492. document.body.appendChild(html`
  493. <div>
  494. <h2>From ${file.name}</h2>
  495. <a href=${result.ssl_url}> View </a>
  496. </div>
  497. `);
  498. });
  499. ```
  500. #### `transloadit:complete`
  501. Fired when an Assembly completed. Requires [`waitForEncoding`](#waitForEncoding)
  502. to be set.
  503. **Parameters**
  504. - `assembly` - The final [Assembly Status][assembly-status] of the completed
  505. Assembly.
  506. ```js
  507. uppy.on('transloadit:complete', (assembly) => {
  508. // Could do something fun with this!
  509. console.log(assembly.results);
  510. });
  511. ```
  512. ## Frequently Asked Questions
  513. ### Accessing the assembly when an error occurred
  514. If an error occurs when an Assembly has already started, you can find the
  515. Assembly Status on the error object’s `assembly` property.
  516. ```js
  517. uppy.on('error', (error) => {
  518. if (error.assembly) {
  519. console.log(`Assembly ID ${error.assembly.assembly_id} failed!`);
  520. console.log(error.assembly);
  521. }
  522. });
  523. ```
  524. ### Assembly behavior when Uppy is closed
  525. When integrating `@uppy/transloadit` with `@uppy/dashboard`, closing the
  526. dashboard will result in continuing assemblies on the server. When the user
  527. manually cancels the upload any running assemblies will be cancelled.
  528. [assembly-status]: https://transloadit.com/docs/api/#assembly-status-response
  529. [template-credentials]:
  530. https://transloadit.com/docs/#how-to-create-template-credentials
  531. [transloadit-services]: https://transloadit.com/services/
  532. [transloadit-concepts]: https://transloadit.com/docs/getting-started/concepts/