Stillframe

Get started API reference What it can picture Plans and limits Using the picture When a feed fails Paying

API reference

Every route a customer can call. Everything the dashboard does, the API does.

The basics

The feed object

Every call that returns a feed returns this shape.

fieldmeaning
idthe number to use in /api/feeds/{id}
nameyour label, up to 100 characters
kindpage, camera or push. Fixed when the feed is made.
urlthe page address, with any password before the @ shown as ***; for a camera, the address with the user and password shown as ***@ and every value after a ? shown as *** (names kept, such as ?user=***&channel=***; a part with no = is a value and is hidden whole); null for a push feed
canvasthe size you chose: 1920x1080, 1080x1920, 3840x2160, 2160x3840, or native (camera and push feeds only)
canvas_in_usethe size being drawn. The same as canvas, except that on a plan without 4K a 4K canvas is drawn at 1080p, same orientation.
refresh_in_use_show often the feed is really refreshed. The same as refresh_s, except that if the plan's fastest refresh is slower than the feed's own, the plan's is used; refresh_s keeps what you chose. null for a push feed.
background#rrggbb, the colour around a picture smaller than the canvas
formatpng or jpg
refresh_sseconds between pictures; null for a push feed
wait_sextra seconds a page waits after it stops loading, 0 to 20
timezonethe time zone a page's clock shows, such as America/New_York
allow_blanktrue if an all-one-colour page is a good picture
enabledfalse stops page and camera refreshes. The last picture is still served.
image_urlthe permanent address of the picture
status.statepending (no result yet), ok, or failing
status.last_ok_at, last_attempt_atUTC times, or null
status.error, detailwhile failing: the reason (see When a feed fails), else null
status.partialtrue if the last good picture was taken before the page finished loading
status.lag_show many seconds past due the next picture is; null for push feeds and disabled feeds
status.render_ms, byteshow long the last attempt took, and the disk this feed uses
status.versioncounts pictures stored; it is the picture's ETag

Settings you can send

Used by POST /api/feeds and PATCH /api/feeds/{id}. A field not in this table is refused with unknown_field.

fieldallowedif you leave it out
kindpage, camera, push. Required when making a feed; ignored when changing one.(required)
nametext, up to 100 charactersempty
urlpage: http:// or https://. Camera: rtsp://, http:// or https://. At most 2048 characters. Not allowed on a push feed.(required for page and camera)
canvasthe four sizes above, the 4K pair only on Standard and Pro; native for camera and pushpage 1920x1080; camera and push native
background#rrggbb or rrggbbblack, #000000
formatpng or jpgcamera jpg; page and push png
refresh_sa whole number of seconds from your plan's fastest refresh to 86400 (a day). Page and camera only.900, or your plan's fastest if that is slower
wait_sa number from 0 to 201
timezonea name such as America/New_YorkUTC
allow_blanktrue or falsefalse
enabledtrue or falsetrue

The address of a page or camera must pass the checks on What it can picture when you make or change the feed, and again every time a picture is taken.

Routes

GET /f/{token}.png and GET /f/{token}.jpg

The feed's newest picture. No key. HEAD works too. Use the extension of the feed's format. After a format change the other extension keeps working too (see PATCH below), so an address someone already embedded does not break.

GET /api/account

Your plan, its limits and what you use. Works while the account is suspended.

{"email": "[email protected]", "plan": "standard", "status": "active", "feeds": 3, "feeds_allowed": 20,
 "fastest_refresh_s": 300, "history_kept": 24, "storage_used": 412339, "storage_allowed": 2147483648,
 "choices": {"canvases": [["1920x1080", "1080p, landscape"], ...], "four_k_plans": "Standard and Pro", "four_k_needs": "Standard or Pro", "refresh_s": [300, 600, ...],
             "default_background": "#000000"}}

status is active, past_due, suspended or closed. A closed account has no key.

GET /api/feeds

All your feeds, oldest first: {"feeds": [feed, ...]}.

POST /api/feeds

Make a feed. Body: the settings above. Answers 201 with the feed.

curl -s -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"kind":"page","url":"https://example.com/","canvas":"800x600"}' https://stillframe.us/api/feeds
{"error": "bad_canvas", "detail": "canvas is one of: 1080x1920, 1920x1080, 2160x3840, 3840x2160"}

GET /api/feeds/{id}

One feed. A feed that is not yours is answered exactly like one that does not exist: 404 not_found.

PATCH /api/feeds/{id}

Change any of the settings, sending only what changes. Answers 200 with the feed.

DELETE /api/feeds/{id}

Remove the feed and its pictures. Answers 200 with {"deleted": id}. Its address stops working.

PUT /api/feeds/{id}/image

Send a picture to a push feed. The body is the file itself; the Content-Type you send is ignored, because the file is read for what it is. At most 10 MB and 50 million pixels, PNG or JPEG. Stillframe draws it again to the feed's canvas and format before serving it, so hidden details in the file are not passed on.

POST /api/feeds/{id}/render

Ask for a page or camera feed to be photographed now. Answers 202 {"queued": id}; the picture arrives when the render finishes. Also clears a failure's slow-down. Once a minute for each feed (429 slow_down otherwise). A push feed answers 400 not_rendered.

POST /api/feeds/{id}/retoken

Give the feed a new address. The old one stops working at once. Answers 200 with the feed. A copy someone already saved elsewhere (an email, a chat) is theirs to lose.

Errors

statuscodemeaning
400bad_kindkind is missing or is not page, camera or push
400bad_namethe name is not text, or is over 100 characters
400bad_urlthe address is missing, too long, unreadable, the wrong kind of address for this feed, or given to a push feed
400blocked_addressthe address is private or local, or on a port Stillframe does not fetch from
400address_not_foundthe name does not resolve
400bad_canvasnot one of the sizes (or native on a page)
400canvas_needs_plana 4K canvas on a plan without 4K; the detail names the plans that have it. Sending the canvas a feed already has is not refused.
400bad_backgroundnot a colour like #1c1917
400bad_formatnot png or jpg
400bad_refreshnot a whole number in the range your plan allows. Sending back the value the feed already has is not refused, even if your plan's fastest rate has since risen above it.
400bad_waitnot a number from 0 to 20
400bad_timezonenot a time zone name
400bad_allow_blank, bad_enablednot true or false
400unknown_fieldthe detail lists the fields that are not settings
400bad_jsonthe body is not a JSON object
400not_pushonly a push feed takes a picture
400not_rendereda push feed is updated by sending it a picture
401unauthorizedno key, a wrong key, or a closed account
402suspendedthe subscription is not active
403csrfa dashboard change without its anti-forgery header; scripts using a key never see this
404not_foundno such feed, address or route
404no_image_yetthe feed has no picture yet
405method_not_allowedthat method does not work on that route
409feed_limitthe plan holds no more feeds
411length_requiredsend a Content-Length
413too_largethe body is over its limit
415bad_imagenot a PNG or JPEG
422bad_imagecould not be drawn
429slow_downtoo many calls; wait Retry-After seconds
500internala fault on our side; try again
503compose_failed, launch_failedthe picture could not be drawn; try again
507quotathe plan's storage is full