Files
Placing an order requires providing RPI Print API with the files that contain the design of each
item. Every file must be a PDF, whatever its URL or its server's Content-Type says. Preflight cannot
open a file in any other format, such as a JPEG or a PNG, and fails the order with a message that
begins "This PDF could not be opened. It may be damaged, or it may not be a valid PDF."
What files does a product take?
Every book product takes an interior book block, which you send as gutsUrl. Which further files it
takes depends on the product. Products with a designable cover take a cover, which you send as
coverUrl. Products with a designable dust jacket take a dust jacket, which you send as
dustJacketUrl.
RPI Print API fails an order item whose files do not match the set its SKU declares. The create
request still returns 201, the order moves to FAILED, and RPI Print API sends the
OrderValidationFailed webhook. The order's validations carry the message "Validation failed:
Invalid pdf-assets provided for order items". The message does not name the fields the SKU expects,
so compare the order item with the files its product takes.
No file may reach 2.5 GB, meaning 2,500,000,000 bytes; a file of exactly that size is rejected. Smaller files are recommended because they process faster.
How do I produce a file for every order?
Many RPI Print API customers build products where every file in every order is unique: a customer's name woven into a story, a family photo dropped into a layout, or fully AI-generated text and illustrations. RPI Print API does not provide file creation, design, or hosting tools; that stage is entirely up to you. In practice, customers building personalized products tend to use one of a few approaches:
- Template merge. A fixed design has variable fields, such as a name, date, photo, or address, and a PDF-generation service or a headless-browser HTML-to-PDF pipeline renders it for each order.
- Custom rendering pipeline. An in-house service, often built on a document-templating library or Adobe InDesign Server, assembles pages programmatically and automates tasks like photo placement and resizing.
- AI-generated content. A language model writes personalized text and an image model generates or restyles illustrations. A post-processing step then upscales images to print resolution and corrects the color space.
Whichever approach you use, your integration needs to produce the same output: a press-ready PDF for each file your product takes, meeting the specifications in Content Creation Standards and Preflighting, hosted at a URL your integration can pass to the API.
Where do I host the files?
Each file must be reachable at a public HTTPS URL. RPI refuses http:// URLs and redirects from
HTTPS to HTTP, and follows at most 3 redirects. We strongly recommend Amazon S3 pre-signed URLs in
the us-west-2 region.
RPI stops a download that runs slower than 50 KB/s for 30 seconds in a row, or that does not finish within about 14 minutes, and the file fails to process.
Because these files often contain a customer's personal photos or text, we recommend time-limited pre-signed URLs rather than permanently public objects, and removing source files from your own storage once your retention needs have passed.
When you host the files yourself or use another service, be aware that RPI may download them using HTTP range requests where your server supports them, which can produce several concurrent requests to the same file in a short period.
A Dropbox share link opens a preview page rather than the file. Replace the dl=0 at the end of the
link with dl=1 so that Dropbox returns the PDF itself.
We advise against using Google Drive. Its sharing permissions frequently block RPI from downloading the file, and the order fails.
How long do my files need to stay reachable?
Your files need to stay reachable until RPI sends one of these webhooks for the order. For most orders that happens within a few minutes of submission.
| Webhook | Why RPI no longer needs your files |
|---|---|
OrderAssetsAllProcessed | Every file in the order has been processed, and RPI works from its own copy of each file. |
OrderFailed or OrderValidationFailed | The order has failed. A failed order is final, and RPI does not fetch its files again. |
If you use pre-signed URLs, set them to expire 7 days after you create the order. RPI does not download the files of an order placed over your daily limit until the queue releases it (see Limits and Quotas). With the default limits, at most 300 orders wait in the queue and RPI releases up to 50 of them a day, so every queued order is released within 6 days, and 7 days covers that with a day to spare. A pre-signed URL stops working when the credentials that signed it expire, whatever expiry you set. To get the full 7 days, which is also the longest expiry S3 allows, sign the URL with an IAM user's long-term access keys. A URL signed with temporary credentials, such as an IAM role's credentials in AWS Lambda or Amazon ECS, expires when those credentials do, often within hours.
RPI keeps its copy of each file for 60 days, so that the file is available if it is needed again, for example for a reprint when a recipient receives a damaged book.
What if RPI can't download a file?
When RPI cannot download a file, or cannot finish processing it, the order fails before preflight runs. The order's validations, in the API response and in webhooks, carry one error for that file. It names the file, a code for what went wrong, and the HTTP status your server answered with when that status is why the download failed:
{
"source": "PrintAssetError-Cover",
"humanReadableString": "Cover file failed (SOURCE_ERROR, HTTP 403): your server refused the download.",
"fatalError": true
}
The file is named Cover file, Interior book block file, or Dust jacket file. A failed order is
final, so fix the file or its URL and place a new order.
An order that failed before RPI began reporting these codes, in October 2026, carries the message
Cover file could not be downloaded. (or the same for the other files) with no code.
| Code | What happened | What to do |
|---|---|---|
SOURCE_ERROR | Your server answered with an error status, or the download failed partway through. | With a status, fix what that status reports. A 403 from a pre-signed URL usually means the link expired or was signed for a different request; see How long do my files need to stay reachable?. With no status, the download failed partway through, usually because the connection to your server dropped and occasionally on RPI's side. Place the order again, and if it fails again, check that your server stays up for the whole download. |
SOURCE_NOT_FOUND | Your server answered 404: no file exists at the URL. | Check the URL, and keep the file in place until RPI no longer needs it. |
EMPTY_BODY | Your server returned an empty file. | Check that the URL serves the PDF itself and not a placeholder or a preview page. |
FILE_TOO_LARGE | The file is 2.5 GB or larger. | Make the file smaller, for example by downsampling images above the resolution the product needs. |
DOWNLOAD_TOO_SLOW | The download ran slower than 50 KB/s for 30 seconds in a row. | Host the file somewhere faster. We recommend Amazon S3 in us-west-2. |
DOWNLOAD_TIMEOUT | The download did not finish within about 14 minutes. | Host the file somewhere faster, or make it smaller. |
HTTPS_REQUIRED | The URL does not start with https://. | Send an https:// URL. |
HTTPS_DOWNGRADE | A redirect sent the download to an http:// address. | Make every redirect stay on https://, or send the final URL. |
REDIRECT_LIMIT | The URL redirected more than 3 times. | Send the file's final URL. |
DNS_FAILED | The URL's host name could not be found. | Check that the host name is spelled correctly and resolves on the public internet. |
INVALID_URL | The URL, or a URL it redirected to, is not a valid URL. | Check that the URL is complete and that special characters are percent-encoded. |
SSRF_BLOCKED | The URL points to a private or reserved network address. | Host the file on a server reachable from the public internet. |
INGEST_TIMEOUT | The download stopped without a result on RPI's side. | Place the order again. If it happens again, contact printapicustomersupport@rpiprint.com. |
PROCESSING_TIMEOUT | RPI downloaded the file but could not finish processing it. | Place the order again. If it happens again, contact printapicustomersupport@rpiprint.com. |
How long does processing take?
Processing files can take a long time. Smaller files usually process in tens of seconds, while larger files can take a few minutes. In extremely rare cases, when system load is very high, your files could be put into a queue and it could take many minutes before processing completes.
To learn when processing finishes, use webhooks, or poll the order as Polling for order status describes.