Skip to content
yeetpostyeetpost

Media

Upload an image, list and delete them, render HTML into one.


Images you upload once and attach to posts. Free within your storage allowance.

List your images

GET/media

Your uploaded and rendered images, newest first, each with the posts that attach it. Read an image itself with GET /media/{mediaId}. A scoped key lists only its own profile's images.

Pages are walked with cursor: pass the cursor of one page as ?cursor= for the next, until it comes back null.

Rate limit: 60 requests per minute per API key.

curl "https://api.yeetpost.com/api/v2/media" \  -H "x-api-key: $YEETPOST_API_KEY"

query parameters

connectionSlugstringoptional

Only images attached to a post on this connection.

postIdstring <uuid>optional

Only images attached to this post.

createdAfterstring <date-time>optional

Only images uploaded after this ISO 8601 timestamp.

cursorstringoptional

The cursor of the previous page.

limitinteger, 1 to 100, default 25optional

Images per page, 1 to 100. Defaults to 25.

response 200

One page of images.

headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset

response body

mediaobject[]required
media[].idstring <uuid>required
media[].contentTypestringrequired

image/png | image/jpeg | image/gif | image/webp

media[].sizeBytesintegerrequired
media[].altTextstring | nullrequired
media[].createdAtstring <date-time>required
media[].postIdsstring <uuid>[]required

The posts that attach the image, newest first.

cursorstring | nullrequired

Pass as ?cursor= for the next page. Null on the last page.

errors

400

A malformed query parameter.

Missing or invalid API key.

More than 60 requests in a minute for this API key. Back off and retry.

Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.

What each code means and the fix: errors.

Upload an image

POST/media

Uploads one image and answers with the id you attach to a post. The body is the raw file, not a multipart form: set Content-Type to the image type and send the bytes. The bytes have to be that type: a file whose signature disagrees with the header is rejected with 400 invalid_media_type.

Images are free. The only limits are size: 8 MB per image, 50 MB stored per account, and 5 images per post. Delete images you no longer need to make room.

Uploading the same bytes twice is one image. The second upload answers with the id of the first and costs nothing against your allowance, so a client that retries an upload cannot fill your storage with copies. If the second upload carries alt_text and the stored image has none, the description is kept; if the stored image already has one, it wins and the new one is ignored. Give a post its own altText to override either.

Rate limit: 60 requests per minute per API key.

curl -X POST "https://api.yeetpost.com/api/v2/media" \  -H "x-api-key: $YEETPOST_API_KEY" \  -H "content-type: image/png" \  --data-binary @image.png
response 200
{  "mediaId": "9b1c2d3e-4f50-4a6b-8c7d-1e2f3a4b5c6d",  "contentType": "image/png",  "sizeBytes": 48213}

query parameters

alt_textstring, at most 1000 charactersoptional

Description of the image for screen readers, kept with the upload and used by every post that attaches it unless the post gives its own.

The image itself. At most 8 MB.

response 200

The image is stored and ready to attach.

headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset

response body

mediaIdstring <uuid>required

Id to attach to a post. Uploading the same bytes again returns this same id.

contentTypestringrequired

image/png | image/jpeg | image/gif | image/webp

sizeBytesintegerrequired

Size of the stored image in bytes.

errors

Empty body, a bad alt_text, or bytes that are not the image type they were sent as (invalid_media_type).

Missing or invalid API key.

The image is over 8 MB (media_too_large), or storing it would put you over your 50 MB allowance (media_storage_full).

The Content-Type is not one of the image types we take.

More than 60 requests in a minute for this API key. Back off and retry.

Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.

What each code means and the fix: errors.

Download an image

GET/media/{mediaId}

Serves the bytes back, with the Content-Type they were uploaded as. The response also carries X-Content-Type-Options: nosniff and Content-Disposition: inline, so a browser renders it as the type it is and never guesses another. Only your own images: somebody else's id answers 404.

Rate limit: 60 requests per minute per API key.

curl "https://api.yeetpost.com/api/v2/media/9b1c2d3e-4f50-4a6b-8c7d-1e2f3a4b5c6d" \  -H "x-api-key: $YEETPOST_API_KEY"

path parameters

mediaIdstring <uuid>required

Id of the image, as returned by POST /media.

response 200

The image itself.

headers: x-content-type-options, content-disposition, x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset

errors

Malformed media id.

Missing or invalid API key.

No image of yours with that id.

More than 60 requests in a minute for this API key. Back off and retry.

Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.

What each code means and the fix: errors.

Delete an image

DELETE/media/{mediaId}

Deletes the image and frees the storage. Posts that used it keep their text and lose the image, so delete an image only once the posts that need it have gone out. A scheduled post whose images were deleted sends as text.

Rate limit: 60 requests per minute per API key.

curl -X DELETE "https://api.yeetpost.com/api/v2/media/9b1c2d3e-4f50-4a6b-8c7d-1e2f3a4b5c6d" \  -H "x-api-key: $YEETPOST_API_KEY"
response 200
{  "id": "9b1c2d3e-4f50-4a6b-8c7d-1e2f3a4b5c6d",  "deleted": true}

path parameters

mediaIdstring <uuid>required

Id of the image, as returned by POST /media.

response 200

The image is deleted.

headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset

response body

idstring <uuid>required
deletedbooleanrequired

true

errors

Malformed media id.

Missing or invalid API key.

No image of yours with that id.

More than 60 requests in a minute for this API key. Back off and retry.

Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.

What each code means and the fix: errors.

Serve an image to a platform that fetches it by URL

GET/media/{mediaId}/raw

Instagram and Threads do not take an upload: a post names a URL and Meta's own servers fetch the bytes from it, with no API key to send. So this one endpoint serves an image without a key, and only through a link yeetpost signed for that image: the id and an expiry, HMAC'd, good for one hour, and minted only when a post to one of those two platforms actually needs it.

You never build these URLs and you never receive one. There is no way to ask for a link, nothing lists them, and an id with no matching signature is a 404, so an id cannot be probed for existence. It is documented because it is a public route on this API and you may see it in your logs.

Rate limit: 60 requests per minute per IP address.

curl "https://api.yeetpost.com/api/v2/media/9b1c2d3e-4f50-4a6b-8c7d-1e2f3a4b5c6d/raw?exp=&sig="

path parameters

mediaIdstring <uuid>required

Id of the image.

query parameters

expintegerrequired

When the link stops working, as a Unix timestamp in seconds.

sigstringrequired

The signature over the id and the expiry.

response 200

The image itself.

errors

The link is expired, unsigned, signed wrong, or names an image that is not there. All four answer the same way.

More than 60 requests in a minute for this API key. Back off and retry.

Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.

What each code means and the fix: errors.

Render HTML into an image

POST/images/render

Renders one HTML document into a jpeg or png and stores it as an image you can attach to a post, exactly as if you had uploaded it. Use it for cards: a quote, a launch graphic, a chart drawn in HTML and SVG.

Size the card with preset (square 1200x1200, landscape 1200x627, portrait 1080x1350) or with width and height (200 to 2000). The size is in CSS pixels and the image is drawn at twice that density, so a 1200x1200 card is a 2400x2400 file. A render is stored under the same 8 MB per image and 50 MB per account limits as an upload.

What a card can load. JavaScript does not run. The only network a card has is Google Fonts (fonts.googleapis.com and fonts.gstatic.com); every other request is blocked. To show one of your own uploaded images, write yeetpost-media:<mediaId> where a URL goes, for example <img src="yeetpost-media:9b1c2d3e-4f50-4a6b-8c7d-1e2f3a4b5c6d">. We inline it before rendering. A key can only reference images it could attach to a post, the images in one card may total at most 10 MB with every use of an image counted, and anything else is 400 invalid_media.

Allowance. 300 renders per calendar month (UTC) per account. A render that fails on the renderer's side does not count; one that times out or comes out over 8 MB does, because it used the renderer's time. Past 300 the answer is 429 render_allowance_reached, naming the date it comes back. An account can also start at most 30 renders a minute across all its keys (429 render_rate_limited).

Attaching. Send postId to append the image to a scheduled post, after the images it already has (five at most). The post is checked before rendering, so one that cannot take the image costs nothing. A post that is being sent answers 409 post_not_editable; if it is picked up mid-render, the image is kept, the render counts, and the error carries mediaId and rendersUsed so you can still use the image. Otherwise use the returned mediaId in mediaIds when you create the post.

A render that takes more than 10 seconds is 504 render_timeout, a renderer failure is 502 render_failed, and 503 renderer_busy means try again in a few seconds; all are safe to retry.

Rate limit: 20 requests per minute per API key.

curl -X POST "https://api.yeetpost.com/api/v2/images/render" \  -H "x-api-key: $YEETPOST_API_KEY" \  -H "content-type: application/json"

request body (application/json)

htmlstring, 1 to 200000 charactersrequired

The card as an HTML document with inline CSS. No JavaScript runs. Reference your own uploads as yeetpost-media:<mediaId>.

presetstringoptional

square 1200x1200, landscape 1200x627, portrait 1080x1350.

square | landscape | portrait

widthinteger, 200 to 2000optional

Width in CSS pixels. Needs height.

heightinteger, 200 to 2000optional

Height in CSS pixels. Needs width.

formatstringoptional

jpeg | png

altTextstring, at most 1000 charactersoptional

Description of the image for screen readers.

connectionIdstring <uuid>optional

The connection the card is for. Recorded with the render; it does not restrict where the image can be posted.

postIdstring <uuid>optional

A scheduled post to append the image to, after its existing images.

response 200

The image is rendered, stored and ready to attach.

headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset

response body

mediaIdstring <uuid>required

Id to attach to a post. Rendering identical bytes again returns this same id.

contentTypestringrequired

image/jpeg | image/png

sizeBytesintegerrequired

Size of the stored image in bytes.

widthintegerrequired

The card's width in CSS pixels. The image itself is twice this.

heightintegerrequired

The card's height in CSS pixels. The image itself is twice this.

postIdstring <uuid> | nullrequired

The post the image was appended to, or null when no postId was sent.

rendersUsedintegerrequired

Renders used this calendar month (UTC), this one included.

rendersLimitintegerrequired

Renders allowed per calendar month.

errors

The request is malformed, a yeetpost-media: reference is not yours (invalid_media), or the post already has five images (too_many_media).

Missing or invalid API key.

connectionId is not one of your connections, or postId is not one of your scheduled posts.

The post was picked up for sending and can no longer be edited (post_not_editable).

The rendered image is over 8 MB (media_too_large), or storing it would put you over your 50 MB allowance (media_storage_full).

The rate limit (20 requests per minute per key, or 30 renders per minute per account as render_rate_limited), or the month's render allowance (render_allowance_reached).

Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.

The renderer failed (render_failed).

The renderer is busy (renderer_busy). The render was not counted.

The card took more than 10 seconds to render (render_timeout).

What each code means and the fix: errors.