AI-103: Image and Video Generation and Editing in Foundry — GPT-image, FLUX and Sora 2
Image and video generation in Microsoft Foundry means calling a deployed generative model (a GPT-image series or FLUX model for images, Sora 2 for video) to create media from text prompts and reference images, and then editing that media with masks, prompts and remixes. This lesson covers the AI-103 skills at the level of the actual calls: which image model to deploy and why dall-e-3 is no longer an option, what images.generate returns, which controls change quality, speed, format and transparency, how mask-based inpainting and input fidelity work, when FLUX needs the Black Forest Labs API instead of the images API, and how Sora 2's asynchronous jobs, reference images, remixes and content restrictions behave.
On this page9 sections
- Which models generate images in Microsoft Foundry?
- How do you generate an image from a text prompt?
- Which controls shape a generated image?
- How do you edit an image with a prompt or a mask?
- When should you use FLUX models, and through which API?
- How does Sora 2 generate a video?
- Which parameters control a Sora 2 video, including reference images?
- How do you edit a generated video?
- Why do Sora 2 generation requests fail?
- Choose an image model in Foundry by availability, supported sizes and API shape, and migrate off the retired dall-e-3
- Generate images with images.generate and handle the base64 response that GPT-image models always return
- Apply generation controls (size, quality, output_format, output_compression, background, streaming partial images) to a stated requirement
- Configure image edits: prompt-driven edits, mask-based inpainting with a valid PNG mask, multi-image requests and input_fidelity
- Pick the right FLUX model and route (Image API or BFL provider API) and address it with the correct model path
- Implement Sora 2 video generation as an asynchronous job, including size, duration, reference images and storage before expiry
- Edit generated videos with remix and design prompts and references that comply with Sora 2's content restrictions
Which models generate images in Microsoft Foundry?
Microsoft Foundry generates images with two model families: the GPT-image series from Azure OpenAI and Black Forest Labs' FLUX models. You deploy one into your Foundry resource and call the deployment by name. The choice usually comes down to three things: whether the model is generally available or needs a limited-access approval, which output sizes it accepts, and which API shape your code already uses.
| Model | Availability | Sizes | Good for |
|---|---|---|---|
| GPT-image-2 | Generally available | Custom WIDTHxHEIGHT: both edges multiples of 16, long edge up to 3,840 px, aspect ratio up to 3:1, total pixels between 655,360 and 8,294,400 (size="auto" can return dimensions outside these limits) | High-resolution and 4K output through the images API |
| GPT-image-1.5, GPT-image-1, GPT-image-1-mini | Limited access (you apply and wait for approval) | Three fixed sizes: 1024x1024, 1024x1536, 1536x1024 | General generation and editing; -mini for fast, bulk or cost-sensitive work |
| FLUX models (FLUX.2-pro, FLUX.2-flex, FLUX.1-Kontext-pro, FLUX-1.1-pro) | Global standard deployment | Depends on the model (1 MP to 4 MP) | Photorealism, in-context editing, multi-reference editing (see the FLUX section) |
dall-e-3 is retired. Microsoft retired it on 4 March 2026: it can't be deployed, and existing deployments no longer work. The replacement is a GPT-image series model, which uses the same images API, so migrating means creating a new deployment and pointing the calls at it. Redeploying a different dall-e-3 version or changing its deployment type does not bring it back. The one code change to expect is in the response: GPT-image models return base64 data rather than a URL (next section).
Microsoft also lists newer GA variants (GPT-image-2.5 Sunburst and Flare) with extra quality levels. The selection logic is the same: check availability, size support and the API before you commit.
How do you generate an image from a text prompt?
You generate an image by calling images.generate on an image deployment, passing the deployment name as model and a text prompt. With the OpenAI Python client pointed at the resource's /openai/v1/ endpoint, the call is the same as on OpenAI's own API.
import base64
result = client.images.generate(
model="gpt-image-1", # your deployment name
prompt="Flat-lay photo of a leather notebook",
size="1536x1024",
quality="medium",
n=1,
)
image_bytes = base64.b64decode(result.data[0].b64_json)
with open("notebook.png", "wb") as f:
f.write(image_bytes)
Three response rules matter:
- GPT-image models always return base64. Each item in
result.datacarriesb64_json; there is no URL. Code written for a URL-returning model readsdata[0].url, getsNone, and has to decodeb64_jsonand write the bytes instead. response_formatis not supported for GPT-image models, so you can't ask for a URL.output_formatis a different setting: it picks the image encoding (PNG or JPEG), not how the image is delivered.nsets how many images one call returns: 1 to 10, default 1. It multiplies the work, so it doesn't speed anything up.
A text prompt alone can't reproduce a specific existing object, such as one particular house or product. When the output has to start from a real image, use an edit request (or a reference-image model) instead of generation.
Which controls shape a generated image?
The GPT-image models expose a small set of controls on images.generate. Each one changes a single thing, and most scenario questions come down to picking the one that changes the thing the requirement names.
| Parameter | Values | What it changes |
|---|---|---|
size | Fixed sizes for GPT-image-1 series; custom multiples of 16 for GPT-image-2 | Output dimensions |
quality | low, medium, high (default high for gpt-image-1, medium for gpt-image-1-mini) | Detail versus speed: lower quality generates faster |
output_format | png (default) or jpeg; WebP is not supported | File encoding of the returned image |
output_compression | 0 to 100 | JPEG file size only; it doesn't change generation time or detail of the composition |
background | transparent, opaque, auto | Whether the image has a background; transparent requires PNG |
stream + partial_images | stream=True, partial_images 1 to 3 | Sends in-progress previews during one request |
n | 1 to 10 | Number of final images |
Transparent backgrounds
For stickers, icons or cut-outs, set background="transparent" and output_format="png". PNG is the only supported output format with an alpha channel, so transparent plus JPEG can't work. auto leaves the decision to the model and opaque asks for a filled background. Microsoft documents transparency for gpt-image-1 and gpt-image-2; confirm support before relying on it with another model.
Faster drafts versus faster-feeling pages
Two different problems are easy to confuse. If generation itself is too slow (for example, a storyboard tool that renders dozens of rough thumbnails before anyone picks one), lower quality for the drafts and keep high for the final image; the model and size stay the same. If the wait is acceptable but users see a blank page, stream the request: with stream=True and partial_images set, the API emits image_generation.partial_image events, each with b64_json data the page can show as a rough preview that sharpens before the final image arrives. Streaming improves perceived latency but doesn't finish sooner, and compression only shrinks a JPEG file.
How do you edit an image with a prompt or a mask?
You edit an image by calling images.edit (the /images/edits endpoint) with one or more input images and a prompt, and optionally a mask that limits where the change may happen. The request format differs from generation:
- multipart/form-data, not JSON. Images and the mask are uploaded as file parts. Embedding base64 images in a JSON body returns errors.
- Up to 16 input images per request, each a PNG or JPG under 50 MB. One request can combine several images, for example a set of furniture photos composed into a single room, so you don't need to split the work. WebP inputs need converting first.
- The generations endpoint takes no input images. Editing always goes through the edits endpoint.
Prompt-driven edits (no mask)
Without a mask, the model starts from your image and applies the prompt wherever it's relevant. That suits scene-wide changes that keep the subject recognisable, such as restyling a city street photo as a watercolour, turning daytime into dusk, or replacing a background while keeping the composition.
Mask-based edits (inpainting)
Inpainting changes only one region and leaves every other pixel as it is. The mask follows three rules, and all three must hold:
| Rule | Correct | Fails |
|---|---|---|
| File type | PNG (it has an alpha channel) | JPEG, which can't hold transparency |
| Dimensions | Exactly the input image's dimensions | Any mask whose width or height differs from the image's |
| Marking | Area to edit is fully transparent (alpha 0); opaque pixels are kept | Painting the area white, black or any colour: colour marks nothing |
A fully opaque mask therefore allows no change at all. When a mask is invalid, correct the mask itself rather than altering the source image.
Preserving faces and features: input_fidelity
input_fidelity controls how hard the model works to match the style and features of the input images, especially faces. Setting it to high preserves faces more accurately, which matters for catalogue or portrait edits where a person must stay recognisably the same. It is not supported by gpt-image-1-mini, so a workload on the mini model needs another GPT-image deployment (such as gpt-image-1) to use it. Other settings don't do its job: quality adds detail rather than matching the input, and input_fidelity also doesn't confine an edit to a region; only a mask does that.
When should you use FLUX models, and through which API?
Use a FLUX model when its strengths fit the job: in-context editing with consistent characters, multi-reference editing, or fast text-to-image. Each FLUX model plays a different role, and not every model is reachable through the OpenAI-compatible images API.
| Model (ID) | Strength | Input | Max output | Image API? |
|---|---|---|---|---|
| FLUX.1-Kontext-pro | In-context generation and editing; keeps a character consistent across edits | Text + 1 image | 1 MP | Yes (generations and edits) |
| FLUX-1.1-pro | Fast text-to-image with strong prompt adherence | Text only | 1.6 MP | Yes (generations) |
| FLUX.2-pro | Top quality for production at scale; multi-reference editing | Text + up to 8 images | 4 MP | No: BFL API only |
| FLUX.2-flex | Text-heavy layouts and fine detail; multi-reference editing | Text + up to 10 images | 4 MP | No: BFL API only |
Two routes to a FLUX deployment
- Image API: the OpenAI-compatible
/openai/v1/images/generations(and, for Kontext,/images/edits) endpoint. An app that already callsimages.generatecan switch to FLUX-1.1-pro or FLUX.1-Kontext-pro by changing only themodelvalue. Check response handling: the FLUX samples read an image URL, while GPT-image deployments returnb64_json. - BFL provider-specific API:
https://<resource>.api.cognitive.microsoft.com/providers/blackforestlabs/v1/<model-path>?api-version=preview. It supports every FLUX model and is the only route to provider parameters such asseed,guidance,steps,aspect_ratioandsafety_tolerance. Availability varies by model:guidanceandstepsare documented for FLUX.2-flex and FLUX.2-pro, andaspect_ratiofor FLUX.2-pro and FLUX.1-Kontext-pro, so check the model's parameter list.
The URL uses a model path, which is not the model ID: flux-kontext-pro (not FLUX.1-Kontext-pro), flux-pro-1.1, flux-2-pro, flux-2-flex. Using the ID in the path is a common mistake.
So any requirement that depends on a provider parameter, such as a fixed seed for reproducible output, means the BFL route; the Image API and the GPT-image models don't expose one. On FLUX.2-flex, guidance (1.5 to 10, default 4.5) sets prompt adherence, with low values weakening it, and steps trades detail for speed. Parameters don't change what a model accepts as input: a text-only model such as FLUX-1.1-pro can't edit an image whatever you set.
FLUX models don't get built-in content filtering at deployment time, so Microsoft advises configuring content safety at inference. That belongs to the responsible-AI topic of this domain.
How does Sora 2 generate a video?
Sora 2 generates video as an asynchronous job: videos.create starts a render and returns at once with a video object whose status is queued and which contains no video data. Renders take minutes, so the code follows a lifecycle:
- Create with
client.videos.create(model=..., prompt=..., size=..., seconds=...), using the OpenAI client against the resource's/openai/v1/base URL. - Poll
client.videos.retrieve(video_id)until the status iscompleted,failedorcancelled(it passes throughqueuedandin_progress). Thecreate_and_pollhelper does both steps and blocks until the job ends. - Download the MP4 with
client.videos.download_content(video_id, variant="video")and store it.
There is no URL in the create response and no streaming mode for video bytes. Remix is a separate operation for changing a finished video, not a way to start a queued job.
Jobs expire after 24 hours
Generated videos are available for up to 24 hours after the job is created (a completed job shows an expires_at time one day after created_at). After that, the only way to get the video again is a new job; nothing you do with the job object extends the window. The rule for any pipeline is to download each MP4 as soon as it completes and keep it in storage you control.
Designing a web app around long renders
Don't call create_and_poll inside an HTTP request handler: it blocks for the whole render and runs into gateway timeouts. The robust pattern is to call videos.create, return the video ID to the user, and let a background worker poll, download and store the MP4 so the user can come back to it. Keep the API calls on the server side, where the resource's credentials live.
Which parameters control a Sora 2 video, including reference images?
A Sora 2 request is controlled by four main parameters on videos.create, which follows OpenAI's video schema:
| Parameter | Values | Notes |
|---|---|---|
prompt | Text | Describe shot type, subject, action, setting, lighting and camera motion; keep it single-purpose |
size | "720x1280" (portrait, default) or "1280x720" (landscape) | A width x height string; the videos.create parameter table lists only these two sizes |
seconds | 4, 8 or 12 (default 4) | Clip duration |
input_reference | One image file (JPEG, PNG or WebP) | Anchors the first frame; its resolution must match size exactly |
Image-to-video with input_reference
input_reference turns a still into the opening frame of the clip, for example a landscape painting that starts to move. The image must have exactly the requested dimensions, so prepare it (resize or crop) to the size you request before upload. Because the API lists only the two sizes above, you adapt the image to the video size, not the other way round. (Microsoft's overview page also has a limitations list naming more sizes, apparently carried over from the earlier Sora API; the videos.create parameter table is the one to build against.) The reference image is also subject to Sora 2's content rules (see the last section), so it must not show a human face.
Don't mix in the older jobs API
Before Sora 2, Azure OpenAI video generation used a different REST API at /video/generations/jobs with fields such as width, height, n_seconds, inpaint_items and crop_bounds, and statuses such as succeeded. None of those are videos.create arguments. In the Sora 2 API you use size, seconds and input_reference, and the finished status is completed.
How do you edit a generated video?
You edit a generated Sora 2 video with remix: client.videos.remix(video_id, prompt=...) takes the ID of a completed video and a new prompt. The service keeps the original's structure, motion, framing, scene transitions and visual layout, and applies the requested change. The result is a new video job with its own ID (its remixed_from_video_id points at the source), so you poll and download it like any other job.
| Need | Use | Why |
|---|---|---|
| A small change to a clip that is otherwise approved (a cooler colour grade, a different sign on a shopfront) | videos.remix | Keeps framing, camera motion and timing |
| A new composition | videos.create with a new prompt | Regenerating discards the original's structure |
| A new clip that opens on a given still | videos.create with input_reference | Anchors only the first frame; the rest is newly generated |
One adjustment per remix
Microsoft's guidance is to limit each remix to one clearly articulated adjustment: narrow edits keep more fidelity to the source and are less likely to introduce visual defects. When several changes are needed, run them as successive remixes, each built on the last completed result. Packing all of them into one prompt invites drift from the original framing.
Editing exported frames one by one with the image edit API is not a video-editing workflow: each frame is edited independently, so the result loses temporal consistency, and the work is heavy.
Why do Sora 2 generation requests fail?
Sora 2 requests most often fail because they break one of the API's current content restrictions, or because a reference image doesn't match the requested size. The Sora 2 API currently:
- allows only content suitable for audiences under 18;
- rejects copyrighted characters and copyrighted music;
- cannot generate real people, including public figures;
- rejects input images that contain human faces.
These rules apply to the prompt and to input_reference alike, and a remix is a generation too, so it can't be used to add a real person afterwards. A request is checked as a whole, so fixing the prompt doesn't rescue a non-compliant image, or the reverse. The workable design keeps the business goal and removes the restricted element from every input, for example by describing a generic, fictional character instead of a named celebrity.
When a job ends with status failed, check the job's error details: a content-policy rejection needs a changed prompt or image, not a retry. Request-level problems (an unsupported size, a reference image of the wrong dimensions) are rejected outright. Broader responsible-AI controls for visual content, such as content filtering, provenance and safety evaluation, are covered in this domain's responsible-AI topic.
Tip. Expect scenario items that describe a company, an image or video deployment in Foundry and a requirement, then ask you to pick the model, call or parameter that meets it. Many items show parameter values or short OpenAI-client calls, so know the exact names: images.generate, images.edit, b64_json, quality, output_format, background, stream with partial_images, input_fidelity, videos.create, videos.retrieve, download_content, videos.remix, size, seconds and input_reference, plus the FLUX routes and model paths. Troubleshooting items describe a request that fails or behaves unexpectedly and ask what to change; some are multi-select.
- dall-e-3 was retired on 4 March 2026; move to a GPT-image deployment, which uses the same images API but returns b64_json instead of a URL.
- GPT-image-2 is generally available and takes custom sizes (edges in multiples of 16); GPT-image-1, 1.5 and 1-mini need limited-access approval and offer three fixed sizes.
- Lower quality generates faster; streaming with partial_images shows previews sooner but doesn't finish sooner; output_compression only shrinks JPEG files.
- A transparent background needs background="transparent" with output_format="png".
- Edits are multipart/form-data with up to 16 PNG/JPG images under 50 MB; a mask must be a PNG of the same size whose editable area is fully transparent.
- input_fidelity=high preserves faces from input images, but gpt-image-1-mini doesn't support it.
- Only FLUX.1-Kontext-pro and FLUX-1.1-pro use the Image API; provider parameters such as seed, guidance, steps and aspect_ratio need the BFL API (availability varies by model), whose URL uses the model path, not the model ID.
- Sora 2 videos.create returns a queued job: poll, then download_content, and store the MP4 within 24 hours.
- The Sora 2 API lists size 720x1280 or 1280x720 and seconds 4, 8 or 12; input_reference must match size exactly.
- videos.remix edits a completed video while keeping its structure; make one clear adjustment per remix, and remember Sora 2 rejects real people and input images with faces.
Frequently asked questions
What replaces dall-e-3 in Microsoft Foundry?
A GPT-image series model. Microsoft retired dall-e-3 on 4 March 2026, so it can't be deployed and existing deployments no longer serve requests. GPT-image models use the same images API, so an app keeps its images.generate call and points it at the new deployment. The main code change is reading the result: GPT-image models always return base64 data in b64_json rather than an image URL, and response_format isn't supported.
Why is result.data[0].url empty with a GPT-image model?
GPT-image models always return the generated image as a base64 string in b64_json and never return a URL. The response_format parameter that some older image models used to request a URL isn't supported for them. Decode b64_json with base64.b64decode and write the bytes to a file or storage. output_format only changes the encoding (PNG or JPEG), not the delivery.
How do I make a mask for inpainting with GPT-image models?
Create a PNG with exactly the same dimensions as the input image and make the area you want to change fully transparent (alpha 0). Opaque pixels are kept as they are. A JPEG mask can't work because JPEG has no transparency, painting the area a colour marks nothing for editing, and a mask of a different size is rejected. Send the image, prompt and mask as multipart/form-data to the images edits endpoint.
Can I edit an image without a mask?
Yes. If you send images.edit an input image and a prompt with no mask, the model applies the prompt to the image as a whole while starting from your picture. That suits scene-wide changes such as an art-style restyle or a new background that keeps the subject recognisable. Use a mask only when a specific region must change and every other pixel must stay untouched.
How do I get a reproducible seed with FLUX in Foundry?
Call the model through the Black Forest Labs provider API at https://<resource>.api.cognitive.microsoft.com/providers/blackforestlabs/v1/<model-path>?api-version=preview and include seed in the JSON body. Provider parameters such as seed, guidance, steps, aspect_ratio and safety_tolerance are available only on that route, not on the OpenAI-compatible Image API, and which ones apply varies by FLUX model. The URL needs the model path, such as flux-kontext-pro or flux-pro-1.1, which differs from the model ID.
How long are Sora 2 videos available after generation?
Up to 24 hours after the job is created; the job object's expires_at time shows when. After that you must create a new job to get the video again, Production pipelines should download the MP4 with videos.download_content as soon as the status is completed and keep it in their own storage.
Why does Sora 2 reject my reference image?
Usually for one of two reasons. The image must match the requested video size exactly, and the videos.create API lists only two sizes, 720x1280 and 1280x720, so resize or crop it first. And Sora 2 currently rejects input images that contain human faces, along with requests for real people (including public figures) and copyrighted characters or music. An image with no person in it avoids the face rule.
What is the difference between Sora 2 remix and generating a new video?
videos.remix takes the ID of a completed video plus a new prompt and keeps the original's structure, motion and framing while applying the change, so it suits small edits to an approved clip. videos.create starts a new composition, even when you pass a frame as input_reference. Microsoft recommends one clearly articulated adjustment per remix; for several changes, run successive remixes.
Source
This lesson covers the "Implement computer vision solutions" domain of the official AI-103 exam guide. Vendors revise their guides — check the source for the current version.
- Microsoft AI-103 study guide — Microsoft Learn
Sign up free to mark lessons complete, bookmark topics and track your exam readiness.