How to Make a UGC Product Video with the Google Flow API
8 min read • September 4, 2026
Table of contents
- Introduction
- Pricing
- About the ids in the requests
- Step 1: a sheet for each product
- Step 2: the presenter
- Step 3: the still, the whole scene in one frame
- Step 4: one clip per product, all from the still
- Step 5: upscale to 1080p
- Step 6: join them
- What to expect
- What it cost
- Run it yourself
- Frequently asked questions
- Conclusion
Introduction
A UGC product video can be built end to end through the useapi.net Google Flow API for 45 Flow credits, with nothing processed locally. One invented presenter shows three invented products to the camera.
UGC is the user-generated-content style that fills social feeds and ad libraries: one person talking to a phone camera, to sell a product, to entertain, or just for fun.
This is the full A-to-Z guide to producing that kind of video at a professional level: the products, the presenter, her lines and the final cut all under your control, in six steps of API calls you can copy as they are.
Here is the result, three 10-second Omni 1.1 Flash clips upscaled to 1080p, every frame and every sound produced through the Google Flow API. The same upscale call goes to 4K when you need professional quality, see Step 5:
45 credits in total
If you would rather watch than read, here is the whole guide in 75 seconds:
watch on YouTube · narration and music from the MiniMax API
Pricing
Omni 1.1 Flash video needs a paid Google AI plan plus a flat $15/month to useapi.net for API access, with no per-call surcharge. Every image, portrait, character and the concatenate below cost nothing. The three 10-second clips cost 15 Flow credits each, 45 in total, which is 45 cents on the Google AI Ultra $99 plan. Full per-tier credit costs are on the Google Flow overview.
About the ids in the requests
Every request below refers to earlier results by their mediaGenerationId. The ids are long, so they are shortened here to user:1234-email:…-image:b0bdf3e8-…, and a line under each request says which earlier result each one is. An image id comes back from POST /images under media[0].image.generatedImage.mediaGenerationId, a character id in the character field of POST /characters, a video id under media[0].mediaGenerationId of the finished job, and an upscaled clip’s id is its source’s id with _upsampled on the end.
Step 1: a sheet for each product
A product sheet is one image that shows the item from four sides, so the model has the whole object and not one lucky angle. POST /images, square, one request per product. The prompt spells out the camera for every panel, because “front, side, back” on its own gave two identical panels for the mug and no true side for the keyboard. A flat object like the keyboard needs a top-down panel, a cube-shaped one does not. No hands, no captions, no logos, so nothing but the product can leak into the clips.
The same works for a real product. Upload photos of it with POST /assets and pass their ids as reference_1 to reference_4 on this request, and the model turns them into a clean four-panel sheet. The same trick makes a sheet for a package, a logo or a set.
curl — POST /images (the mug)
curl --location 'https://api.useapi.net/v1/google-flow/images' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'aspectRatio="1:1"' \
--form 'count="2"' \
--form 'prompt="Orthographic product-catalog sheet on a plain white background: a matte white ceramic mug with a straight cylindrical body and a clearly visible glowing amber light band around its base, about a finger wide, like a smart heated mug. The sheet is divided into four equal panels by thin grey lines in a 2 by 2 grid. Every panel shows the same single item at exactly the same size, position and lighting, camera at the item'\''s eye level unless stated: top-left: side profile, the handle pointing left and seen edge-on; top-right: view from the handle side, the handle pointing straight at the camera; bottom-left: view from the opposite side, the handle hidden behind the body; bottom-right: three-quarter view from slightly above, the handle to the right. Soft even studio light, photoreal. Object only: no hands, no people, no props, no text anywhere, no captions, no labels, no logo, no packaging."'
curl — POST /images (the desk robot)
curl --location 'https://api.useapi.net/v1/google-flow/images' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'aspectRatio="1:1"' \
--form 'count="2"' \
--form 'prompt="Orthographic product-catalog sheet on a plain white background: a small rounded pastel mint desk robot, a palm-sized cube with a glossy black screen face showing a happy smiling expression, two round white eyes and a curved white smile, a little rounded antenna nub on top, a small round white dial on its right side, and a speaker grille on its back. The sheet is divided into four equal panels by thin grey lines in a 2 by 2 grid. Every panel shows the same single item at exactly the same size, position and lighting, camera at the item'\''s eye level unless stated: top-left: front view showing the smiling face; top-right: right side view showing the round dial and the antenna nub; bottom-left: back view showing the speaker grille; bottom-right: three-quarter view showing the smiling face and the dial. Soft even studio light, photoreal. Object only: no hands, no people, no props, no text anywhere, no captions, no labels, no logo, no packaging."'
curl — POST /images (the keyboard)
curl --location 'https://api.useapi.net/v1/google-flow/images' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'aspectRatio="1:1"' \
--form 'count="4"' \
--form 'prompt="Orthographic product-catalog sheet on a plain white background: a real mechanical three-key macro pad, the kind sold for shortcuts: a slim, low-profile white aluminum case, three mechanical key switches in one row with sculpted dished keycaps and a small gap between them, coral on the left, lemon yellow in the middle, sky blue on the right, a USB-C port on the back edge. Exactly three keys in one row, never more. The sheet is divided into four equal panels by thin grey lines in a 2 by 2 grid. Every panel shows the same single item at exactly the same size, position and lighting, camera at the item'\''s eye level unless stated: top-left: top-down view straight from above, the three keys in a row left to right; top-right: front view at eye level; bottom-left: left side view at eye level, the slim case and the keycap profile seen edge-on; bottom-right: three-quarter view from above. Soft even studio light, photoreal. Object only: no hands, no people, no props, no text anywhere, no captions, no labels, no logo, no packaging."'
Images cost nothing, so ask for count of 2 to 4 and keep the best sheet. The keyboard took a few rounds before its prompt described a real macro pad with a top-down panel, the cube worked first time.
Step 2: the presenter
Three calls. A front portrait from a description. A three-quarter portrait generated from the first one with reference_1, so the two agree on the face. Then POST /characters with both portraits, which returns a character reference. From then on she is @character_1 in any prompt, and Google pins her through its own entity system instead of through a description.
curl — POST /images (front portrait)
curl --location 'https://api.useapi.net/v1/google-flow/images' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'aspectRatio="3:4"' \
--form 'count="2"' \
--form 'prompt="Character reference portrait, photoreal, natural skin, no heavy retouching: a strikingly attractive young woman in her early twenties with a sleek platinum-blonde blunt bob and straight bangs, dark defined eyebrows, icy grey eyes, a tiny silver nose stud, a playful smirk with a hint of teeth, wearing a fitted black turtleneck and a thin gold chain necklace. Head and shoulders, facing the camera straight on, plain light-grey studio background, soft even light. No text, no logo, no captions."'
Rendered a few looks, picked this one. If a detail needs changing afterwards, the chain say, re-render her with her own portrait as reference_1 and a prompt that names only the change, and the face stays put.
curl — POST /images (three-quarter portrait)
curl --location 'https://api.useapi.net/v1/google-flow/images' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'aspectRatio="3:4"' \
--form 'count="1"' \
--form 'reference_1="user:1234-email:…-image:a236ef66-…"' \
--form 'prompt="@reference_1 is the same woman: identical face, hair, freckles, sweater and earrings. Three-quarter view from the waist up, relaxed natural smile, plain light-grey studio background, soft even light. Photoreal, no text."'
reference_1 is the front portrait, a236ef66. This prompt still mentions freckles, a sweater and earrings left over from an earlier presenter, and it did no harm: with a reference image in the request, the reference wins over the words.
curl — POST /characters
curl --location 'https://api.useapi.net/v1/google-flow/characters' \
--header 'Authorization: Bearer user:1234-…' \
--form 'displayName="Mia"' \
--form 'personalityNotes="Quick, bright, deadpan delivery with a smile in her voice. Talks to the camera like a friend showing off things she bought at 2am."' \
--form 'imageReference_1="user:1234-email:…-image:a236ef66-…"' \
--form 'imageReference_2="user:1234-email:…-image:d891301c-…"' \
--form 'voice="Leda"'
imageReference_1 is the front portrait a236ef66, imageReference_2 the three-quarter d891301c. The response’s character field is her id, 53ca1036 below. The voice is one of Google’s system presets and rides along with the character, but it cannot reach the clip mode used in Step 4, see What to expect.
Step 3: the still, the whole scene in one frame
One request puts everything together. The character goes in as character_1, the three sheets as reference_1 to reference_3, and the prompt places them by tag, left to right on the table in front of her. This frame becomes both ends of every clip, so it is the one place where the tags do their work.
curl — POST /images
curl --location 'https://api.useapi.net/v1/google-flow/images' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'aspectRatio="9:16"' \
--form 'count="2"' \
--form 'character_1="user:1234-email:…-character:53ca1036-…"' \
--form 'reference_1="user:1234-email:…-image:b0bdf3e8-…"' \
--form 'reference_2="user:1234-email:…-image:7aaed056-…"' \
--form 'reference_3="user:1234-email:…-image:4f861c23-…"' \
--form 'prompt="Full-frame vertical phone video look, no phone, no bezel. @character_1 sits at a light wooden table in a bright minimal creator studio, facing the camera, waist-up and centered, a plain warm-grey backdrop behind her, soft key light from the left with a gentle catchlight in her eyes. Laid out on the table in front of her, left to right, each fully visible and resting flat on the table: the mug from @reference_1, the desk robot from @reference_2, the keyboard from @reference_3. Her hands rest on the table, relaxed closed-mouth smile, eyes on the lens. Photoreal, no text, no captions."'
character_1 is the character from Step 2, 53ca1036. reference_1 to reference_3 are the three sheets from Step 1: the mug b0bdf3e8, the desk robot 7aaed056, the keyboard 4f861c23.
The mug has its glow, the robot its face and antenna, the keyboard its three colours and its port, and she is the woman from the portraits.
Step 4: one clip per product, all from the still
Omni’s first-plus-last-frame mode with the still in both slots, one request per product, the same POST /videos each time. This mode takes nothing but the two images, no sheets, no character, no voice reference. That is fine, because the still already holds all of it. Every item she picks up came out matching its sheet from the still alone.
The prompt does three jobs. It pins both ends to the frame, with a quiet beat on each side. It gives her the line and the voice. And it times the choreography: she starts talking as she lifts the item, the item is back on its spot by the eight-second mark, and the last two seconds are a still, silent hold. Without that last part she ran late and her arm snapped into the end frame.
curl — POST /videos (the mug)
curl --location 'https://api.useapi.net/v1/google-flow/videos' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'model="omni-flash"' \
--form 'aspectRatio="portrait"' \
--form 'duration="10"' \
--form 'resolution="720p"' \
--form 'startImage="user:1234-email:…-image:034cddc8-…"' \
--form 'endImage="user:1234-email:…-image:034cddc8-…"' \
--form 'prompt="She begins and ends exactly on this frame: hands resting on the table, the three items laid out in front of her, a small closed-mouth smile, looking into the lens, with a short quiet beat before she moves and another after she settles back. Timing matters: after a short quiet beat she picks up the mug on the left with both hands and starts talking as she lifts it, holding it up to the camera and talking straight to the lens, quick and bright with a deadpan edge and a smile in her voice, keeping both hands on the mug while she speaks. She says: \"Three gadgets smarter than me. Low bar. One: this mug texts me when my coffee'\''s cold. Better follow-up than my ex.\" Right after the last word she gives one short laugh to herself, still holding the mug. By the eight-second mark the mug is back down gently in exactly the same spot and both hands are resting on the table again, brought back in one calm unhurried movement. For the final two seconds she holds completely still, hands resting on the table, looking into the lens with a small closed-mouth smile. Natural room tone, no music, no captions, no text on screen."'
startImage and endImage are both the still from Step 3, 034cddc8. The same two ids go into all three clips.
55808825, shown after the 1080p upscale of Step 515 credits
curl — POST /videos (the desk robot)
curl --location 'https://api.useapi.net/v1/google-flow/videos' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'model="omni-flash"' \
--form 'aspectRatio="portrait"' \
--form 'duration="10"' \
--form 'resolution="720p"' \
--form 'startImage="user:1234-email:…-image:034cddc8-…"' \
--form 'endImage="user:1234-email:…-image:034cddc8-…"' \
--form 'prompt="She begins and ends exactly on this frame: hands resting on the table, the three items laid out in front of her, a small closed-mouth smile, looking into the lens, with a short quiet beat before she moves and another after she settles back. Timing matters: after a short quiet beat she picks up the desk robot in the middle with both hands and starts talking as she lifts it, holding it up to the camera with its smiling face toward the lens and turning it once and talking straight to the lens, quick and bright with a deadpan edge and a smile in her voice, keeping both hands on it while she speaks. The other two items stay on the table exactly where they are. She says: \"Two: a desk robot that reacts to my day. It has a face. It has never once looked impressed.\" Right after the last word she raises one eyebrow at the camera, a quick expressive beat, still holding the desk robot. By the eight-second mark the desk robot is back down gently in exactly the same spot and both hands are resting on the table again, brought back in one calm unhurried movement. For the final two seconds she is silent and holds completely still, hands resting on the table, looking into the lens with a small closed-mouth smile. Natural room tone, no music, no captions, no text on screen."'
c4d0e6b1, shown after the 1080p upscale of Step 515 credits
curl — POST /videos (the keyboard)
curl --location 'https://api.useapi.net/v1/google-flow/videos' \
--header 'Authorization: Bearer user:1234-…' \
--form 'email="[email protected]"' \
--form 'model="omni-flash"' \
--form 'aspectRatio="portrait"' \
--form 'duration="10"' \
--form 'resolution="720p"' \
--form 'startImage="user:1234-email:…-image:034cddc8-…"' \
--form 'endImage="user:1234-email:…-image:034cddc8-…"' \
--form 'prompt="She begins and ends exactly on this frame: hands resting on the table, the three items laid out in front of her, a small closed-mouth smile, looking into the lens, with a short quiet beat before she moves and another after she settles back. Timing matters: after a short quiet beat she picks up the keyboard on the right with both hands and starts talking as she lifts it, holding it up to the camera with the three keys facing the lens and talking straight to the lens, quick and bright with a deadpan edge and a smile in her voice, keeping both hands on it while she speaks. The other two items stay on the table exactly where they are. She says: \"Three: a keyboard with three keys. Copy, paste, undo. That'\''s my whole career. Oh, the mug'\''s texting. Bye!\" Right after the last word she raises one eyebrow at the camera, a quick expressive beat, still holding the keyboard. By the eight-second mark the keyboard is back down gently in exactly the same spot and both hands are resting on the table again, brought back in one calm unhurried movement. For the final two seconds she is silent and holds completely still, hands resting on the table, looking into the lens with a small closed-mouth smile. Natural room tone, no music, no captions, no text on screen."'
3cc8ea2f, shown after the 1080p upscale of Step 515 credits
Same woman, same table, same light, and each clip opens and closes on the still, so any of them can follow any other. The lines are around 20 words, which is what 10 seconds holds at this pace with room for the beat at the end.
Step 5: upscale to 1080p
Omni 1.1 Flash renders at 720p. POST /videos/upscale takes a clip to 1080p for free on any paid plan, in about 40 seconds, and answers in the same call with the upscaled clip’s id and URL. One request per clip, no email, the account comes from the id.
curl — POST /videos/upscale (the mug, then the same for the other two)
curl --location 'https://api.useapi.net/v1/google-flow/videos/upscale' \
--header 'Authorization: Bearer user:1234-…' \
--form 'mediaGenerationId="user:1234-email:…-video:55808825-…"' \
--form 'resolution="1080p"'
mediaGenerationId is the mug clip from Step 4, 55808825. The same call with c4d0e6b1 and 3cc8ea2f upscales the robot and the keyboard. Each response carries the new clip under media[0].mediaGenerationId, which is the source id with _upsampled on the end, so the three upscaled ids are 55808825-…_upsampled, c4d0e6b1-…_upsampled and 3cc8ea2f-…_upsampled. The clips shown in Step 4 are these upscaled versions. 4K is also available, for 50 credits and only on a Google AI Ultra plan.
Step 6: join them
POST /videos/concatenate takes the three upscaled ids in order and returns the joined file as base64, at the clips’ resolution. The trims decide whether the joins feel like one take. Each clip opens with a short hold on the still and closes with a settle back onto it, and untrimmed those stack into a freeze at every cut. But she finishes each line with her hands already resting, so a trim measured from the picture alone cuts into the last words. Cut after the last sound plus a beat, never earlier. On these clips that meant leaving clip 1 whole, since its laugh runs to the last frame, taking just over half a second off the end of clip 2, and a few frames off the start of clips 2 and 3.
curl — POST /videos/concatenate
curl --location 'https://api.useapi.net/v1/google-flow/videos/concatenate' \
--header 'Authorization: Bearer user:1234-…' \
--header 'Content-Type: application/json' \
--data '{
"media": [
{ "mediaGenerationId": "user:1234-email:…-video:55808825-…_upsampled" },
{ "mediaGenerationId": "user:1234-email:…-video:c4d0e6b1-…_upsampled", "trimStart": 0.458, "trimEnd": 0.6 },
{ "mediaGenerationId": "user:1234-email:…-video:3cc8ea2f-…_upsampled", "trimStart": 0.125 }
]
}'
The three ids are the upscaled clips from Step 5 in order: the mug, the desk robot, the keyboard.
0 credits
She finishes a line with her hands on the table, the cut lands, and she reaches for the next item. The joined file was re-encoded to a smaller size for hosting, the three clips are as the API returned them.
What to expect
- Generate, do not edit. The UGC talking head post extended a clip with video-to-video edits, and that still works when the lines are short. Here it did not. An edit keeps its source’s speech on the source’s own timeline, so with a 10-second line filling the seed, a new line got braided into the old one instead of replacing it, and the products left on the table drifted between takes. Generating each clip from the still gave complete lines, intact products and cleaner joins, for fewer credits.
- The still carries the tags. The first-plus-last-frame mode accepts only the two images. Do the tagging in the still, with the character and the sheets, and the clips inherit it.
- Time the choreography. A 10-second clip with a full line needs the put-down called out by the clock, “by the eight-second mark”, and a still, silent hold at the end. Left to itself the model ran the line long and jumped into the end frame.
- Describe the voice the same way in every prompt. Nothing carries a voice between separate generations, and a character can hold a voice preset but cannot reach this mode. With one identical description the three clips came back close enough to pass as one take.
- Sheets need per-panel cameras. Name what each of the four panels shows. Give flat objects a top-down panel. Keep hands, captions and logos out, because whatever is on the sheet can end up in the clip.
- Trim to the sound, not the picture. She goes still before she stops talking. A cut placed at the first still frame took the end of a line with it.
- The presenter is invented. Google’s moderation is stricter with real, identifiable people. Start from a generated character.
What it cost
| Step | Mode | Credits |
|---|---|---|
| Three product sheets, 1:1 | Nano Banana 2 Lite | 0 |
| Two presenter portraits, 3:4 | Nano Banana 2 Lite | 0 |
| The character | — | 0 |
| The still, 9:16 | Nano Banana 2 Lite, character + 3 references | 0 |
| Clip 1, the mug, 10s | I2V, first + last frame | 15 |
| Clip 2, the desk robot, 10s | I2V, first + last frame | 15 |
| Clip 3, the keyboard, 10s | I2V, first + last frame | 15 |
| Upscale, three clips to 1080p | — | 0 |
| Concatenate | — | 0 |
| Total | 45 |
A 10-second Omni clip costs 15 credits at 720p, so the whole video is 45 cents on the Google AI Ultra $99 plan. Images, characters, the 1080p upscale and the concatenate cost nothing, so iterate freely on the sheets, the presenter and the still before spending a credit on video. 4K is the one upgrade that costs, 50 credits a clip on Ultra.
Run it yourself
Every step above is one API call, and the six of them chain into a script. The complete Node.js pipeline, a Python port, and the prompts.json holding every prompt on this page live in useapi/google-flow-api/ugc-product-video. Clone it, put your own products and lines in prompts.json, and one command builds the whole video.
It checkpoints after every step, so an interrupted run resumes instead of paying for the clips again, and you can redo a single step — a better still, a different presenter — without regenerating what came before it.
Frequently asked questions
- Can I use my own product photos instead of generated sheets? Yes. Upload them with POST /assets and pass the returned ids as
reference_1toreference_3on the still, exactly as the generated sheets are passed here. The four-panel sheet is a way to give the model every side of an object, and a real product benefits from the same treatment. - Why not edit one clip into the next, like the talking-head post? Because a video-to-video edit keeps its source’s speech on the source’s timeline. With short lines that replacement works. With a 10-second line filling the clip, the new line got braided into the old one and the products on the table drifted. Generating every clip from the same still avoids both, and costs 15 credits instead of 20. See What to expect.
- Why do all three clips start and end on the same frame? So they can be joined in any order with no visible cut. The first-plus-last-frame mode pins both ends of each clip to the still, and the concatenate trims the short holds around each join. The mechanism is explained in the UGC talking head post.
- Does the voice stay the same across the clips? Nothing carries a voice between separate first-plus-last generations, since that mode takes no audio reference, and a character’s voice preset cannot reach it either. Describing the voice identically in every prompt kept these three close enough to pass as one take. If you need a guaranteed voice, the reference-to-video mode accepts
referenceAudio_1, at the cost of the pinned frames. - How much does it cost? You keep your paid Google AI plan and add the flat useapi.net subscription. The whole video is 45 Flow credits, 45 cents on the Ultra $99 plan, and every image, portrait, character and the concatenate are free. See Pricing.
Conclusion
Visit our Discord Server or
Telegram Channel for any support questions and concerns.
Check our GitHub repo with code examples.
Cross posted
Also published on dev.to.





