Recuro Media API
Restore and colorize film from your own program: upload a file, see what the job would cost, try a free preview frame, run restoration, Reconstruct, colorization, frame interpolation and sound restoration on our servers, and download the result - from a media asset manager, a render farm, a script or a plugin of an editing application. You can do most of what the workspace on our website does. These stay on the website: paying (top-ups, orders, invoices), the crop mask (anamorphic and letterbox corrections), video previews, saving your own presets, SFTP delivery servers, the project fields (Project Owner, Project ID) and the account settings.
New to APIs? Read Start here (5 minutes), then make your first call. Experienced? The workflow, the reference and the machine-readable openapi.yaml (OpenAPI 3.1) are what you need.
- Base address:
https://www.recuromedia.com/api/1.0- HTTPS only. Requests and responses are JSON (application/json; charset=utf-8), except chunks of files, images and results. - Versioning: this is version 1.0, at
/api/1.0. It only grows: we add fields, endpoints and error codes without notice, so your program must ignore fields it does not know. A change that would break a program gets a new version address; none is planned. - Never put an API key into a web page's JavaScript: every visitor could read it. Call the API from
your server or a desktop program. (The API answers browser requests from other addresses - CORS,
Access-Control-Allow-Origin: *, no cookies - for the desktop plugins' web views, not to put secrets into web pages.)
The API was rebuilt on 6 Oct 2026. Requests in the earlier form (one address with an action field) answer
ApiActionRetired.
Start here
This part is for you if you have never used an API before. It explains what an API is, what ours does, what you need, and every word the rest of the page uses.
What an API is
An API (application programming interface) lets one program use another program over the internet: your program sends a request to our server, and our server sends back a response with data your program can read - no person clicks a button. You can try it in a terminal window with one command (your first call) before you write a single line of a program.
What you can do with our API
- Send us film: upload a video or sound file of up to 50 GiB in pieces that survive a broken connection, or let us fetch it from an https address.
- Learn about it: we analyse every file - length, frame rate, frame size, black borders, black-and-white or colour, scenes, sound, timecode.
- Know the price first: a quote tells you what a job costs and whether your balance covers it.
- Try for free: a preview shows one frame before and after, without charge.
- Process it: restoration (noise, dust and scratches, flicker, colour, stability, sharpness), Reconstruct, colorization (with your review of the colours), frame interpolation, sound restoration - in MOV, MXF or MP4.
- Get it back: follow the progress, download the result (resumable), or hand out a download link; let us call your server when a job is done (webhooks).
What you need before you start
- An account. Sign up on the website with Sign Up at the top of the page, and confirm your e-mail address. A company account has one administrator: the person who signed up.
- API access. Contact us and ask us to switch on API access for your administrator account. Until we have, the next step is not shown.
- An API key and secret. Signed in as the administrator, open My Account (top right) > Administrator Tools, find API Key and Secret and press CREATE API SECRET. The key (16 characters) and the secret (32 characters) appear. Copy the secret at once: it is shown only this one time. Keep it in a password manager or your server's secret store - never in your code or in a repository. Lost it? Press DELETE API SECRET..., then CREATE API SECRET again; the old secret stops working at that moment.
- Money or seconds on the account. Jobs are paid from a prepaid balance (top it up in the workspace) or, by agreement, by invoice. Previews and quotes are free. See Billing.
- A tool to send requests. curl is already on Windows 10 and 11, macOS and Linux. For programs: any language that can send HTTPS requests; our full example is in Python 3.8 or later.
Words you will meet
Each word has a tiny example. Links to these words appear across the page.
- API (application programming interface)
- A way for one program to use another program over the internet. Your program sends a request to our server and gets a response back - no person clicks anything. Example: Your script asks "what does it cost?" and gets the price as data.
- Request
- One message from your program to our server: an HTTP method, an address, headers and sometimes a body. Example:
GET https://www.recuromedia.com/api/1.0/me - Response
- The message our server sends back to one request: a status code, headers and - except for 204 and 304 - a body, which is JSON unless you downloaded a file or an image. Example:
200 OKwith{"user": {...}} - Base address
- The beginning that every address of this API shares. You add the path of an endpoint to it. Example:
https://www.recuromedia.com/api/1.0+/me - Endpoint
- One HTTP method together with one path: one thing the API can do. The reference lists all of them. Example:
POST /jobsstarts a job. - Path parameter
- A part of the path that you fill in, written in curly brackets in this documentation. Example:
/jobs/{job_id}becomes/jobs/job_3150. - Query parameter
- An option added to the address after a question mark; several are joined with
&. Example:/media?status=ready&limit=2 - HTTP method
- The kind of request:
GETreads,POSTcreates or does something,PUTreplaces or saves,DELETEremoves,HEADreads only the headers. Example:DELETE /jobs/job_3150deletes a job. - Status code
- A three-digit number at the start of every response that says how the request went: 2xx worked, 3xx nothing new, 4xx your request has a problem, 5xx our side has a problem. All of them are explained under Errors. Example:
201 Created,404 Not Found - Header
- A name and a value sent before the body of a request or a response, for information about it (who you are, the body's format, when to ask again). Example:
Content-Type: application/json - Body
- The content of a request or response after the headers. In this API it is JSON, except when you send a chunk of a file or download an image or a result. Example:
{"file_name": "A001_C003.mov", "size": 35181362} - JSON (JavaScript Object Notation)
- A text format for data: objects in curly brackets with
"name": valuepairs, lists in square brackets, text in double quotes, numbers,true,falseandnull(no value). Example:{"status": "ready", "warnings": []} - API key and API secret
- Your program's user name (the key, 16 characters) and password (the secret, 32 characters) for this API. You send both with every request. Keep the secret secret, like a password. Example:
curl -u "YOUR_API_KEY:YOUR_API_SECRET" ... - Access token
- A temporary password (it starts with
rma_) that works for 1 hour. Apps get one when a person signs in; partners can swap their key and secret for one. Example:Authorization: Bearer rma_4QyH0m1Zr8... - Refresh token
- A longer-lived token of an app (it starts with
rmr_, works 90 days) used only to get new access tokens. Example:POST /auth/tokenwithgrant_typerefresh_token - Scope
- A permission of a key or token: which endpoints it is allowed to use. Each endpoint names its scope in the reference. Example:
jobs:writeallows starting and deleting jobs. - Credential
- Whatever proves who you are in a request: your API key and secret, or an access token. Example: Limits are counted per credential.
- Upload
- The transfer of one file from your computer to us. You open it, send the file in chunks and complete it; then the file is a media. Example:
upl_5f0c2a9e41b7d3c8e6a1f094 - Chunk
- One piece of the file in an upload, 8 MiB unless you choose another size. Chunks are numbered from 0. Example: A 35 MB file is sent as 5 chunks: 0 to 4.
- Media
- A file we have received (by upload or import) and analysed. Jobs and previews are always made from a media. One media, many media. Example:
med_4821 - Job
- One processing run of a media with your settings (for example restoration or colorization). It costs money and ends with a result. Example:
job_3150 - Result
- The finished file a completed job delivers, which you download. Example:
A001_C003 - Custom - job_3150.mov - Preview
- A free before/after image of one frame with the settings you consider. Example:
prv_3171 - Keyframe
- In a colorization job: a frame of a scene that is colorized first. After your approval its colours are carried to the other frames of the scene. Example: Frame 12 of scene 0.
- Preset
- A saved set of filters with an output format and size, by us or by you in the workspace. Example:
pre_90"Restore without Grain" - Filter
- One processing step you can choose, for example noise removal or colorization. Example:
medium_dust_and_scratches - Polling
- Asking again and again, a few seconds apart, whether something has finished. Never faster than once a second; the
Retry-Afterheader tells you when to ask next. Example: AskGET /jobs/job_3150every second untilstatusiscompleted. - ETag
- A short fingerprint of a response, sent in the
ETagheader. Send it back inIf-None-Match: if nothing has changed you get a short304instead of the whole answer, and a 304 never counts against your limits. Example:ETag: W/"4fba7bfc885cb47a48c0a537fd8ba09e" - Idempotency key
- A random value (a UUID) you send with a request that creates something. If the response gets lost and you send the same request with the same key again, you get the first response again instead of a second job. Example:
Idempotency-Key: 9b2f0c7e-3d4a-4f61-8a5e-2c1b7d9e0f43 - Rate limit
- The most requests you can send in a time, for example 120 a minute. Above it you get
429 Too Many Requestsand waitRetry-Afterseconds. Example:RateLimit-Remaining: 118 - Retry-After
- A response header with a number of seconds: how long to wait before you ask again. Example:
Retry-After: 1 - Webhook
- Instead of you polling us, our server sends a request to an address of yours when something happens (a job has completed). Example: A POST to
https://your-server.example.com/recuro-webhook - Page and cursor
- Long lists come in pages. Each page ends with
next_cursor; send it ascursorto get the next page, until it isnull. Example:GET /jobs?cursor=eyJiZWZvcmUiOjM1ODF9 - UUID (universally unique identifier)
- A random 36-character value that is practically never the same twice. Python:
uuid.uuid4(); PowerShell:[guid]::NewGuid(); shell:openssl rand -hex 16(32 characters, as good). Example:9b2f0c7e-3d4a-4f61-8a5e-2c1b7d9e0f43 - SHA-256
- A 64-character fingerprint of a file's content. If one byte changes, the fingerprint changes. Used to check that a file arrived whole. Example:
sha256sum file.mov(Linux),shasum -a 256 file.mov(macOS),(Get-FileHash file.mov).Hash.ToLower()(PowerShell:Get-FileHashalone prints upper case - the case does not matter) - curl
- A command-line program that sends HTTP requests. It comes with macOS, Linux and Windows 10/11 (there it is
curl.exe). The-uoption sends a key and secret,-Ha header,-da body,-osaves the answer as a file;-sShides the progress meter but still shows curl's own error messages;--failsaves no error answer as a file (curl ends with exit code 22). Example:curl -sS https://www.recuromedia.com/api/1.0/health
Abbreviations
| Short | Meaning |
|---|---|
| AI | artificial intelligence |
| ASCII | the basic set of 95 printable characters: English letters, digits, space and punctuation (no accented letters) |
| JPEG, PNG | image file formats: JPEG is smaller, PNG keeps every detail |
| NTSC | the American television standard of 29.97 frames per second |
| URL | uniform resource locator: a web address such as https://www.recuromedia.com/ |
| UTF-8 | the standard way to store text in any language |
| YAML | a text format for structured data, easier to read than JSON (used by openapi.yaml) |
| 2K | here: a picture that is not HD and whose long side is at most 2048 and short side at most 1556 pixels (DCI 2K 2048 × 1080, 2K scope 2048 × 858, full-aperture film scans 2048 × 1556): our larger price tier and the largest picture we take |
| 4K | a picture 2160 pixels high (3840 × 2160): we make it only by upscaling (output scaling 2160); 4K files cannot be uploaded |
| HD | high definition - here: a picture whose long side (the larger of width and height) is at most 1920 and short side at most 1080 pixels, and that is not SD |
| SD | standard definition - here: a picture whose long side is at most 1280 and short side at most 720 pixels; priced as HD |
| CORS | cross-origin resource sharing: rules that let a program in a web view call another address |
| EUR | euro |
| ETA | estimated time of arrival: here, the estimated seconds until a job has finished |
| fps | frames per second |
| GiB, MiB | binary sizes: 1 MiB = 1,048,576 bytes, 1 GiB = 1,073,741,824 bytes. 1 KB here means 1,024 bytes; 1 MB (only in rounded sizes such as "a 35 MB file") 1,000,000 bytes |
| HMAC | hash-based message authentication code: a signature made with a secret key (used for webhooks) |
| HTTP, HTTPS | the protocol of the web; HTTPS is HTTP encrypted. This API takes HTTPS only |
| ISO 8601, ISO 3166 | standards of the International Organization for Standardization (ISO): 8601 for a date and time, here in UTC (2026-10-06T09:04:18Z); 3166 for two-letter country codes (SE) |
| MAM | media asset manager: a system that stores and organises video files |
| MXF, MOV, MP4 | video file formats; ProRes, DNxHR, H.264 and HEVC are ways the picture is stored in them |
| NLE | non-linear editor: an editing application such as Adobe Premiere Pro, DaVinci Resolve or Avid Media Composer |
| PKCE | proof key for code exchange: a one-time secret pair that proves the app that started a browser sign-in is the one that finishes it; S256 means the challenge is the SHA-256 of the verifier |
| RFC | request for comments: the published standards of the internet, for example RFC 9457 for error responses |
| UTC | coordinated universal time: the time zone of every time in this API (London winter time) |
How to read this page
- One word per thing: a file is on your computer; after the upload it is a media on ours; a job processes a media; its finished file is the result. A request gets a response.
- "Must" means the API refuses the request otherwise. "Can" means you are allowed to, but do not have to. "We recommend" means the API works without it, but your program is safer with it.
- Placeholders are in capitals: replace
YOUR_API_KEY,YOUR_API_SECRETandYOUR_FILE_SHA256with your own. Every other id, token, code, hash, file name and size in an example is an example value too: use the ids (med_4821,job_3150,upl_...) and tokens (rma_...,rmr_...) you get back, the 6-digit codes of your e-mails, and your file's name, size and SHA-256. - Shell examples work as they are in bash (Linux, Git Bash on Windows) and in zsh (Terminal on macOS). They
carry no
#comments: zsh does not take comments in pasted lines. (Pasting your own comments into zsh? Runsetopt interactivecommentsfirst.) - Units: times in seconds, sizes in bytes, frames counted from 0, money in the currency it names (euros:
EUR), dates and times in UTC. - In the reference,
{job_id}in a path is a path parameter: write the id there without the curly brackets.
Your first call in 5 minutes
Three requests: one that needs no key (is the service there?), one with your key (who am I?), and one with a JSON body (what would a job cost?). None of them costs anything. The 5 minutes start once you have your API key and secret: we switch API access on first (What you need, steps 2 and 3).
On Windows (PowerShell)
Open PowerShell (press the Windows key, type powershell, press Enter). Type
curl.exe, not curl: in Windows PowerShell 5.1, curl is another
command (Invoke-WebRequest) that does not understand -u. curl.exe is part of Windows 10 (version
1803 and later) and Windows 11. Paste these lines one block at a time and press Enter:
# 1. Is the service there? (no key needed)
curl.exe -sS https://www.recuromedia.com/api/1.0/health
# 2. Your key and secret (replace both placeholders, keep the quotes)
$Key = "YOUR_API_KEY"
$Secret = "YOUR_API_SECRET"
# 3. Who am I? -u sends the key and secret (HTTP Basic). ${Key} needs its curly brackets
# in front of the colon - "$Key:$Secret" would not work in PowerShell.
curl.exe -sS -u "${Key}:${Secret}" https://www.recuromedia.com/api/1.0/meA JSON body in PowerShell: write it into a file and let curl send the file. Typing the JSON on the command line does not
work in Windows PowerShell 5.1 - it removes the double quotes inside it, and the API answers
InvalidJson. Write the file with Set-Content -Encoding ascii, as below. Do
not write it with >, Out-File or -Encoding utf8: they put invisible bytes before the text
(UTF-16, or a byte order mark), which the API also refuses as InvalidJson.
# 4. What would a 60-second HD restoration cost? (a quote: free, nothing is started)
Set-Content -Path quote.json -Encoding ascii -Value '{"planned": {"duration_seconds": 60, "width": 1920, "height": 1080}, "settings": {"filters": ["noise", "medium_dust_and_scratches"]}}'
curl.exe -sS -u "${Key}:${Secret}" -H "Content-Type: application/json" --data "@quote.json" https://www.recuromedia.com/api/1.0/quotesPrefer PowerShell's own commands? Invoke-RestMethod turns the JSON response into an object you can read field by
field. On a 4xx or 5xx response it stops with only "The remote server returned an error"; our code and
detail are in $_.ErrorDetails.Message, which the catch below prints:
$Basic = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${Key}:${Secret}"))
try {
$Me = Invoke-RestMethod -Uri https://www.recuromedia.com/api/1.0/me -Headers @{ Authorization = "Basic $Basic" }
$Me.plan.name # Prepaid
$Me.balance.amount # 412.50
} catch {
$_.ErrorDetails.Message
}In the old Command Prompt (cmd.exe) write curl (it is curl.exe there), use the key and secret
directly (-u "KEY:SECRET") and write every double quote inside a JSON body as \".
On macOS and Linux
Open Terminal (macOS: Applications > Utilities > Terminal). curl is already installed. Paste one block at a time and press Enter. First your settings for this terminal window - replace both placeholders and keep the quotes:
API=https://www.recuromedia.com/api/1.0
AUTH="YOUR_API_KEY:YOUR_API_SECRET"1. Is the service there? No key is needed:
curl -sS "$API/health"; echo2. Who am I? -u sends the key and secret (HTTP Basic):
curl -sS -u "$AUTH" "$API/me"; echo3. What would a 60-second HD restoration cost? A quote: free, nothing is started:
curl -sS -u "$AUTH" "$API/quotes" -H "Content-Type: application/json" \
-d '{"planned": {"duration_seconds": 60, "width": 1920, "height": 1080}, "settings": {"filters": ["noise", "medium_dust_and_scratches"]}}'; echoThe single quotes around the JSON keep its double quotes intact. ; echo only adds a line break after the
response. -sS hides curl's progress meter but still shows curl's own error messages (for example a mistyped
address). To read a long response more easily, add | python3 -m json.tool before ; echo (Python 3 must be
installed).
What you should see
Request 1 answers {"status":"ok","api_version":"1.0", ...}. Request 2 answers your
account as one long line of JSON - shortened and spread out here:
{
"user": { "id": "usr_1042", "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com", "...": "..." },
"company": { "id": "cmp_311", "name": "Example Films Ltd", "account_type": "client" },
"plan": { "code": "prepaid", "name": "Prepaid", "watermark": false, "billing": "balance" },
"balance": { "amount": "412.50", "currency": "EUR" },
"...": "..."
}Check: user.email is your address, plan.name your plan and balance.amount what you can
spend in euros. Every field is explained in the Me object. Request 3 answers a
quote: "price": {"amount": "25.00", "currency": "EUR"} (60 seconds at
€25 per minute) and "covers": true when your balance pays for it.
That is all it takes: you have used the API. Next, the whole workflow.
If you see an error instead
Every error of the API is JSON with a code - the word to look up in the error table - and a
sentence (detail). The ones you are most likely to meet now:
| What you see | What it means | What to do |
|---|---|---|
Parameter cannot be processed because the parameter name 'u' is ambiguous (a red PowerShell error) | You typed curl in Windows PowerShell 5.1, which runs another command (Invoke-WebRequest). | Type curl.exe. |
"code":"Unauthorized" (401) | The request had no key: -u is missing, or - in Windows PowerShell - $Key and $Secret are empty (a new window forgets them). | Set $Key and $Secret again and repeat with -u. |
curl stops and asks Enter host password for user '': | macOS and Linux: AUTH is empty - a new terminal window forgets the settings. | Press Ctrl+C, paste the settings block (API= and AUTH=) again, then the request. |
"code":"InvalidCredentials" (401) | The key or the secret is wrong - often a space or a missing character from copying. | Copy both again. Secret lost: create a new one (What you need, step 3). After 20 wrong tries in 15 minutes your address is blocked for a while: wait. |
"code":"ApiAccessDisabled" (403) | API access is not switched on for your user. | Contact us (What you need, step 2). |
"code":"InvalidJson" (400) | The body of request 3 is not valid JSON - on Windows the quotes were removed, or the file starts with a byte order mark. | Follow the Windows steps exactly: the JSON in a file, -Encoding ascii, --data "@quote.json". |
curl: (3) URL rejected: No host part in the URL | API is empty: a new terminal window forgets the settings. | Paste the settings block again, then the request. |
curl: (6) Could not resolve host or curl: (7) Failed to connect | Your computer cannot reach our server: a typing error in the address, no internet, or a company firewall or proxy. | Check the address; try it in a browser (/api/1.0/health shows the JSON); ask your IT department about a proxy (curl option -x). |
| Nothing at all is printed | An example copied with -s instead of -sS hides curl's own error messages. | Run it again with -sS (or -v, which shows every step) to see what went wrong. |
The core workflow
Every job takes the same way through the API: upload, job, download. The workflow page shows every request of it with its response, in the shell and as a complete Python program.
- Upload the file: open an upload, send the file in chunks and complete it; we analyse the media (steps 2 to 4).
- See the price, then start the job with the filters you choose (step 5).
- Follow the job until it is done (step 6) - a colorization waits for your review of its keyframes first (step 7).
- Download the result (step 8) and clean up (step 9).
Questions and answers
- Do I need to be a programmer?
- No, to try it: the first call and the workflow are commands you paste into a terminal. To connect your own systems for good you, or someone in your team, will write a small program; restore.py is a complete one to start from.
- Does trying the API cost money?
- No.
GETrequests, quotes, uploads, analyses and previews are free. OnlyPOST /jobstakes money, and it gives it back if the job fails or is cancelled. A quote shows the price first. - Is there a test system?
- No. Use short clips (a few seconds) while you build: a 2-second HD restoration costs €0.80.
- How do I know when a job is done?
- Poll
GET /jobs/{job_id}(at most once a second, asRetry-Aftersays) untilstatusiscompleted, or let us call your server (webhooks, API keys only). - My program crashed during an upload. Do I have to start again?
- No: ask
GET /uploads/{upload_id}which chunks are missing and send only those (Resuming an upload), within 7 days. - I sent POST /jobs and got no response. Did it start?
- Send the same request with the same
Idempotency-Keyagain: you get the job if it started, and it starts once if it did not. Without a key, look inGET /jobsbefore you send it again. - Which picture sizes can I upload?
- Up to 2K: 2048 × 1556 pixels, either way round
(HD, DCI 2K and full-aperture 2K scans). A 4K file is refused (
PictureTooLarge) - export it at 2K or HD first. You can still get a 4K result: output scaling2160upscales the film. Read the limit fromlimits.pictureofGET /healthrather than writing the numbers into your program. - Can I process only a part of a long film?
- Not yet: cut the part you want (with a second before and after) and upload that part.
- Can I run the same media with other settings?
- Yes, one job at a time: download the first result, delete that job (
DELETE /jobs/{job_id}), then start the new one. - Why is my key refused right after I created it?
- Check that you copied the secret completely (32 characters) and that you send
key:secretwith a colon between them. A secret is shown once; if you are not sure, delete it and create a new one. - Which programming languages can I use?
- Any that can send HTTPS requests: Python, JavaScript (Node.js), PHP, C#, Java, Go, and others. openapi.yaml can generate a client for many languages (for example with OpenAPI Generator).
- Whom do I ask?
- Contact us, with the
request_idof the request in question.
Where to go next
- Getting Access
- API keys for your own program, signing in inside an app or in the browser, tokens and scopes.
- The Workflow
- Every request from the upload to the download, step by step, in the shell and in Python.
- Concepts and Conventions
- Uploads, filters, previews, jobs, keyframes and billing; headers, formats, polling, idempotency and the limits.
- Reference
- Every endpoint with its parameters, its response, an example and the error codes it can answer.
- Objects
- Every object of the responses, field by field.
- Errors
- The HTTP statuses and every error code, with what your program should do.
- Webhooks
- Let us call your server when a media is ready or a job is done, and check the signature.
- openapi.yaml
- The whole API in machine-readable form (OpenAPI 3.1).
