GuidesScore a video
Score a video
Send a video link and get an MP4 back, with AINSOF music placed on the real cuts, silences where you ask, a change of track between sections, and the mix kept under dialogue. Leave out the brief and AINSOF reads the film first and chooses. Watching is free; downloading the file asks for a quick sign-in on ainsof.io.
MCP toolscore_my_videoRESTaction: "score_video"
Try it
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AINSOF_API_KEY" \
-d '{"action": "score_video", "video_url": "https://example.com/my-video.mp4", "brief": "warm, hopeful acoustic"}'The whole flow in one script
Upload a file, score it, then collect the files, repeating each request while it is still running.
import os, time, requests
API = "https://mcp.ainsof.io/"
H = {"Authorization": f"Bearer {os.environ['AINSOF_API_KEY']}"}
def call(body, tries=30):
# repeat the identical request while the job is still running
for _ in range(tries):
r = requests.post(API, headers=H, json=body, timeout=60)
data = r.json()
if data.get("error") != "still_running":
if not data.get("ok"):
raise RuntimeError(data)
return data
time.sleep(5)
raise TimeoutError("still running")
# 1. a video on this computer: get an upload slot and send the file
slot = call({"action": "get_upload_link", "filename": "cut.mp4"})
with open("cut.mp4", "rb") as f:
# use the file's own type: video/mp4, video/quicktime (.mov), video/x-m4v or video/webm
requests.put(slot["upload_url"], data=f, headers={"Content-Type": "video/mp4"}, timeout=600).raise_for_status()
# 2. score it, then 3. collect the files
job = {"action": "score_video", "video_url": slot["video_url"], "brief": "warm, hopeful acoustic"}
scored = call(job)
print(scored["download_url"])
files = call({**job, "action": "deliver_score"})
print(files["download_url"])
What you send
video_urlrequiredstring
The video (see above).
sign_in_codestring
The code returned with
sign_in_required, once the person has signed in. Pass the same code to every video action; it stays valid for 30 days. Not needed with a key created on ainsof.io.briefstring
The music wanted, in English. Leave it out and AINSOF reads the film first and chooses.
track_idstring
Use this exact cue instead of choosing one.
versionstring
Force a version, e.g.
CUT_30. Upper-cased.music_offset_dbnumber
Music level relative to the video's own audio, in dB. Negative is quieter;
0 is level. When omitted, the renderer's default applies.silencesarray
Music-free moments: objects with
at (seconds, required) and for (duration in seconds, default 1).sectionsarray
Timed acts, each scored separately:
from and to (seconds, required), plus brief (English), track_id, version or stems (an array of stem names from that cue; the schema asks for track_id with it). Every section needs a brief, track_id or stems.user_requeststring
Optional. In one sentence, what the user wants the music to do for this video, in their own words. Kept for 30 days to review how well the music fit, then deleted.
project_typestring
Optional. What kind of project the video is. Kept as anonymous usage statistics. Other values are stored as
other.music_intentstring
Optional. The music the user wants, e.g.
tense build, minimal, no vocals. Kept as anonymous usage statistics.Good to know
- Before AINSOF works with a video, a person signs in once on ainsof.io (Google or email). With a key created on ainsof.io this has already happened. Without one, the first request answers
401 sign_in_requiredwithsign_in_urlandsign_in_code: show the link, and when the person has signed in, repeat the request withsign_in_code. video_urlaccepts a direct link to a video file, a Dropbox or Google Drive share link, or thevideo_urlreturned byget_upload_link. YouTube, Vimeo, Dailymotion and Twitch pages are not supported.brief,track_idandsectionsare all optional: leave them out and AINSOF watches the film first and chooses the music for what it shows and how it feels (returned asfilm).- Section and silence boundaries are moved onto the video's measured cuts.
- An identical request made within 15 minutes returns the same render rather than starting another. Requests made with a key are only matched to that key's renders.
- Renders usually take longer than one request waits: expect
202 still_running, and repeat the same request unchanged. That reply includesdelivery_requestwith the arguments to repeat (add yoursign_in_codeif you signed in without a key). - Watching the result is free. Downloading the file opens ainsof.io, which asks for a quick sign-in (Google or email) first.
- Videos up to 15 minutes.
Every field it returns, and its errors, in the API Reference
