Synento docs
Guides

Edited clips with JSON2Video

Cut the best moments of a Synento recording into a short vertical clip with subtitles, using JSON2Video.

View as Markdown

Every Synento session is already a recording. This guide turns that recording into a 30–60 second clip you can share: the two or three moments that matter, in vertical 9:16, with subtitles burned in. It works for interview highlights, stand-up recaps, customer quotes and support review.

The flow has three steps:

  1. Get the MP4 of the session from Synento, and put it at a URL JSON2Video can read.
  2. Pick the moments: transcribe the audio and choose start and end times, by hand or with an LLM.
  3. Render the clip with JSON2Video: one API call that cuts, crops and adds subtitles.

You need a Synento project with its secret API key (sk_live_…, from the dashboard), a JSON2Video API key, and somewhere to host a file for an hour, such as an S3 or R2 bucket. JSON2Video's free plan includes enough credits to try this guide several times; its renders carry a watermark.

This guide was written with the JSON2Video team. Here is a clip made with it from a 2-minute recording.

1. Get the MP4

Start the export

Ask for an export once the session has ended. layout=presenter fills the frame with one person's camera (focus, their user id) and shows up to four others as small thumbnails, which suits interviews and talks:

curl "https://api.synento.com/v1/sessions/{sessionId}/export?layout=presenter&orientation=vertical&focus=alice" \
  -H "Authorization: Bearer sk_live_xxxxx"

Response (202):

{ "data": { "job_id": "8d0c2f0e-…" }, "error": null }

Pick the orientation by the cameras people used. Each camera keeps its own shape in the export, so:

  • Phones (portrait cameras): use orientation=vertical, as above. The 720×1280 file is already 9:16 and the camera fills it.
  • Laptop webcams (landscape cameras): leave orientation out to get a 1280×720 file. In a vertical export a landscape camera becomes a band across the middle with black above and below. From a landscape export, JSON2Video crops the centre of the frame (step 3), where a webcam usually has the face. The thumbnails sit at the edges and are cropped away.

Avoid layout=grid for a vertical clip: side-by-side tiles end up as a thin strip, or cut in half by the crop.

Two limits to know: every participant in the session needs camera video, and screen shares are not included in the MP4. See Exporting to MP4 for the full details.

Wait for it to finish

Check the job until status is completed:

curl https://api.synento.com/v1/exports/{jobId} \
  -H "Authorization: Bearer sk_live_xxxxx"
{
  "data": {
    "job_id": "8d0c2f0e-…",
    "room_id": "9b1c4e7a2d3f4a8b9c0d1e2f3a4b5c6d",
    "status": "completed",
    "progress_pct": 100,
    "download_url": "/v1/exports/8d0c2f0e-…/download"
  },
  "error": null
}

Checking every 10 seconds or so is plenty. If you would rather be told, the export.completed webhook fires when an export finishes. Its payload names the session (session_id) but not the export and carries no link to the file. To get the job id, repeat the same export request: it returns the finished job ("reused": true) without encoding or charging again.

Make the file reachable

The download_url needs your secret API key, and JSON2Video cannot send one. Download the file yourself, then host it at a short-lived link. With S3:

curl https://api.synento.com/v1/exports/{jobId}/download \
  -H "Authorization: Bearer sk_live_xxxxx" \
  --output session.mp4

aws s3 cp session.mp4 s3://your-bucket/clips/session.mp4
aws s3 presign s3://your-bucket/clips/session.mp4 --expires-in 3600

The last command prints a signed URL. That is the SESSION_MP4_URL used below. On Cloudflare R2, add --endpoint-url https://<account-id>.r2.cloudflarestorage.com to both aws s3 commands; everything else is the same. An hour is enough, since JSON2Video only needs it while the render runs. Never put your Synento API key in a URL.

2. Pick the moments

JSON2Video cuts the video where you tell it to. It does not choose the moments for you, so this step happens before the render.

Transcribe the MP4 with timestamps. The exported MP4 mixes everyone's audio into one track. Transcribe that file rather than anything else, so the times you get are times in the file you will cut. Any speech-to-text service that returns segment or word timestamps works: OpenAI Whisper, Deepgram, AssemblyAI, ElevenLabs Speech to Text, and others.

Choose two or three segments of 8–20 seconds each. You can do it by hand, or give the transcript to an LLM:

Below is the transcript of a recorded call, with start and end times in seconds.
Pick the 3 moments that best summarise the call for someone who did not attend.
Each moment must be a complete sentence or answer, between 8 and 20 seconds long.
Return only JSON: [{"start": 12.4, "end": 25.1, "why": "..."}]

<transcript>

Move each start about 0.3 seconds earlier and each end about 0.3 seconds later, so no word is clipped: transcript timestamps often end a little before the speech does. When the next person starts talking straight away, end the cut where their first word begins instead, or the clip picks up the start of it.

3. Render the clip

Each moment becomes one scene. In each scene, seek is where the cut starts in the MP4, in seconds, and duration is how long it lasts. resize: "cover" fills the vertical frame, and position: "center-center" makes the crop take the middle of a landscape export. Leave it out and JSON2Video keeps the left edge instead, showing the thumbnails and cutting off the person in focus. The subtitles element sits at movie level: it transcribes the finished clip and burns in the captions, so you do not need to send the transcript again.

Save this as clip.json:

{
  "resolution": "instagram-story",
  "quality": "high",
  "scenes": [
    {
      "elements": [
        { "type": "video", "src": "SESSION_MP4_URL", "seek": 2.5, "duration": 10.6, "resize": "cover", "position": "center-center" }
      ]
    },
    {
      "elements": [
        { "type": "video", "src": "SESSION_MP4_URL", "seek": 59.7, "duration": 11, "resize": "cover", "position": "center-center" }
      ]
    },
    {
      "elements": [
        { "type": "video", "src": "SESSION_MP4_URL", "seek": 104.3, "duration": 9.8, "resize": "cover", "position": "center-center" }
      ]
    }
  ],
  "elements": [
    {
      "type": "subtitles",
      "settings": {
        "style": "classic-progressive",
        "position": "bottom-center",
        "max-words-per-line": 3,
        "font-size": 70
      }
    }
  ]
}

instagram-story is 1080×1920. For other shapes, use full-hd (1920×1080) for a horizontal clip, from a landscape export, or squared for 1:1.

Send it to JSON2Video:

curl -X POST "https://api.json2video.com/v2/movies" \
  -H "x-api-key: YOUR_JSON2VIDEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d @clip.json

The response contains a project id:

{ "success": true, "project": "bfLEfgAXt91xaS5U", "timestamp": "2026-10-23T11:01:24.023Z" }

Rendering runs in the background, so check every 10 seconds or so until movie.status is done (or error, with the reason in movie.message):

curl "https://api.json2video.com/v2/movies?project=PROJECT_ID" \
  -H "x-api-key: YOUR_JSON2VIDEO_API_KEY"
{
  "success": true,
  "movie": {
    "status": "done",
    "url": "https://json2video-cdn1.s3.amazonaws.com/clients/…/renders/….mp4",
    "duration": 31.8,
    "width": 1080,
    "height": 1920
  }
}

movie.url is the finished clip. A 30-second clip took about 20 seconds to render. You can then delete the copy you uploaded in step 1.

Cost

  • JSON2Video bills per second of finished video, rounded up: a 31.8-second clip uses 32 credits, however long the original session was.
  • Synento counts only the export, in exported participant-minutes: each person's time in the recording. A 2-minute call with 2 people is 4. Plans include 300 a month on Free and 3,000 on Pro, then $0.004 each on Pro. Asking for the same export again costs nothing.

Doing it with a coding agent

Both services have MCP servers, so an agent such as Claude Code or Cursor can do most of this for you. Connect both:

claude mcp add --transport http synento https://api.synento.com/mcp
npx -y @json2video/cli mcp install claude

Then run /mcp in Claude Code and choose synento to sign in. See Connect your agent for other editors.

Synento's MCP server can find the session (list_sessions) and show what was recorded (get_session_manifest), but it does not start exports. The key it creates for your app (rk_live_…) cannot export either. So the agent also needs your project's secret key: put it in an environment variable such as SYNENTO_API_KEY rather than pasting it into the chat, and tell the agent where it may upload the MP4.

Then ask, for example: "Find yesterday's interview session in Synento. Export it with the presenter layout focused on the guest, using SYNENTO_API_KEY (vertical if they were on a phone, landscape otherwise), upload the MP4 to my S3 bucket with a one-hour link, pick the three best answers from a transcript, and render a vertical highlight clip with subtitles through JSON2Video."

Variations

  • Branding: add an image element (your logo) at movie level, or a short title scene at the start with a text element.
  • Follow the speaker: for an interview, export once per person (focus=alice, then focus=bob) and cut each moment from the export of whoever is talking, so the person speaking always fills the frame. Each export counts its exported participant-minutes, so two exports cost twice as much on the Synento side.
  • One clip per moment: send one render per segment instead of three scenes in one movie, for a set of short quotes.
  • Subtitle style and language: see JSON2Video's subtitles reference for styles, colours and translation.
  • Whole session with captions: one scene with the whole MP4 ("duration": -1) and the subtitles element give a captioned copy of the call.

Reference

On this page