Reports for clients
Build a PDF or XLSX report of a project's listings under your agency's name, wait until it is ready, and download it within 7 days.
What you'll build
A report to forward to your client: every directory with its status, and the link once a listing is live, prepared under your agency's name. The PDF reads as a document; the XLSX has 1 row per listing for your own sheets. For a client portal of your own, the same data comes from the listings.
Before you start
- A launched project. A report lists its listings, so a draft has nothing to show.
- Somewhere to keep the file. Reports are deleted 7 days after they are ready.
1. Build the report
POST /projects/{project_id}/reports starts a report in pdf or xlsx. Each project can start 1 PDF every 30 seconds and 1 XLSX every 10 seconds.
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/reports \
-H "Authorization: Bearer $SUBMITATOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"format": "pdf"}'{
"object": "report",
"id": "rep_6Hn2Wq8Lx3Kt9Vb5Rz1MdP",
"livemode": false,
"project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
"format": "pdf",
"include_logins": false,
"status": "building",
"file_name": null,
"created_at": "2026-10-08T15:02:10Z",
"ready_at": null,
"expires_at": null
}2. Wait until it is ready
The report moves from building to ready, or to failed. Wait for the report.ready webhook, or read the report every 3 seconds.
curl https://api.submitator.com/v1/reports/rep_6Hn2Wq8Lx3Kt9Vb5Rz1MdP \
-H "Authorization: Bearer $SUBMITATOR_API_KEY"{
"object": "report",
"id": "rep_6Hn2Wq8Lx3Kt9Vb5Rz1MdP",
"livemode": false,
"project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
"format": "pdf",
"include_logins": false,
"status": "ready",
"file_name": "ledgerly-listings-2026-10-08.pdf",
"created_at": "2026-10-08T15:02:10Z",
"ready_at": "2026-10-08T15:02:41Z",
"expires_at": "2026-10-15T15:02:41Z"
}A failed report sends report.failed. Build a new one, and write to support with the event's id if it fails again.
3. Download the file
GET /reports/{report_id}/file returns the file itself, with its name in Content-Disposition. Keep a copy: after expires_at the call returns 410 gone.
curl https://api.submitator.com/v1/reports/rep_6Hn2Wq8Lx3Kt9Vb5Rz1MdP/file \
-H "Authorization: Bearer $SUBMITATOR_API_KEY" \
-o ledgerly-listings.pdfThe report shows statuses with the labels the console uses: Pending, In progress, Needs you, Submitted, Live, Not accepted and Cancelled. In test mode the file is a sample marked TEST MODE.
4. Or build your own view
For a page in your own portal, read the listings and show what you like. Each live listing has its live_url, and proof_url is a screenshot of it when there is one.
curl "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/listings?status=live&limit=100" \
-H "Authorization: Bearer $SUBMITATOR_API_KEY"{
"object": "listing",
"id": "lst_7Hk2Qn4Rt9Vx1Bm6Cz3LdK",
"directory": { "id": "dir_2Lm8Wq3Zk7Rt1Xc5Vb9NdF", "name": "BetaList", "domain_rating": 73 },
"status": "live",
"live_url": "https://betalist.com/startups/ledgerly",
"proof_url": "https://feed.example.net/a/Pf8Kq2Wm.t6Lx9",
"live_at": "2026-10-08T14:00:00Z"
}The images in proof_url and the directory logos load from a neutral host with no brand on it, so they can go on your client's page as they are. A Domain Rating you show should credit Ahrefs, which measures it.
5. Include the logins
Some directories need an account to list a product, and we create one there for your client. Send include_logins: true to hand those logins over with the report: the PDF gets a Directory logins page and the XLSX a Logins sheet, with each directory, where to sign in, the email, the username where the directory uses one, and whether the account is ready. Both show the project's one password, which every login uses.
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/reports \
-H "Authorization: Bearer $SUBMITATOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"format": "pdf", "include_logins": true}'{
"object": "report",
"id": "rep_3Vx8Lm2Qt7Kn5Wb9Rz4HcJ",
"format": "pdf",
"include_logins": true,
"status": "building"
}Wait for it and download it as in steps 2 and 3. The limits of step 1 count reports with logins separately, so a PDF with logins can start right after a PDF without.
The file holds credentials, so only a key with full permissions and your team in the console can download it: a read-only key gets 403 permission_denied. The page of a share link never offers it, even when it is the newest report, so send the file to your client yourself.
Ask your client to keep the password unchanged while listings are in progress: every account signs in with it. For your own portal, Logins returns the same logins as JSON, and the emails each directory sent to its login, unless they go to your client's own address.
Check it worked
GET /reports/rep_6Hn2Wq8Lx3Kt9Vb5Rz1MdPshowsstatusreadyand anexpires_at7 days afterready_at.- The downloaded file opens, and its rows match
GET /projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/listings.
What can go wrong
| Code | Status | Fix |
|---|---|---|
rate_limited | 429 | A report of the same format, with or without logins as this one, started less than 30 seconds (PDF) or 10 seconds (XLSX) ago. Wait the seconds in Retry-After. |
not_found | 404 | The report is still building, or the id is unknown in this mode. |
gone | 410 | The file is older than 7 days and was deleted. Build a new report. |
validation_failed | 422 | format is not pdf or xlsx, or include_logins is not true or false. |
Next steps
- Launch and track: what the statuses in the report mean.
- Receive webhooks: get
report.readyinstead of polling. - Reports: the operations in full.