Add an image

Save a banner or billboard in Spyne from a public link, so you can reuse it in many promotions by its id.

Adding the same link twice returns the image you already have instead of making a copy.

POSThttps://api.spyne.ai/api/pv1/branding-assets
AuthBearer tokenRate limit30 changes / min per rooftop

Before you call it

This step is optional: Create a promotion also accepts image links directly and saves them for you.

The link must be public and reachable. Spyne fetches it and refuses links to private or internal addresses (such as localhost or a private IP), links that don't resolve, and links that don't answer with a 2xx or 3xx status within 30 seconds. Use a direct link to a PNG or JPG file.

Counts toward the 30 changes a minute per rooftop.


Request body

Requiredalways send
ParameterTypeRequiredDescription
typestringRequiredbanner (laid over a photo, such as a price strip) or billboard (a full image added as its own slide).
urlstringRequiredPublic link to the image. Spaces at either end are trimmed.

Sample request

curl --request POST \
  --url 'https://api.spyne.ai/api/pv1/branding-assets' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "type": "banner",
  "url": "https://example.com/fall-offer.png"
}'
import requests

url = "https://api.spyne.ai/api/pv1/branding-assets"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
}
payload = {"type": "banner", "url": "https://example.com/fall-offer.png"}

response = requests.post(url, headers=headers, json=payload)
print(response.status_code, response.json())
const response = await fetch("https://api.spyne.ai/api/pv1/branding-assets", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ type: "banner", url: "https://example.com/fall-offer.png" }),
});
console.log(response.status, await response.json());

Sample response

{
  "success": true,
  "statusCode": 201,
  "message": "Asset created",
  "data": {
    "id": "1584",
    "type": "banner",
    "url": "https://example.com/fall-offer.png",
    "duplicate": false
  }
}
{
  "success": true,
  "statusCode": 200,
  "message": "An asset already exists for this exact URL on this team",
  "data": {
    "id": "1584",
    "type": "banner",
    "url": "https://example.com/fall-offer.png",
    "duplicate": true,
    "note": "If this URL now serves a different image than when it was first uploaded, or that asset was deleted, change the URL slightly (e.g. append ?v=2) to create a new asset. Otherwise, reuse this id."
  }
}

Response parameters (201, 200)

ParameterTypeDescription
data.idstringThe image id. Send it as assetId in a promotion.
data.typestringbanner or billboard.
data.urlstringThe saved link.
data.duplicatebooleanfalse for a new image (201). true when this exact link was already saved with the same type (200); the existing image is returned.
data.notestringOnly when duplicate is true.

The same link saved under the other type (banner vs billboard) creates a new image. Changed the picture but kept the same link? Add something like ?v=2 to the link so it's saved as a new image.

Errors

StatusCodeWhen it happens
400INVALID_REQUESTtype or url is missing or invalid. details.errors lists every problem.
400INVALID_ASSET_URLThe link is malformed, private or internal, doesn't resolve, or didn't answer within 30 seconds.
400VALIDATION_FAILEDSpyne refused the image; message says why.
400TEAM_NOT_RESOLVEDThe API key isn't linked to a rooftop.
401UNAUTHORIZEDThe API key is missing or wrong.
429RATE_LIMITEDMore than 30 changes this minute. Wait the seconds in Retry-After.
502 / 503SERVICE_UNAVAILABLEA Spyne service is briefly unavailable. Retry shortly.

Every code is explained in Errors and FAQs. Images can't be deleted through this API.

What happens next

Send the id as assetId when you check and create a promotion.


Did this page help you?