# Launch

URL: https://submitator.com/docs/api/launch

> Preview, launch and follow the listings.

Preview, launch and follow the listings. `GET /projects/{project_id}/readiness` is free and shows what a launch would do; `POST /projects/{project_id}/launch` uses 1 launch and creates up to 100 listings, one per directory.

A listing moves `pending` → `in_progress` → `submitted` → `live`, or ends `not_accepted` or `cancelled`. When it waits on you or your client it shows `action_required` with an `action` to take. Listing times are rounded down to the hour.

## Preview a launch

`GET https://api.submitator.com/v1/projects/{project_id}/readiness`

Shows for free what a launch would do now: whether the project is ready, how many directories it would get, and what would unlock more. On a launched project it previews what `POST /projects/{project_id}/listings` would add from the free allowance. The numbers follow the catalog and can change from one hour to the next.

| Parameter | In | Required | What it is |
| --- | --- | --- | --- |
| `project_id` | path | Yes | The project's id. |

Response 200:

```json
{
  "object": "readiness",
  "livemode": false,
  "project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
  "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."
    },
    {
      "requirement": "competitors",
      "directories": 3,
      "how": "Add at least 1 competitor in competitors."
    },
    {
      "requirement": "promo_code",
      "directories": 1,
      "how": "Add a promo code in promo_code."
    }
  ],
  "not_matching": {
    "b2b_only": 4,
    "ai_only": 7,
    "directories_only": 2,
    "other": 0
  },
  "cost": {
    "launches": 1,
    "available": 100
  }
}
```

Typical errors: [`not_found`](https://submitator.com/docs/errors#not_found), [`rate_limited`](https://submitator.com/docs/errors#rate_limited).

## Launch a project

`POST https://api.submitator.com/v1/projects/{project_id}/launch`

Uses 1 launch and creates a listing in `pending` for each directory picked, up to 100. Send `"auto"` to take the best directories the project qualifies for, `include` to name them, or `exclude` to leave some out. A failed call spends nothing, and a second launch of the same project returns 409 `already_launched`. Listings beyond your capacity of 100 in progress wait in `pending` and start as others finish.

| Parameter | In | Required | What it is |
| --- | --- | --- | --- |
| `project_id` | path | Yes | The project's id. |
| `Idempotency-Key` | header | No | A 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. |

| Body field | Type | Required | What it is |
| --- | --- | --- | --- |
| `directories` | object | No | Which directories to launch with. Defaults to `auto`. |
| `auto_replace` | boolean | No | Sets the project's `auto_replace`. Leave it out to keep the project's value, except that a launch with `include` sets it to `false`. |

Request:

```json
{
  "directories": "auto"
}
```

Response 202:

```json
{
  "object": "project",
  "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
  "livemode": false,
  "status": "in_progress",
  "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": {
    "total": 100,
    "used": 0,
    "reserved": 87,
    "available": 13
  },
  "progress": {
    "total": 87,
    "pending": 87,
    "in_progress": 0,
    "action_required": 0,
    "submitted": 0,
    "live": 0,
    "not_accepted": 0,
    "cancelled": 0
  },
  "external_id": "crm_8812",
  "metadata": {
    "account_owner": "Priya",
    "crm_stage": "onboarding"
  },
  "created_at": "2026-10-03T13:58:12Z",
  "updated_at": "2026-10-03T14:05:40Z",
  "launched_at": "2026-10-03T14:05:40Z"
}
```

Typical errors: [`not_ready`](https://submitator.com/docs/errors#not_ready), [`no_launches_left`](https://submitator.com/docs/errors#no_launches_left), [`already_launched`](https://submitator.com/docs/errors#already_launched), [`nothing_to_submit`](https://submitator.com/docs/errors#nothing_to_submit).

## List a project's listings

`GET https://api.submitator.com/v1/projects/{project_id}/listings`

Returns one listing per directory, highest Domain Rating first. Filter by `status` or `directory`. Listing times are rounded down to the hour.

| Parameter | In | Required | What it is |
| --- | --- | --- | --- |
| `project_id` | path | Yes | The project's id. |
| `status` | query | No | Only listings in this status. |
| `directory` | query | No | Only the listing at this directory. |
| `cursor` | query | No | `next_cursor` from the previous page of the same list, as you received it. Leave it out for the first page. |
| `limit` | query | No | How many items to return, 1 to 100. Defaults to 20. |

Response 200:

```json
{
  "object": "list",
  "data": [
    {
      "object": "listing",
      "id": "lst_7Hk2Qn4Rt9Vx1Bm6Cz3LdK",
      "livemode": false,
      "project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
      "directory": {
        "id": "dir_2Lm8Wq3Zk7Rt1Xc5Vb9NdF",
        "name": "BetaList",
        "domain_rating": 73,
        "logo_url": "https://feed.example.net/a/x1Lq7Rt.k9Zm"
      },
      "status": "live",
      "reason": null,
      "action": null,
      "live_url": "https://betalist.com/startups/ledgerly",
      "proof_url": "https://feed.example.net/a/Pf8Kq2Wm.t6Lx9",
      "created_at": "2026-10-03T14:00:00Z",
      "submitted_at": "2026-10-04T09:00:00Z",
      "live_at": "2026-10-08T14:00:00Z"
    }
  ],
  "has_more": true,
  "next_cursor": "cur_8Tq2Xn5Wb1Lz7Pd3"
}
```

Typical errors: [`not_found`](https://submitator.com/docs/errors#not_found), [`validation_failed`](https://submitator.com/docs/errors#validation_failed), [`invalid_cursor`](https://submitator.com/docs/errors#invalid_cursor).

## Add directories

`POST https://api.submitator.com/v1/projects/{project_id}/listings`

Adds directories to a launched project from its free allowance, the part that listings neither use nor reserve. A directory that already has a listing on the project cannot be added again. With `auto_replace` on, this happens for you whenever allowance frees up or a fitting directory joins the catalog.

| Parameter | In | Required | What it is |
| --- | --- | --- | --- |
| `project_id` | path | Yes | The project's id. |
| `Idempotency-Key` | header | No | A 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. |

| Body field | Type | Required | What it is |
| --- | --- | --- | --- |
| `directories` | object | No | Which directories to add, up to the free allowance. Defaults to `auto`. |

Request:

```json
{
  "directories": "auto"
}
```

Response 202:

```json
{
  "object": "project",
  "id": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
  "livemode": false,
  "status": "in_progress",
  "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": "installed",
    "checked_at": "2026-10-04T09:58:03Z"
  },
  "auto_replace": true,
  "excluded_directories": [],
  "allowance": {
    "total": 100,
    "used": 53,
    "reserved": 39,
    "available": 8
  },
  "progress": {
    "total": 96,
    "pending": 9,
    "in_progress": 30,
    "action_required": 0,
    "submitted": 31,
    "live": 22,
    "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-04T10:02:15Z",
  "launched_at": "2026-10-03T14:05:40Z"
}
```

Typical errors: [`allowance_exhausted`](https://submitator.com/docs/errors#allowance_exhausted), [`nothing_to_submit`](https://submitator.com/docs/errors#nothing_to_submit), [`invalid_directories`](https://submitator.com/docs/errors#invalid_directories).

## Read a listing

`GET https://api.submitator.com/v1/listings/{listing_id}`

Returns one listing with its directory, its status and, once live, its URL. A listing keeps its id for the life of the project, including after a correction.

| Parameter | In | Required | What it is |
| --- | --- | --- | --- |
| `listing_id` | path | Yes | The listing's id. |

Response 200:

```json
{
  "object": "listing",
  "id": "lst_7Hk2Qn4Rt9Vx1Bm6Cz3LdK",
  "livemode": false,
  "project": "prj_4QzX1m9Lr2Vb7Nc8Tk3HwP",
  "directory": {
    "id": "dir_2Lm8Wq3Zk7Rt1Xc5Vb9NdF",
    "name": "BetaList",
    "domain_rating": 73,
    "logo_url": "https://feed.example.net/a/x1Lq7Rt.k9Zm"
  },
  "status": "live",
  "reason": null,
  "action": null,
  "live_url": "https://betalist.com/startups/ledgerly",
  "proof_url": "https://feed.example.net/a/Pf8Kq2Wm.t6Lx9",
  "created_at": "2026-10-03T14:00:00Z",
  "submitted_at": "2026-10-04T09:00:00Z",
  "live_at": "2026-10-08T14:00:00Z"
}
```

Typical errors: [`not_found`](https://submitator.com/docs/errors#not_found), [`rate_limited`](https://submitator.com/docs/errors#rate_limited).
