ScreenshotNeo

BlogGuides

Generating Images from URLs with an API

Learn the difference between generating from a prompt and editing an image supplied by URL, with OpenAI and Stability API workflows.

By the ScreenshotNeo team1 October 20268 min read

“Generating an image from a URL” describes two different jobs:

  1. Prompt-only generation: you send text and receive a newly generated image.
  2. Image-conditioned generation or editing: you send an existing image as visual context, identified by a URL, base64 data URL or uploaded file ID, and ask the model to create or modify an image.

OpenAI documents both workflows. Its Responses API accepts an image input as a fully qualified URL, a base64-encoded data URL or a file ID. Its Image API exposes separate generation and editing operations. Always confirm the current model, request schema and output settings in the vendor’s documentation before shipping.

1. Decide what “URL” means

What you have What you want Typical workflow
A text prompt A new image Call a text-to-image generation endpoint.
An existing public image URL A variation, edit or transformation Pass the URL as an image input where supported, or download it and upload the bytes.
A generated image reference A URL that other systems can fetch Save the returned bytes or hosted asset according to the provider’s output contract.

A URL is not automatically a generated-image URL. Some APIs return image bytes or base64 JSON rather than a public link. Treat input URLs and output storage as separate concerns.

2. OpenAI: supply an image URL as input

OpenAI’s image guide documents three image-input forms for the Responses API: a fully qualified URL, a base64 data URL or a file ID. Use the URL form when the image is reachable by the API and does not require your private browser session. Use a data URL or file upload when the source is private, short-lived or protected. See the official image guide for the current content schema and supported models.

Request shape

The exact model and image-generation tool options change. Keep them configurable and copy the current tool schema from the official guide.

curl https://api.openai.com/v1/responses \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_CURRENT_MODEL",
    "input": [{
      "role": "user",
      "content": [
        {"type": "input_text", "text": "Create a clean editorial variation of this image."},
        {"type": "input_image", "image_url": "https://example.com/source.jpg"}
      ]
    }]
  }'

Replace YOUR_CURRENT_MODEL and the tool or output fields with the values listed in the live documentation. The request demonstrates the important part: the source image is supplied as a fully qualified URL alongside an instruction.

Python

import os
import requests

payload = {
    "model": os.environ["OPENAI_IMAGE_MODEL"],
    "input": [{
        "role": "user",
        "content": [
            {"type": "input_text", "text": "Create an editorial variation of this image."},
            {"type": "input_image", "image_url": "https://example.com/source.jpg"}
        ]
    }]

response = requests.post(
    "https://api.openai.com/v1/responses",
    headers={
        "Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=120,
)
response.raise_for_status()
print(response.json())

Node.js

const payload = {
  model: process.env.OPENAI_IMAGE_MODEL,
  input: [{
    role: 'user',
    content: [
      { type: 'input_text', text: 'Create an editorial variation of this image.' },
      { type: 'input_image', image_url: 'https://example.com/source.jpg' }
    ]
  }]
};

const response = await fetch('https://api.openai.com/v1/responses', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});

if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
console.log(await response.json());

When to use the Image API instead

OpenAI recommends the Image API for a single image from one prompt and the Responses API for conversational or multi-step image workflows. The Image API also documents generation and editing operations. Its output quality, size, format and compression can be adjusted. Check the current image-generation reference for model-specific fields and limits.

3. Base64 and file inputs

A remote URL is convenient, but it can fail when the image is private, expires quickly or blocks automated fetches. Download the image yourself, then send a base64 data URL or upload it using the provider’s file workflow. Base64 increases payload size, so enforce a byte limit before encoding.

python - <<'PY'
import base64, requests

source = requests.get('https://example.com/source.jpg', timeout=30)
source.raise_for_status()
if len(source.content) > 10 * 1024 * 1024:
    raise ValueError('source image exceeds local safety limit')
data_url = 'data:' + source.headers.get('content-type', 'image/jpeg') + ';base64,' + base64.b64encode(source.content).decode()
print(data_url[:80] + '...')
PY

Use the resulting data URL in the image-input field documented by your provider. Do not log the complete value if the image is private.

4. Stability AI: upload image data for image-to-image

Stability AI’s reviewed REST documentation uses authenticated requests and multipart form data. Its image-to-image guide describes modifying an initial image with a prompt, but the reviewed material does not establish that an endpoint fetches an arbitrary remote URL. Download the source image and submit its bytes unless the exact endpoint reference says URL inputs are supported. The REST API reference is authoritative for the endpoint, fields and current model names.

curl -X POST "https://api.stability.ai/YOUR_CURRENT_ENDPOINT" \
  -H "Authorization: Bearer $STABILITY_API_KEY" \
  -H "Accept: image/*" \
  -F "image=@source.jpg" \
  -F "prompt=Create a clean editorial variation"

Some endpoints return image bytes; others can return base64 JSON. Select the response format documented for the endpoint you use.

5. URL, access and security requirements

  • Use an absolute HTTPS URL that returns image bytes with a correct content type.
  • Check redirects, TLS certificates and authentication requirements before sending the request.
  • Do not expose signed URLs or private image URLs in logs, prompts or client-side code.
  • Validate content type and size after downloading; reject HTML error pages masquerading as images.
  • Strip or constrain user-controlled URLs to reduce SSRF risk in your own download service.

6. Output controls and limits

Output controls are vendor- and model-specific. Confirm size, quality, format, compression and background options in the current reference. OpenAI’s image-generation reference lists prompt limits of 32,000 characters for GPT Image models, 1,000 for DALL·E 2 and 4,000 for DALL·E 3. It also documents background options and notes that transparent output requires PNG or WebP for specified supported GPT Image models. These values are not universal limits.

Stability’s reference displays a rate limit of 150 requests every 10 seconds and a documented 10 MiB request-size threshold for an endpoint. It lists 400, 403, 413, 422, 429 and 500 responses. Treat those values as endpoint-specific and recheck them before implementation.

7. One-shot versus iterative workflows

Use case Best fit Reason
One prompt, one image Image API generation Simple request and response.
Reference image plus one edit Image editing or image-to-image endpoint Send image data and an instruction.
Several revisions with conversation context Responses API workflow Keep instructions and image references across steps as supported.

8. Troubleshooting

“Invalid image URL” or a 400 response

Cause: the URL is relative, redirects unexpectedly, returns HTML or requires authentication. Fix: open it from a clean HTTP client, verify the final status, content type and bytes, then use a data URL or upload.

403 or 401 from the source host

Cause: hotlink protection, cookies or a private origin. Fix: fetch the image in your trusted backend and submit bytes; never place provider secrets in browser code.

413 or request-size failure

Cause: the encoded or multipart payload exceeds an endpoint limit. Fix: resize or recompress before upload and enforce a byte ceiling.

429 rate limit

Cause: request bursts exceed the vendor’s current limit. Fix: use exponential backoff with jitter, cap concurrency and honor retry headers when present.

The result is not an image

Cause: you parsed a JSON response as bytes, or the endpoint returned an error document. Fix: inspect status and content type before saving; parse base64 fields when the reference specifies JSON output.

Output does not preserve the source

Cause: generation is prompt-only or the edit strength and reference fields are model-specific. Fix: use the documented editing/image-to-image operation and describe the elements that must remain unchanged.

9. Performance, reliability and cost

  • Latency: download the source once, reuse bytes for retries and set a timeout longer than ordinary JSON requests.
  • Retries: retry transient 429 and 5xx responses with bounded exponential backoff; do not blindly retry validation errors.
  • Idempotency: create a request ID in your system and store the source hash, prompt and provider response so a retry does not create duplicate work unnoticed.
  • Caching: cache source downloads by URL and content hash when licensing and freshness rules allow it.
  • Cost: provider pricing and model availability change. Track image dimensions, retries and failed requests, and check the current pricing page before setting budgets.

10. A practical implementation checklist

  1. Define whether you need prompt-only generation or editing with a reference image.
  2. Confirm that your chosen provider accepts a URL; otherwise download and upload bytes.
  3. Choose URL, base64 or file ID based on privacy, size and lifetime.
  4. Verify the current endpoint, model name, authentication header and request schema.
  5. Set output format, size, quality and compression explicitly where supported.
  6. Validate source content type, dimensions and byte size.
  7. Add bounded retries for 429 and transient 5xx responses.
  8. Store the returned bytes or decode base64 according to the response contract.
  9. Log request metadata without logging private URLs or image data.

Or skip the browser setup

If what you really need is a clean image of a webpage URL, ScreenshotNeo is a screenshot API rather than a generative image model. It accepts one GET request and returns PNG, JPEG, WebP or PDF. Cookie and consent banners, newsletter popups and chat widgets are removed before capture; bot checks, blank pages and failed loads are not billed. Its MCP server lets Claude, Cursor and other MCP clients call take_screenshot, get_page_info and capture_pdf.

See the ScreenshotNeo API documentation for all options. This is a direct capture example:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The free plan includes 1,000 screenshots each month with no card. Paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can every image API fetch a public URL directly?

No. OpenAI documents URL, base64 and file-ID inputs for its Responses API. Stability’s reviewed REST material documents multipart image data and does not establish arbitrary URL fetching.

Should I use a URL or base64?

Use a URL for a stable, publicly reachable image. Use base64 or a file upload for private, expiring or access-controlled images.

Is this the same as taking a webpage screenshot?

No. Generative APIs create or edit pixels from prompts and references. A screenshot API renders a webpage and captures its current visual state.

How do I keep API credentials safe?

Call providers from a server, store keys in environment variables or a secret manager, and never embed them in browser JavaScript.