Back to home

LaunchIgniter Submission API

Submit a product once and have it listed across all three directories in the LaunchIgniter network:

DirectoryDomainWhat you get
launchigniterlaunchigniter.comProduct page with a dofollow backlink
startuptrustedstartuptrusted.comAuto-approved startup listing with a dofollow backlink
saasgrowsaasgrow.appBadge-verified SaaS listing with a dofollow backlink
  • Base URL: https://api.launchigniter.com
  • Content type: application/json
  • Access: by invitation. Contact us to have a key issued for your account.

Authentication

Every request needs the API key you were issued. Send it either way:

Authorization: Bearer lip_live_xxxxxxxxxxxxxxxxxxxxxxxx
X-API-Key: lip_live_xxxxxxxxxxxxxxxxxxxxxxxx

Your key is bound to a LaunchIgniter account and carries three things set when it was issued:

  1. Which directories you may submit to.
  2. How many submissions you get per directory.
  3. A validity window — after expiresAt the key stops working.

Keys are stored hashed. If you lose one it cannot be recovered, only rotated — ask us for a replacement.

Errors

HTTPerrorMeaning
401authentication_requiredNo key sent
401invalid_api_keyKey is unknown, or the linked account was deleted
401api_key_revokedKey was revoked
401api_key_expiredKey is past its validity window
403directory_not_grantedYou asked for a directory your key cannot use
403no_directory_accessThe key has no directories granted at all
400invalid_requestA field failed validation, or an image could not be downloaded — read message
429rate_limitedYou are sending too fast — see Rate limits below
500server_errorSomething broke on our side; safe to retry
503image_storage_unavailableOur image storage was briefly unreachable; retry the request

GET /partner/v1/me

Check what your key can do and how much quota is left. Call this first.

curl https://api.launchigniter.com/partner/v1/me \
  -H "Authorization: Bearer $LAUNCHIGNITER_API_KEY"
{
  "key": {
    "name": "Acme Agency - production",
    "mask": "lip_live_a1b2c3...9f8e",
    "createdAt": "2026-09-01T10:12:00.000Z",
    "expiresAt": "2027-09-01T00:00:00.000Z",
    "lastUsedAt": "2026-09-03T08:41:22.000Z"
  },
  "account": {
    "name": "Acme Agency",
    "username": "acme",
    "email": "[email protected]"
  },
  "directories": [
    { "directory": "launchigniter", "name": "LaunchIgniter", "limit": 250, "used": 12, "remaining": 238 },
    { "directory": "startuptrusted", "name": "StartupTrusted", "limit": 250, "used": 12, "remaining": 238 },
    { "directory": "saasgrow", "name": "SaaSGrow", "limit": null, "used": 12, "remaining": null }
  ]
}

A limit of null means unlimited.


GET /partner/v1/categories

The authoritative list of category slugs accepted by the categories field. Categories are mapped automatically to the closest equivalent on StartupTrusted and SaaSGrow, so you only ever send LaunchIgniter slugs.

curl https://api.launchigniter.com/partner/v1/categories \
  -H "Authorization: Bearer $LAUNCHIGNITER_API_KEY"
{
  "categories": [
    { "name": "Artificial Intelligence", "slug": "ai" },
    { "name": "Developer Tools", "slug": "developer-tools" },
    { "name": "SaaS", "slug": "saas" }
  ]
}

Commonly used slugs include ai, saas, developer-tools, marketing, productivity, design, ecommerce, finance, analytics-tool, chrome-extension, mobile-app, newsletter, no-code, seo-tools, project-management and website-builder. Always fetch the live list rather than hardcoding it.


POST /partner/v1/listings

Submit one product to every directory your key can reach.

curl -X POST https://api.launchigniter.com/partner/v1/listings \
  -H "Authorization: Bearer $LAUNCHIGNITER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme AI",
    "tagline": "Ship your SaaS in a weekend",
    "description": "Acme AI turns a product brief into a deployable Next.js app with auth, billing and a dashboard already wired up.",
    "websiteUrl": "https://acme.ai",
    "logoUrl": "https://acme.ai/logo.png",
    "categories": ["ai", "developer-tools"],
    "demoVideoUrl": "https://www.youtube.com/watch?v=xxxxxxxxxxx",
    "screenshotUrls": [
      "https://acme.ai/shots/dashboard.png",
      "https://acme.ai/shots/editor.png"
    ],
    "isOpenSource": false,
    "isVibeCoded": true,
    "maker": {
      "email": "[email protected]",
      "name": "Acme Founder"
    },
    "directories": ["launchigniter", "startuptrusted", "saasgrow"]
  }'

Request body

FieldTypeRequiredNotes
namestringyesMax 80 characters. Truncated to 28 on StartupTrusted and SaaSGrow, which have shorter title limits.
taglinestringyesMax 200 characters. One line — this is the listing subtitle on LaunchIgniter.
descriptionstringyesMax 5000 characters. Carried in full to all three directories and shown on the listing page. StartupTrusted and SaaSGrow also shorten it at a word boundary for their card blurb and meta description.
websiteUrlstringyesMust be http(s). Used for duplicate detection.
logoUrlstringyesMust be http(s) and point at a publicly reachable image. Copied to our CDN on submission — see Images below. Every directory shows the listing with its logo.
categoriesstring[]yes1–3 slugs from GET /partner/v1/categories. The first one drives the category on the other two directories.
demoVideoUrlstringnoYouTube or Loom URL. LaunchIgniter only.
screenshotUrlsstring[]yes1–6 image URLs, kept in the order given. Copied to our CDN on submission — see Images below. Shown on the LaunchIgniter listing only.
isOpenSourcebooleannoDefaults to false. LaunchIgniter only.
isVibeCodedbooleannoDefaults to false. LaunchIgniter only.
maker.emailstringnoThe account the StartupTrusted and SaaSGrow listings are created under, so your client can claim and edit them. Defaults to the email on your key. An account is created there if none exists.
maker.namestringnoDisplay name for that account.
directoriesstring[]noSubset of the directories your key is granted. Defaults to all of them.

The LaunchIgniter product itself is always owned by the account your key belongs to. maker only affects the two partner directories.

Response

Each directory is reported independently, so a failure on one never blocks the others.

HTTPstatusMeaning
201completedEvery requested directory succeeded
207partialSome directories succeeded, some did not
422failedNo directory accepted the listing
200Idempotent replay of an earlier submission
{
  "status": "completed",
  "createdAt": "2026-09-03T09:15:04.221Z",
  "listing": {
    "name": "Acme AI",
    "tagline": "Ship your SaaS in a weekend",
    "websiteUrl": "https://acme.ai",
    "categories": ["ai", "developer-tools"],
    "makerEmail": "[email protected]"
  },
  "results": [
    {
      "directory": "launchigniter",
      "name": "LaunchIgniter",
      "status": "success",
      "listingSlug": "acme-ai",
      "listingUrl": "https://launchigniter.com/product/acme-ai"
    },
    {
      "directory": "startuptrusted",
      "name": "StartupTrusted",
      "status": "success",
      "listingSlug": "acme-ai",
      "listingUrl": "https://startuptrusted.com/startup/acme-ai"
    },
    {
      "directory": "saasgrow",
      "name": "SaaSGrow",
      "status": "success",
      "listingSlug": "acme-ai",
      "listingUrl": "https://saasgrow.app/saas/acme-ai/timeline"
    }
  ],
  "quota": [
    { "directory": "launchigniter", "name": "LaunchIgniter", "limit": 250, "used": 13, "remaining": 237 },
    { "directory": "startuptrusted", "name": "StartupTrusted", "limit": 250, "used": 13, "remaining": 237 },
    { "directory": "saasgrow", "name": "SaaSGrow", "limit": null, "used": 13, "remaining": null }
  ]
}

Per-directory result status

StatusMeaningConsumes quota
successA new listing was createdyes
duplicateThe product was already listed there. The existing listing is brought live — approved and badge-verified — and listingUrl points at itno
failedThe directory rejected the listing; see errorno
skippedYour submission allowance for that directory is used up; the result also carries "quotaExceeded": trueno

Only newly created listings count against your quota, so retries after a partial failure are free.

An existing listing is never a failure. If any of the three directories already carries the product — whether it came from an earlier API call, a Pro launch, or a submission made directly on that site — the listing is approved and badge-verified so it goes live, and the directory reports duplicate with the existing listingUrl. Ownership of an existing listing is never transferred; it stays with whoever created it.

Common failed reasons:

  • A product with this name or website was rejected on LaunchIgniter — the product was turned down by moderation. Resubmitting will not override that.
  • Integration not configured — a temporary outage on our side. Safe to retry.

Rate limits

Limits are per API key, not per IP, so your traffic is never affected by another partner.

ScopeLimit
All endpoints120 requests per 15 minutes
POST /partner/v1/listings20 submissions per hour

Submissions are held to a tighter limit because one call fans out to three directories and downloads every image you reference.

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Going over returns HTTP 429 with "error": "rate_limited"; wait for the window in RateLimit-Reset and retry. A 429 never creates a listing, so retrying is safe.

If your volume needs a higher ceiling, ask and we will raise it on your key.

Images

logoUrl and screenshotUrls may point at any public host. We do not hotlink them: each image is downloaded once, at submission time, and stored on our own CDN. The listing then uses our copy, so it keeps rendering even if you later move or delete the original.

That means the URLs in the response are ours, not the ones you sent:

"logoUrl": "https://minio-l408owcw08k844gg4wk4ck8g.173.249.12.9.sslip.io/launch-igniter/images/1717171717-3f9c2a1b.png"

Store whatever we return rather than hardcoding the host — the storage host can change.

Requirements for every image URL:

  • Reachable over http(s) from the public internet at the moment you submit — no auth, no signed URLs that have already expired, no internal hosts.
  • Served with an image content type: PNG, JPEG, GIF, WebP, AVIF, SVG, BMP or ICO.
  • 10MB or smaller.

If any image fails these checks the whole submission is rejected with a 400 and a message naming the offending URL — nothing is listed. Fix the URL and call the endpoint again.

Idempotency

There is nothing to send. Retries are safe by default, and we deduplicate on your behalf using your API key and the submitted websiteUrl.

If you already completed a submission for that site, we return the original result with HTTP 200 and "idempotentReplay": true instead of submitting again.

{
  "status": "completed",
  "idempotentReplay": true,
  "results": [ ... ]
}

A partial or failed submission is never replayed — call the endpoint again with the same body and it genuinely retries. Directories that already accepted the product report duplicate and are not charged, while the failed ones are attempted again.


GET /partner/v1/listings

Everything submitted with your key, newest first.

Query parameters

ParameterDefaultNotes
page1
limit20Max 100
statusOmit to get everything. Narrows to completed, partial or failed
curl "https://api.launchigniter.com/partner/v1/listings?limit=50" \
  -H "Authorization: Bearer $LAUNCHIGNITER_API_KEY"
{
  "submissions": [ { "status": "completed", "createdAt": "...", "listing": {}, "results": [] } ],
  "pagination": { "page": 1, "limit": 50, "total": 3, "totalPages": 1 }
}

Add status only when you want a subset - here, the submissions where every directory succeeded:

curl "https://api.launchigniter.com/partner/v1/listings?status=completed&limit=50" \
  -H "Authorization: Bearer $LAUNCHIGNITER_API_KEY"

?status=partial and ?status=failed narrow to the submissions that need attention, so an empty list from those is the healthy result, not a lost submission.

GET /partner/v1/listings/{website}

The most recent submission your key made for a site, in the same shape as the POST response. Submissions are addressed by the website they were submitted for — pass the domain, with or without a scheme or www..

curl https://api.launchigniter.com/partner/v1/listings/acme.ai \
  -H "Authorization: Bearer $LAUNCHIGNITER_API_KEY"

Returns 404 with {"error": "not_found"} if your key has not submitted that site.


Review and publication

  • LaunchIgniter — partner submissions publish immediately when your key has auto-approval enabled, which is the default. Otherwise they enter the normal moderation queue and go live once reviewed. GET /partner/v1/listings reflects the submission, not the moderation outcome. The product page links out dofollow.
  • StartupTrusted and SaaSGrow — listings are auto-approved and live right away. StartupTrusted links out dofollow on every listing; SaaSGrow listings are created badge-verified, which is what makes the backlink dofollow.

Please only submit real, working products. Keys that submit spam, dead links or duplicate domains get revoked.


Working example

A small Node script that checks quota, submits a batch and reports what landed where:

const API = 'https://api.launchigniter.com';
const KEY = process.env.LAUNCHIGNITER_API_KEY;

const call = async (path, options = {}) => {
  const res = await fetch(`${API}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${KEY}`,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });
  const body = await res.json();
  if (!res.ok && res.status !== 207) {
    throw new Error(`${res.status} ${body.error}: ${body.message ?? ''}`);
  }
  return body;
};

const me = await call('/partner/v1/me');
console.log('Quota:', me.directories);

for (const product of products) {
  const result = await call('/partner/v1/listings', {
    method: 'POST',
    body: JSON.stringify({
      name: product.name,
      tagline: product.tagline,
      description: product.description,
      websiteUrl: product.url,
      logoUrl: product.logo,
      screenshotUrls: product.screenshots,
      categories: [product.category],
      maker: { email: product.founderEmail, name: product.founderName },
    }),
  });

  for (const r of result.results) {
    console.log(`${product.name} -> ${r.directory}: ${r.status} ${r.listingUrl ?? r.error ?? ''}`);
  }
}

Support

Questions, a higher allowance, or a key rotation: email [email protected] with the masked key (lip_live_a1b2c3...) — never the full key.

Maulik Dhameliya