Projects
A project is one of your client's products. Create it from a URL and we fill in what the site tells us; then add a logo, 1 to 5 screenshots and a contact email.
A draft costs nothing and you can delete it. Once launched, a project stays: it cannot be deleted, and its contact_email can no longer change.
Returns your projects in the key's mode, newest first. Filter by status, find one by your own external_id, or search names and URLs with q.
status?stringOnly projects in this status.
"draft""in_progress""action_required""on_hold""completed"external_id?stringOnly the project with this external_id. Matches the whole value, case-sensitive.
length <= 100q?stringOnly projects whose name or URL contains this text, ignoring case. 2 to 100 characters.
2 <= length <= 100cursor?stringnext_cursor from the previous page of the same list, as you received it. Leave it out for the first page.
length <= 500limit?integerHow many items to return, 1 to 100. Defaults to 20.
1 <= value <= 10020One page of projects.
application/json- response
One page of a list. Projects, newest first.
object*stringAlways list.
data*array<>The items on this page.
has_more*booleantrue when there is another page.
next_cursor*|Send it as cursor for the next page. null when has_more is false.
length <= 500Typical errors
curl "https://api.submitator.com/v1/projects" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY"{ "object": "list", "data": [ { "object": "project", "id": "prj_1Nc7Vd3Kq8Zr5Tx2Wm9LbH", "livemode": false, "status": "in_progress", "hold_reason": null, "action": null, "url": "https://quotafy.test", "name": "Quotafy", "maker_name": "Tom Okafor", "contact_email": "sales@quotafy.test", "tagline": "Quotes your clients sign in one click", "short_description": "Quotafy turns a price list into quotes that clients accept and sign online, with reminders and a deposit link.", "long_description": null, "category": "saas", "pricing_model": "paid", "price_amount_cents": 2900, "price_period": "monthly", "launch_date": "2026-08-20", "twitter_url": "https://x.com/quotafy", "competitors": [ { "name": "Bidsheet", "url": "https://bidsheet.test" } ], "tags": [ "quotes", "proposals", "e-signature" ], "audience": { "b2b": true, "ai": false, "directory": false }, "promo_code": "QUOTE30", "promo_description": "30% off the first 3 months", "logo": { "object": "image", "id": "img_1Qa8Kx3Wm7Lt2Vb9Rz5NcE", "status": "ready", "url": "https://feed.example.net/a/Qf2Lm8Wx.k5Tp3", "error": null }, "screenshots": [ { "object": "image", "id": "img_4Qb2Kw9Lx5Mt8Vb3Rz7NdG", "status": "ready", "url": "https://feed.example.net/a/Qg9Nt4Vb.z7Kr2", "error": null } ], "autofill": { "status": "complete", "name_source": "input", "filled": [], "image_candidates": [] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 12, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [ "dir_3Vb8Qm2Xk6Lt9Wr4Nc1ZpG" ], "allowance": { "total": 100, "used": 72, "reserved": 20, "available": 8 }, "progress": { "total": 92, "pending": 0, "in_progress": 20, "action_required": 0, "submitted": 33, "live": 39, "not_accepted": 0, "cancelled": 0 }, "external_id": "crm_8907", "metadata": {}, "created_at": "2026-10-05T09:40:18Z", "updated_at": "2026-10-08T13:31:52Z", "launched_at": "2026-10-05T10:12:07Z" }, { "object": "project", "id": "prj_3Ac9Kx4Wq7Lt2Vb8Rz5NmD", "livemode": false, "status": "completed", "hold_reason": null, "action": null, "url": "https://acme.test", "name": "Acme CRM", "maker_name": "Lena Park", "contact_email": "hello@acme.test", "tagline": "The CRM for teams of five", "short_description": "Acme CRM keeps contacts, deals and follow-ups in one shared list, with a weekly digest for the whole team.", "long_description": null, "category": "saas", "pricing_model": "freemium", "price_amount_cents": 900, "price_period": "monthly", "launch_date": null, "twitter_url": null, "competitors": [], "tags": [ "crm", "sales" ], "audience": { "b2b": true, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": "img_3Ad7Kx2Wq8Lt4Vb9Rz1NmH", "status": "ready", "url": "https://feed.example.net/a/Ac6Rk1Wn.p4Lx8", "error": null }, "screenshots": [ { "object": "image", "id": "img_0Ae5Kw1Lq9Xt3Vb7Rz2McJ", "status": "ready", "url": "https://feed.example.net/a/Ad3Mq7Zt.v9Kc1", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline" ], "image_candidates": [] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 51, "badge": { "status": "installed", "checked_at": "2026-10-03T15:08:30Z" }, "auto_replace": false, "excluded_directories": [], "allowance": { "total": 100, "used": 85, "reserved": 0, "available": 15 }, "progress": { "total": 88, "pending": 0, "in_progress": 0, "action_required": 0, "submitted": 3, "live": 82, "not_accepted": 2, "cancelled": 1 }, "external_id": "crm_8650", "metadata": {}, "created_at": "2026-10-03T15:01:44Z", "updated_at": "2026-10-07T18:22:47Z", "launched_at": "2026-10-03T15:12:09Z" } ], "has_more": true, "next_cursor": "cur_Pq7Lx2Wm9Kt4Vb8R"}Creates a draft for one of your client's products. Only url is required: we read the site and fill in the name, tagline and short description you leave out. Images given as logo_url and screenshot_urls import in the background, so they show importing first. A draft costs nothing.
Idempotency-Key?stringA unique string, such as a UUID, that makes a retry safe. A success is kept for 24 hours: a repeat with the same key and body returns it again with Idempotent-Replayed: true, and the same key with another body returns 422 idempotency_key_reused. A repeat while the first request runs returns 409 idempotency_key_in_use. An error changes nothing, so a repeat after one runs again.
1 <= length <= 255application/json- body
A new project. Only url is required; autofill fills in the name, tagline and short description you leave out. Add contact_email, a logo and at least 1 screenshot before you launch.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name?stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name?|The person directories list as the maker, up to 100 characters.
length <= 100contact_email?|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline?|One line about the product, up to 100 characters.
length <= 100short_description?|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description?|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category?|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model?|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents?|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period?|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date?|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url?|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors?array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags?array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience?Marks that open the directories which accept only some kinds of products.
promo_code?|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description?|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo_url?stringA public URL of the logo, imported in the background: PNG, JPEG, GIF or WebP, up to 5 MB. logo.status shows importing until it is done.
urilength <= 2048screenshot_urls?array<>1 to 5 public URLs of screenshots, imported in the background in this order. Directories that take a single screenshot use the first.
1 <= items <= 5external_id?|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata?Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20excluded_directories?array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
auto_replace?booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
The new draft, as created from the from_a_url request.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timecurl -X POST "https://api.submitator.com/v1/projects" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY" \ -H "Idempotency-Key: 4f9d2c1e-ledgerly-create" \ -H "Content-Type: application/json" \ -d '{"url":"https://ledgerly.test","contact_email":"founder@ledgerly.test","external_id":"crm_8812","logo_url":"https://ledgerly.test/press/logo.png","screenshot_urls":["https://ledgerly.test/press/dashboard.png"]}'{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "draft", "hold_reason": null, "action": null, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": null, "contact_email": "founder@ledgerly.test", "tagline": null, "short_description": null, "long_description": null, "category": null, "pricing_model": null, "price_amount_cents": null, "price_period": null, "launch_date": null, "twitter_url": null, "competitors": [], "tags": [], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": null, "status": "importing", "url": null, "error": null }, "screenshots": [ { "object": "image", "id": null, "status": "importing", "url": null, "error": null } ], "autofill": { "status": "running", "name_source": "domain", "filled": [], "image_candidates": [] }, "readiness": { "ready": false, "missing": [ "logo", "screenshots" ] }, "domain_rating": null, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [], "allowance": null, "progress": null, "external_id": "crm_8812", "metadata": {}, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-03T13:58:12Z", "launched_at": null}Returns the project with its status, readiness, allowance and listing counts. Poll it, or follow project.* events, to learn about changes.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$The project.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timeTypical errors
curl "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY"{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "action_required", "hold_reason": null, "action": { "code": "install_badge", "waiting_on": "client", "client_message": "Please add the directory badges block to https://ledgerly.test. 9 directories list Ledgerly once their badges show on the site." }, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": "Maya Chen", "contact_email": "founder@ledgerly.test", "tagline": "Double-entry bookkeeping for solo founders", "short_description": "Ledgerly keeps the books for one-person companies: bank sync, invoices and a year-end pack for your accountant.", "long_description": null, "category": "saas", "pricing_model": "freemium", "price_amount_cents": 1200, "price_period": "monthly", "launch_date": null, "twitter_url": null, "competitors": [], "tags": [ "accounting", "bookkeeping", "invoicing" ], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": "img_5Mx2Kq8Wt3Lr9Vb7Nz1HdQ", "status": "ready", "url": "https://feed.example.net/a/Lq7Wx2Km.r9Tz4", "error": null }, "screenshots": [ { "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "url": "https://feed.example.net/a/Sv3Nk8Qp.m2Wx7", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline", "short_description" ], "image_candidates": [ { "url": "https://ledgerly.test/apple-touch-icon.png", "suggested_as": "logo", "width": 180, "height": 180 }, { "url": "https://ledgerly.test/og-image.png", "suggested_as": "screenshot", "width": 1200, "height": 630 } ] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 34, "badge": { "status": "not_found", "checked_at": "2026-10-08T09:12:44Z" }, "auto_replace": true, "excluded_directories": [], "allowance": { "total": 100, "used": 78, "reserved": 14, "available": 8 }, "progress": { "total": 96, "pending": 0, "in_progress": 5, "action_required": 9, "submitted": 8, "live": 70, "not_accepted": 3, "cancelled": 1 }, "external_id": "crm_8812", "metadata": { "account_owner": "Priya", "crm_stage": "onboarding" }, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-08T14:17:01Z", "launched_at": "2026-10-03T14:05:40Z"}Changes the fields you send and leaves the others as they are. Send null or an empty string to clear a field. After launch contact_email can no longer change; other edits apply to listings that have not reached their directory yet.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$application/json- body
The fields to change. Fields you leave out keep their value; null or an empty string clears a field. Change images with the logo and screenshot operations.
1 <= propertiesurl?stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name?stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name?|The person directories list as the maker, up to 100 characters.
length <= 100contact_email?|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline?|One line about the product, up to 100 characters.
length <= 100short_description?|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description?|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category?|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model?|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents?|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period?|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date?|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url?|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors?array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags?array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience?Marks that open the directories which accept only some kinds of products.
promo_code?|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description?|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500external_id?|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata?Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20excluded_directories?array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
auto_replace?booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
The project after the change.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timeTypical errors
curl -X PATCH "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"maker_name":"Maya Chen","category":"saas","pricing_model":"freemium","price_amount_cents":1200,"price_period":"monthly","tags":["accounting","bookkeeping","invoicing"],"metadata":{"account_owner":"Priya","crm_stage":"onboarding"}}'{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "draft", "hold_reason": null, "action": null, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": "Maya Chen", "contact_email": "founder@ledgerly.test", "tagline": "Double-entry bookkeeping for solo founders", "short_description": "Ledgerly keeps the books for one-person companies: bank sync, invoices and a year-end pack for your accountant.", "long_description": null, "category": "saas", "pricing_model": "freemium", "price_amount_cents": 1200, "price_period": "monthly", "launch_date": null, "twitter_url": null, "competitors": [], "tags": [ "accounting", "bookkeeping", "invoicing" ], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": "img_5Mx2Kq8Wt3Lr9Vb7Nz1HdQ", "status": "ready", "url": "https://feed.example.net/a/Lq7Wx2Km.r9Tz4", "error": null }, "screenshots": [ { "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "url": "https://feed.example.net/a/Sv3Nk8Qp.m2Wx7", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline", "short_description" ], "image_candidates": [ { "url": "https://ledgerly.test/apple-touch-icon.png", "suggested_as": "logo", "width": 180, "height": 180 }, { "url": "https://ledgerly.test/og-image.png", "suggested_as": "screenshot", "width": 1200, "height": 630 } ] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 34, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [], "allowance": null, "progress": null, "external_id": "crm_8812", "metadata": { "account_owner": "Priya", "crm_stage": "onboarding" }, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-03T14:02:31Z", "launched_at": null}Deletes a project that has not launched, with its images. A launched project cannot be deleted: the call returns 409 already_launched and changes nothing.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$The project is deleted.
application/json- response
What was deleted.
object*stringThe kind of object that was deleted.
"project""webhook_endpoint"id*stringThe deleted object's id.
livemode*booleantrue in live mode, false in test mode.
deleted*booleanAlways true.
Typical errors
curl -X DELETE "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY"{ "object": "project", "id": "prj_5Ob2Kx8Wq3Lt7Vb9Rz1NmE", "livemode": false, "deleted": true}Removes the logo from a draft. A launched project must keep a logo: removing it returns 422 validation_failed, so replace it with PUT instead.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$The project without a logo. readiness.missing lists logo again.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timeTypical errors
curl -X DELETE "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/logo" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY"{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "draft", "hold_reason": null, "action": null, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": null, "contact_email": "founder@ledgerly.test", "tagline": "Double-entry bookkeeping for solo founders", "short_description": "Ledgerly keeps the books for one-person companies: bank sync, invoices and a year-end pack for your accountant.", "long_description": null, "category": null, "pricing_model": null, "price_amount_cents": null, "price_period": null, "launch_date": null, "twitter_url": null, "competitors": [], "tags": [], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": null, "screenshots": [ { "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "url": "https://feed.example.net/a/Sv3Nk8Qp.m2Wx7", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline", "short_description" ], "image_candidates": [ { "url": "https://ledgerly.test/apple-touch-icon.png", "suggested_as": "logo", "width": 180, "height": 180 }, { "url": "https://ledgerly.test/og-image.png", "suggested_as": "screenshot", "width": 1200, "height": 630 } ] }, "readiness": { "ready": false, "missing": [ "logo" ] }, "domain_rating": 34, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [], "allowance": null, "progress": null, "external_id": "crm_8812", "metadata": {}, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-03T14:00:55Z", "launched_at": null}Uploads the logo as multipart/form-data with a file field, or imports it from url in a JSON body. PNG, JPEG, GIF or WebP up to 5 MB; it replaces the current logo. Imports from a URL count toward a limit of 60 per hour.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$- body
An image file, sent as multipart/form-data.
file*fileA PNG, JPEG, GIF or WebP file of up to 5 MB.
binaryThe project, with the new logo in logo.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timecurl -X PUT "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/logo" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://ledgerly.test/press/logo.png"}'{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "draft", "hold_reason": null, "action": null, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": null, "contact_email": "founder@ledgerly.test", "tagline": "Double-entry bookkeeping for solo founders", "short_description": "Ledgerly keeps the books for one-person companies: bank sync, invoices and a year-end pack for your accountant.", "long_description": null, "category": null, "pricing_model": null, "price_amount_cents": null, "price_period": null, "launch_date": null, "twitter_url": null, "competitors": [], "tags": [], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": "img_5Mx2Kq8Wt3Lr9Vb7Nz1HdQ", "status": "ready", "url": "https://feed.example.net/a/Lq7Wx2Km.r9Tz4", "error": null }, "screenshots": [ { "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "url": "https://feed.example.net/a/Sv3Nk8Qp.m2Wx7", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline", "short_description" ], "image_candidates": [ { "url": "https://ledgerly.test/apple-touch-icon.png", "suggested_as": "logo", "width": 180, "height": 180 }, { "url": "https://ledgerly.test/og-image.png", "suggested_as": "screenshot", "width": 1200, "height": 630 } ] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 34, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [], "allowance": null, "progress": null, "external_id": "crm_8812", "metadata": {}, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-03T14:01:20Z", "launched_at": null}Adds one screenshot, uploaded as file or imported from url. A project holds 1 to 5 screenshots, and directories that take a single screenshot use the first one. The new screenshot is the last item of screenshots in the response.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$- body
An image file, sent as multipart/form-data.
file*fileA PNG, JPEG, GIF or WebP file of up to 5 MB.
binaryThe project, with the new screenshot last in screenshots.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timeTypical errors
curl -X POST "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/screenshots" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://ledgerly.test/press/reports-page.png"}'{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "draft", "hold_reason": null, "action": null, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": "Maya Chen", "contact_email": "founder@ledgerly.test", "tagline": "Double-entry bookkeeping for solo founders", "short_description": "Ledgerly keeps the books for one-person companies: bank sync, invoices and a year-end pack for your accountant.", "long_description": null, "category": "saas", "pricing_model": "freemium", "price_amount_cents": 1200, "price_period": "monthly", "launch_date": null, "twitter_url": null, "competitors": [], "tags": [ "accounting", "bookkeeping", "invoicing" ], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": "img_5Mx2Kq8Wt3Lr9Vb7Nz1HdQ", "status": "ready", "url": "https://feed.example.net/a/Lq7Wx2Km.r9Tz4", "error": null }, "screenshots": [ { "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "url": "https://feed.example.net/a/Sv3Nk8Qp.m2Wx7", "error": null }, { "object": "image", "id": "img_6Wn3Kq8Lx2Rt7Vb9Mz4HcB", "status": "ready", "url": "https://feed.example.net/a/Tz5Kq1Wm.n8Lr3", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline", "short_description" ], "image_candidates": [ { "url": "https://ledgerly.test/apple-touch-icon.png", "suggested_as": "logo", "width": 180, "height": 180 }, { "url": "https://ledgerly.test/og-image.png", "suggested_as": "screenshot", "width": 1200, "height": 630 } ] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 34, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [], "allowance": null, "progress": null, "external_id": "crm_8812", "metadata": { "account_owner": "Priya", "crm_stage": "onboarding" }, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-03T14:03:05Z", "launched_at": null}Removes one screenshot. A launched project keeps at least 1, so removing its last screenshot returns 422 validation_failed.
project_id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$image_id*stringThe screenshot's id, from screenshots[].id on the project.
^img_[0-9A-Za-z]{22}$The project without that screenshot.
application/json- response
One of your client's products, from draft to the last listing.
object*stringAlways project.
id*stringThe project's id.
^prj_[0-9A-Za-z]{22}$livemode*booleantrue for a live project, false for a test project.
status*stringWhere the project stands. When more than one fits, the first in this list wins:
on_hold: work is paused;hold_reasonsays why.action_required: you or your client need to act;actionsays what.in_progress: listings are moving and nobody needs to act.completed: no listing ispending,in_progressoraction_required, and auto-replace has nothing to add. Listings insubmittedcan still go live.draft: not launched yet.
The console and reports show these as Draft, In progress, Needs you, On hold and Completed.
"draft""in_progress""action_required""on_hold""completed"hold_reason*|Why work is paused, when status is on_hold: review while we review the project, which clears without action from you, or paused when we paused it. null otherwise.
"review""paused"nullaction*|What to do, when status is action_required. null otherwise.
url*stringYour client's site, http or https, up to 2,048 characters. Unique among your projects in the mode. Live mode accepts public addresses only: no IP addresses and no .test, .example, .invalid or .localhost hosts.
urilength <= 2048name*stringThe product's name as directories show it, 2 to 100 characters. Until you set one, it comes from the domain, and once autofill finishes, from the site's title.
2 <= length <= 100maker_name*|The person directories list as the maker, up to 100 characters.
length <= 100contact_email*|Required to launch. Some directories register the listing to this address and send their emails here. Unique among your projects in the mode, and fixed once the project launches.
emaillength <= 254tagline*|One line about the product, up to 100 characters.
length <= 100short_description*|A short description, up to 500 characters. Most directories show this one.
length <= 500long_description*|A longer description, up to 2,000 characters, for directories that take one.
length <= 2000category*|The product's category. We map it to each directory's own list of categories.
"saas""ai_tools""dev_tools""no_code""productivity""other"nullpricing_model*|How the product is sold.
"free""freemium""paid""open_source"nullprice_amount_cents*|The headline price in US cents, such as 1200 for $12. Leave it null for a free product.
0 <= valueprice_period*|What price_amount_cents pays for.
"monthly""yearly""one_time"nulllaunch_date*|The day the product went public, YYYY-MM-DD, for directories that ask for it. Not the day the project launched here: that is launched_at.
datetwitter_url*|The product's profile on X, as an https://x.com/ or https://twitter.com/ URL.
^https://(x|twitter)\.com/.+uricompetitors*array<>Up to 20 products this one is an alternative to. Some directories list a product only next to its competitors. Sending a list replaces the whole list.
items <= 20tags*array<>Up to 10 keywords of up to 40 characters each. Sending a list replaces the whole list.
items <= 10audience*Marks that open the directories which accept only some kinds of products.
promo_code*|A discount code for the product, up to 50 characters. Some directories list only products with one.
length <= 50promo_description*|What promo_code gives, up to 500 characters, such as 30% off the first 3 months.
length <= 500logo*|The logo, or null when the project has none.
screenshots*array<>0 to 5 screenshots, in the order directories use them.
items <= 5autofill*What we read from the client's site to fill in the project.
readiness*Whether the project can launch. GET /projects/{project_id}/readiness shows the full preview.
domain_rating*|The client's site's Domain Rating from Ahrefs, 0 to 100. null until it is measured, which starts after your first purchase.
0 <= value <= 100badge*The badge on the client's site, as of the last check. GET /projects/{project_id}/badge has the install kit.
auto_replace*booleanNew projects start with true. When true, we add fitting directories from the free allowance for you: after a listing ends not_accepted or cancelled, after the badge passes verification, and when a new directory joins the catalog. A launch with include turns it off unless the launch sends auto_replace: true.
excluded_directories*array<>Directories never to use for this project: auto launches, auto adds and auto-replace skip them. A launch with exclude adds its list here. Sending a list replaces the whole list.
allowance*|How the launch's 100 directories are spent. null before launch.
progress*|How many listings are in each status. null before launch.
external_id*|Your own id for the project, up to 100 characters, such as the client's id in your CRM. Unique among your projects in the mode; find a project by it with GET /projects?external_id=.
length <= 100metadata*Your own key-value data. We store it and return it, and use it for nothing else.
properties <= 20created_at*stringWhen the project was created.
date-timeupdated_at*stringWhen a field, the status or a listing count last changed.
date-timelaunched_at*|When the project launched. null for a draft.
date-timeTypical errors
curl -X DELETE "https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/screenshots/img_6Wn3Kq8Lx2Rt7Vb9Mz4HcB" \ -H "Authorization: Bearer $SUBMITATOR_API_KEY"{ "object": "project", "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP", "livemode": false, "status": "draft", "hold_reason": null, "action": null, "url": "https://ledgerly.test", "name": "Ledgerly", "maker_name": "Maya Chen", "contact_email": "founder@ledgerly.test", "tagline": "Double-entry bookkeeping for solo founders", "short_description": "Ledgerly keeps the books for one-person companies: bank sync, invoices and a year-end pack for your accountant.", "long_description": null, "category": "saas", "pricing_model": "freemium", "price_amount_cents": 1200, "price_period": "monthly", "launch_date": null, "twitter_url": null, "competitors": [], "tags": [ "accounting", "bookkeeping", "invoicing" ], "audience": { "b2b": false, "ai": false, "directory": false }, "promo_code": null, "promo_description": null, "logo": { "object": "image", "id": "img_5Mx2Kq8Wt3Lr9Vb7Nz1HdQ", "status": "ready", "url": "https://feed.example.net/a/Lq7Wx2Km.r9Tz4", "error": null }, "screenshots": [ { "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "url": "https://feed.example.net/a/Sv3Nk8Qp.m2Wx7", "error": null } ], "autofill": { "status": "complete", "name_source": "site", "filled": [ "name", "tagline", "short_description" ], "image_candidates": [ { "url": "https://ledgerly.test/apple-touch-icon.png", "suggested_as": "logo", "width": 180, "height": 180 }, { "url": "https://ledgerly.test/og-image.png", "suggested_as": "screenshot", "width": 1200, "height": 630 } ] }, "readiness": { "ready": true, "missing": [] }, "domain_rating": 34, "badge": { "status": "not_checked", "checked_at": null }, "auto_replace": true, "excluded_directories": [], "allowance": null, "progress": null, "external_id": "crm_8812", "metadata": { "account_owner": "Priya", "crm_stage": "onboarding" }, "created_at": "2026-10-03T13:58:12Z", "updated_at": "2026-10-03T14:03:40Z", "launched_at": null}