AI certificate background via API: text-free art, names added in code
Generate a landscape certificate border at 4:3 or 3:2, with no text, then print names and dates with code so nothing is misspelled. Sume rows and cost.

For certificates, diplomas or award cards, generate the decorative background and border with the Sume image API and print the names yourself. Names and dates are exactly the text that must not contain a typo, and image models sometimes alter letters. Splitting the job means one generation (about four cents) and one deterministic text overlay for any number of recipients.
Landscape ratios on the catalog (read 2026-10-03): 4:3 and 3:2 are listed by most rows. Seedream 4.0, 4.5 and 5.0 Lite, Qwen Image and Max, Flux 2 Pro and Flex all list 3:2; the Imagen rows list 4:3 but not 3:2.
Generate the border
Say that the center must stay empty and that there is no text. A single n: 4 call gives four designs for four times the price: $0.15 on Flux 2 Pro. A call that is still running after the 30-second wait returns 202 with a job envelope instead of 200, so check the status code before reading data; see Jobs and results.
import os
import requests
resp = requests.post(
"https://api.sume.com/v1/images",
headers={"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"},
json={
"model": "black-forest-labs/flux.2-pro",
"prompt": "elegant certificate border, thin gold line ornaments in the corners, cream paper texture, large empty center, no text, no letters",
"aspect_ratio": "3:2",
"n": 4,
},
timeout=60,
)
resp.raise_for_status()
if resp.status_code == 202:
print("still running:", resp.json()["data"]["status_url"])
else:
for image in resp.json()["data"]:
print(image["url"])Print the names
Read a CSV and write one PNG per person. Use a font file you have the licence for; the call below falls back to Pillow's bundled font.
import csv
from PIL import Image, ImageDraw, ImageFont
bg = Image.open("border.png").convert("RGB")
font = ImageFont.load_default(size=bg.width // 18)
with open("names.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
img = bg.copy()
d = ImageDraw.Draw(img)
w = d.textlength(row["name"], font=font)
d.text(((img.width - w) / 2, img.height * 0.45), row["name"], font=font, fill="black")
img.save(f"certificate-{row['name']}.png")Why not let the model write the names
Text-in-image is a use for which you can test Ideogram, Flux 2 Flex and others, and Sume publishes no accuracy rate. For a list of 200 different names, any per-image error rate becomes a proofreading job. Deterministic text takes a few lines.
Sources
Related posts
More in Use cases
- AI character series on Shorts: avoid the same situation each time
YouTube's inauthentic content policy flags characters in identical situations with the same outcomes. How to keep an AI character and vary the story in Sume.
- AI children's book illustrations with the same character on every page
Make storybook pages where the hero stays recognisable: draw one anchor image, pass it as a reference on every page call, and keep the style words fixed.
- AI classroom background music for lesson videos, under narration
Make calm instrumental music for a lesson video: a prompt that keeps vocals out, a Python script, and a Timeline bed that ducks under the teacher's voice.
- AI clip to a vertical Short, in order: captions go last
The call order that avoids rework when turning an AI clip into a YouTube Short on Sume: generate, probe, trim, dim, music bed, render, then burn captions last.
Written by Sume