Onboard a client's product
Turn a client's URL into a project that is ready to launch, with what we read from the site, images, a contact email and your own references.
What you'll build
A draft project for one client: the name, tagline and short description read from their site, a logo, screenshots and a contact email, plus your CRM's id so you can find it later. When readiness.ready is true, the project is ready to launch. A draft costs nothing.
Before you start
- A key. A test key works for every step, and test mode accepts sites on
.test. With a live key, use your client's real site. - What your client gives you. The site's URL, an email address they read, and their logo and 1 to 5 screenshots, as files or URLs.
The contact email matters: some directories register the listing to it and send their emails there. It cannot change once the project launches.
1. Create the project from the URL
Only url is required. Send the contact email, your own id in external_id, and anything else you keep about the client in metadata.
curl https://api.submitator.com/v1/projects \
-H "Authorization: Bearer $SUBMITATOR_API_KEY" \
-H "Idempotency-Key: crm_8812-create" \
-H "Content-Type: application/json" \
-d '{"url": "https://ledgerly.test", "contact_email": "founder@ledgerly.test", "external_id": "crm_8812", "metadata": {"account_owner": "Priya"}}'{
"object": "project",
"id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
"status": "draft",
"url": "https://ledgerly.test",
"name": "Ledgerly",
"contact_email": "founder@ledgerly.test",
"logo": null,
"screenshots": [],
"autofill": { "status": "running", "name_source": "domain", "filled": [], "image_candidates": [] },
"readiness": { "ready": false, "missing": ["logo", "screenshots"] },
"external_id": "crm_8812",
"metadata": { "account_owner": "Priya" }
}The Idempotency-Key makes the call safe to send twice: a repeat within 24 hours returns this same project. Each url, contact_email and external_id belongs to one project per mode, so a second project with any of them returns 409 project_exists, with the first one in existing.
2. Wait for the site to be read
Right after the create call, autofill.status is running and name comes from the domain. Read the project again until the status is complete: by then the name, tagline and short description you left empty are filled in.
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP \
-H "Authorization: Bearer $SUBMITATOR_API_KEY"{
"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 }
]
}Autofill fills only the fields you left empty, and never sets an image by itself. When it ends failed, the site could not be read: fill in the fields yourself in step 4.
3. Add the images
image_candidates lists images on the site that could serve: the site's icon as a logo, its social preview as a screenshot. Pass one as url, or upload your client's own file as multipart/form-data. A project needs 1 logo and 1 to 5 screenshots, in PNG, JPEG, GIF or WebP up to 5 MB.
curl -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/apple-touch-icon.png"}'
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/screenshots \
-H "Authorization: Bearer $SUBMITATOR_API_KEY" \
-F "file=@dashboard.png"{
"object": "project",
"id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
"logo": { "object": "image", "id": "img_5Mx2Kq8Wt3Lr9Vb7Nz1HdQ", "status": "ready", "error": null },
"screenshots": [
{ "object": "image", "id": "img_2Kr9Lx3Wq7Mt5Vb8Nz1HcF", "status": "ready", "error": null }
],
"readiness": { "ready": true, "missing": [] }
}Directories that take a single screenshot use the first one, so add the strongest first. You can also pass logo_url and screenshot_urls in the create call, and they import in the background.
4. Fill in what directories ask for
Directories ask for more than a name: a category, the pricing, tags and the maker. Send what you know with PATCH; a field you leave out keeps its value.
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"]}'| Field | Rule |
|---|---|
tagline / short_description / long_description | Up to 100, 500 and 2,000 characters. Most directories show the short description. |
category | saas, ai_tools, dev_tools, no_code, productivity or other. We map it to each directory's own list. |
pricing_model | free, freemium, paid or open_source, with price_amount_cents and price_period for a paid plan. |
tags | Up to 10, each up to 40 characters. |
competitors, promo_code, audience | These open more directories: Reach more directories. |
null or an empty string clears a field. A list you send, such as tags, replaces the whole list.
5. Check that it is ready
GET /projects/{project_id}/readiness is free. It says whether the project can launch, how many directories a launch would get now, and what would unlock more.
curl https://api.submitator.com/v1/projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/readiness \
-H "Authorization: Bearer $SUBMITATOR_API_KEY"{
"object": "readiness",
"ready": true,
"missing": [],
"directories": { "selected": 87, "limit": 100, "top_domain_rating": 92, "median_domain_rating": 48 },
"unlocks": [
{ "requirement": "badge", "directories": 9, "how": "Install the badge on https://ledgerly.test and verify it." }
],
"cost": { "launches": 1, "available": 100 }
}Until ready is true, missing names what to add: contact_email, logo or screenshots.
Check it worked
GET /projects?external_id=crm_8812returns the project, so your CRM can find it by its own id.readiness.readyistrueon the project and onGET /projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/readiness.autofill.statusiscomplete, or you filled in the name, tagline and short description yourself.
What can go wrong
| Code | Status | Fix |
|---|---|---|
project_exists | 409 | Another project has this url, contact_email or external_id. Use the one in existing, or change the field. |
validation_failed | 422 | A field breaks a rule; errors names each one. With a live key, a .test site fails with not_public_url. |
image_unreachable | 422 | The image URL did not return an image. Upload the file instead. |
quota_exceeded | 422 | Before your first purchase, test mode allows 25 projects and 100 new ones a day. |
Next steps
- Launch and track: spend 1 launch and follow each listing.
- Reach more directories: what the unlocks mean and how to get them.
- Install the badge: the unlock most projects can get.