Adds one or SEVERAL PHOTOS to the Google Business Profile listing (visible on Maps/Search) in a single call. Give image_url for one photo, or image_urls for a batch of up to 10 — a batch is the normal case after upload_image, which hands back one public URL per photo the user dropped. Each URL must be a publicly reachable direct image link, because Google downloads it server-side. category applies to every photo in the call: ADDITIONAL (default) | PROFILE (profile picture) | COVER | LOGO | EXTERIOR | INTERIOR | PRODUCT | AT_WORK | FOOD_AND_DRINK | MENU | TEAM — upload different categories in separate calls. LOGO does not work: measured 22 Sep 2026, Google accepted the request, processed it as PROFILE and left every slot unchanged, so the logo has to be set in the Business Profile dashboard by hand. Whatever category you ask for, the reply is now checked against the slot Google actually wrote to; if they differ the photo is reported as failed with both categories and the credit is refunded, instead of a success that changed nothing. A batch is charged PER PHOTO, exactly as separate calls would be, and a photo Google rejects is not charged. If some photos go up and others fail you get both lists back with the reason for each, so a partial result is never reported as full success. This adds photos to the listing's PHOTO GALLERY; it does NOT attach them to an Update post — to publish a post WITH a photo use gbp_create_post(image_url=...). COVER ASPECT RATIO IS CHECKED BEFORE THE UPLOAD: Google rejects a cover photo whose ratio is wrong with a bare "Request contains an invalid argument." that names no cause and still burns the credit, so the image is measured first and you get the actual pixel size, the ratio and what Google expects (16:9). Pass allow_any_ratio=true to skip that check. SAFETY: confirm=false → preview, confirm=true → publish. location = a gbp_list_locations value or the business name/domain.