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"}}'
Response 201 (some fields left out)
{
  "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"
autofill once complete
{
  "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"
Response 200 (some fields left out)
{
  "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"]}'
FieldRule
tagline / short_description / long_descriptionUp to 100, 500 and 2,000 characters. Most directories show the short description.
categorysaas, ai_tools, dev_tools, no_code, productivity or other. We map it to each directory's own list.
pricing_modelfree, freemium, paid or open_source, with price_amount_cents and price_period for a paid plan.
tagsUp to 10, each up to 40 characters.
competitors, promo_code, audienceThese 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"
Response 200 (some fields left out)
{
  "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_8812 returns the project, so your CRM can find it by its own id.
  • readiness.ready is true on the project and on GET /projects/prj_4QzX1m9Lr2Vb7Nc8Tk3HwP/readiness.
  • autofill.status is complete, or you filled in the name, tagline and short description yourself.

What can go wrong

CodeStatusFix
project_exists409Another project has this url, contact_email or external_id. Use the one in existing, or change the field.
validation_failed422A field breaks a rule; errors names each one. With a live key, a .test site fails with not_public_url.
image_unreachable422The image URL did not return an image. Upload the file instead.
quota_exceeded422Before your first purchase, test mode allows 25 projects and 100 new ones a day.

Next steps