Stripe branding icon: JPG or PNG under 512 KB, 128 px up
Stripe wants a JPG or PNG icon under 512kb and at least 128 x 128 px. Make a 1:1 mark on Sume, shrink it in Pillow, and know where the icon shows up.
Stripe's branding page says icons and logos must be JPG or PNG, less than 512kb, and 128px by 128px or larger. The icon is the square mark; the logo is a non-square override. A 1:1 image from Sume resized to 512 x 512 clears every number on that list with room to spare, as long as you check the file size after saving.
What the icon and logo are used for
The same page has a table of where each setting appears. The practical consequence: if you upload only an icon, it is the one asset that reaches emails, checkout, the customer portal, hosted invoice pages and invoice PDFs. The logo is optional and only shows on Checkout, Payment Links and invoice PDFs.
| Setting | Emails | Checkout and Payment Links | Customer portal | Hosted invoice page | Invoice PDFs |
|---|---|---|---|---|---|
| Icon | Yes | Yes | Yes | Yes | Yes |
| Logo | No | Yes | No | No | Yes |
| Brand color | Yes | No | Yes | Yes | Yes |
| Accent color | Yes (background color) | Yes | Yes | Yes | No |
Generating the square mark on Sume
Use a square ratio and leave lettering out of the prompt. Image models draw marks well and text unreliably, so add a wordmark yourself afterwards. The Image API docs show Seedream 4.5 accepting aspect_ratio: "1:1", which is what the script uses; GET /v1/images/models lists every other model that takes 1:1.
POST /v1/images answers 200 with data[].url when it finishes inside its 30-second budget and 202 with a job envelope when it does not. The script stops on 202 so you can read the job result instead of guessing at the body.
Resize and check the size
Stripe's limit is stated as 512kb, and the page does not say whether that is 512,000 or 524,288 bytes. The script treats 500,000 bytes as the ceiling so either reading passes. JPEG quality steps down until the file fits; a flat-color mark usually fits on the first try.
import os, io, requests
from PIL import Image
r = requests.post(
"https://api.sume.com/v1/images",
headers={"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"},
json={"model": "bytedance-seed/seedream-4.5", "aspect_ratio": "1:1", "prompt": "simple geometric monogram mark on a plain background, flat colors, no text"},
timeout=60,
)
r.raise_for_status()
if r.status_code != 200:
raise SystemExit("202: read the finished job from /v1/jobs/{id}/result")
img = Image.open(io.BytesIO(requests.get(r.json()["data"][0]["url"], timeout=60).content))
img = img.convert("RGB").resize((512, 512), Image.LANCZOS)
for q in (92, 85, 75, 65):
img.save("stripe-icon.jpg", "JPEG", quality=q)
if os.path.getsize("stripe-icon.jpg") < 500_000:
break
else:
raise SystemExit("icon is still over the size limit")
print(os.path.getsize("stripe-icon.jpg"), "bytes")Order of operations
Resize first, then compress, and check the size last. If you also need the optional non-square logo, make it a separate generation, since a square mark cropped into a wide shape usually looks wrong.
Notes
- Stripe does not state a maximum pixel size on this page. 512 x 512 is a choice that keeps the file small while staying above 128 px.
- Branding is account-wide and set in the Dashboard. The page notes that Connect platforms and non-Connect users cannot configure their own branding through the Accounts API.
- A single image is billed at the amount shown in the
usage.costfield of the response. Failed generations are not billed. - If the mark needs transparent corners, request a PNG from a model that supports
background: transparent; the docs name ChatGPT Image 2.5 for that.
Sources
Related posts
More in Developers
- STT sentence segmentation: unpunctuated speech split on silence
Sume STT 1.0 segmentation mode sentence returns gapless sentence segments, splitting unpunctuated runs on silence. Options, boundary_lead_ms and caveats.
- Submit 20 music takes at once: queued is normal, queue_full is not
Sume accepts music jobs as queued while the queue has room, then returns 429 queue_full. Default accepted-job capacity by plan, from 6 on Free to 120 on Scale.
- subscribeFormatRun onCreated: save the run id, set your own key
subscribeFormatRun makes a new Idempotency-Key per call unless you pass one. Save the run id in onCreated and pass a stable key so a restart cannot double-run.
- Sume schedule 404 action_not_found: five causes behind one code
One 404 action_not_found covers an unknown id, an archived schedule, a foreign workspace, a wrong handle or slug, or a team-owned schedule. A checklist.
Written by Sume