# OpenAPI, Postman and Insomnia > The LaunchList API publishes a machine-readable OpenAPI 3.1 document. Import the URL into Postman, Insomnia, Bruno or a code generator and you have every endpoint, ready to call. Source: https://getlaunchlist.com/help/docs/api/openapi --- The whole API is published as an **OpenAPI 3.1** document at this URL: ```text https://api.getlaunchlist.com/v1/openapi.json ``` It needs no API key. Point a tool at it and you get every endpoint, every parameter, every response shape and the scope each call requires. ## Postman 1. **Import → Link**, and paste the URL above. 2. Postman builds a collection from the document. Open its **Authorization** tab, choose **Bearer Token**, and paste your key. 3. Send a first request to prove the key works. `GET /v1/workspace` is the friendliest one, since it touches no data and reports the plan, the scopes and the rate limit. It needs the `projects:read` scope, so if your key is capture-only it will answer `403`. That still means the key is good, just not for that call: send something the key is scoped for instead. Re-import the same link whenever you want the latest endpoints. Postman offers to replace the existing collection rather than duplicating it. > [!TIP] Keep the key in an environment variable > Set a Postman environment variable such as `launchlist_key` and use `{{launchlist_key}}` as the > bearer token. That way a shared collection never carries a live secret. ## Insomnia, Bruno, Hoppscotch All three import an OpenAPI URL directly, and all three read the same document: - **Insomnia**: Create → Import From → URL - **Bruno**: Import Collection → OpenAPI V3 - **Hoppscotch**: Collections → Import → OpenAPI ## Generating a client Any generator that reads OpenAPI 3.1 works. For example, with [openapi-generator](https://openapi-generator.tech): ```bash openapi-generator generate \ -i https://api.getlaunchlist.com/v1/openapi.json \ -g typescript-fetch \ -o ./launchlist-client ``` Every operation carries a stable `operationId`, such as `createContact`, `listInvitations` or `redeemInvitation`, and those are what your generated method names come from. We treat them as part of the contract, so regenerating will not silently rename your calls. ## What the document tells you that a guide does not Each operation carries an `x-required-scope` extension naming the exact scope it enforces: ```json "post": { "operationId": "createContact", "x-required-scope": "contacts:write" } ``` That is read straight from the route's own middleware, and a test fails our build if the two ever disagree. So it is the reliable answer to "which scope does this key need", rather than a table somebody remembered to update. ## Which server it points at The `servers` entry is rewritten to whatever host served the document. Import from `api.getlaunchlist.com` and your collection calls production. If you are running LaunchList somewhere else, import from that host and the collection follows it, instead of quietly calling production with your live key. ## Testing without touching your audience Use a **test key**. In **Embed & API → Developers → API keys**, press **New API key** and choose **Test** under **Mode**. A test key starts `llk_test_` (a live key starts `llk_live_`), and its mode can never change. A test key works on test data only. It does not need the project's test mode to be on: - **Every contact it creates is a test contact.** It runs through the same signup pipeline as a live key and comes back with `"livemode": false`. The same email can be a test contact and a real contact at once; they never merge. - **Every read returns test data only.** Listing, counting, retrieving, segment counts, tag counts and the events feed see test contacts and nothing else. A real contact's id answers `404`, so a test key can never read, change or delete one. - **A live key never sees test data**, so whatever a test run leaves behind stays out of your real integration too. - **Setup reads as it is.** Projects, forms, stages, tags, segments and automations come back the same as for a live key, so a test run uses your real form and stage names. - **Some things answer `403 test_mode_unsupported`** because they would reach your real project or real signups: every broadcast and import endpoint, creating a tag or a segment, a code anyone can use, exchanging an invite handoff, and redeeming an invitation that was not issued to a test contact. Personal invitations for test contacts work end to end. - **What happens after a signup is what test mode does.** Verification emails for test contacts go to the workspace owner. An invitation email, and the welcome email when it is switched on, go to the test contact's own address with `[Test]` in the subject, so use an address you own. Webhooks fire, marked `is_test`. Test contacts are never enrolled in automations, sit on a separate test leaderboard, never credit a real referrer, and never count toward your plan. - **A project keeps at most 100 test contacts.** Past that, creating a new one answers `403 test_audience_full` until you clear some. Every response to a test key carries `LaunchList-Mode: test`, and `GET /v1/workspace` reports `api_key.mode`, so a test suite can check it is not pointed at live data before it writes anything. Test contacts stay out of every normal view in the dashboard. They appear in **Signups** under the **Test** segment, and **Clear test data** in the project's test mode setting removes them along with their submissions, events and referrals. Deleting a test contact through the API removes it the same way. Two more habits are worth having: - **Use a scratch project for anything a test key cannot do.** A key can be pinned to a single project when you create it, and a pinned key cannot see or touch anything else in the workspace. - **Send `Idempotency-Key` on writes.** Retrying a request that carries the same key returns the original response rather than doing the work twice. See [Idempotency](/help/docs/api/idempotency). ## Common questions ### Does LaunchList have a Postman collection? Yes, in the form Postman prefers. Import https://api.getlaunchlist.com/v1/openapi.json and Postman builds the collection itself, with every endpoint, parameter and example filled in. Re-import to pick up new endpoints. ### Where is the LaunchList OpenAPI spec? At https://api.getlaunchlist.com/v1/openapi.json. It needs no API key, and a test checks it against the API's own routes on every build, so it cannot describe an endpoint that does not exist or miss one that does. ### Can I generate a client library from the LaunchList API? Yes. The document is OpenAPI 3.1, so any generator that reads 3.1 will produce a typed client. Every operation carries a stable operationId, which is what the generated method names come from.