---
title: "Using FirstSales with Codex | FirstSales"
description: "Connect Codex to FirstSales over the REST API (or CLI in a shell) — first whoami call, scoped keys, idempotent writes, and stopping on unsupported operations."
canonical: "https://firstsales.io/tutorial/firstsales-with-codex/"
---

[Home](/)/[Tutorials](/tutorial/)/Using FirstSales with Codex

Developer & CLI

# Using FirstSales with Codex

Connect Codex to FirstSales over the REST API (or CLI in a shell) — first whoami call, scoped keys, idempotent writes, and stopping on unsupported operations.

8 min read·Advanced·6 steps

1. 1  
## Pick the right path for your Codex setup  
FirstSales offers two integration paths. If your Codex environment has a **shell with npm**, install the `@firstsales.io/cli` and drive it like any shell agent — it handles auth, JSON, and idempotency for you. If Codex runs **without shell access** (browser or sandboxed), call the **Developer API** directly over HTTPS. The docs group Codex with API-first agents for exactly this reason.
2. 2  
## Store the key as an environment secret  
Create a Developer API key in **Settings → API** and put it in your Codex environment's secret store as `FIRSTSALES_API_KEY`. Never paste the raw key into a prompt or commit it — reference the env var in code.  
```  
# in your Codex task's environment  
FIRSTSALES_API_KEY=fs-key-...  
FIRSTSALES_BASE_URL=https://api.app.firstsales.io  
```
3. 3  
## Verify identity first  
Whichever path, the first call confirms the key resolves to the org and workspace you expect:  
```  
curl https://api.app.firstsales.io/api/v1/whoami \  
  -H "Authorization: Bearer $FIRSTSALES_API_KEY"  
```
4. 4  
## Read state before writing  
Have Codex inspect before it mutates. Resources are scoped to org and workspace:  
```  
curl https://api.app.firstsales.io/api/v1/organizations/ORG_ID/workspaces/WS_ID/campaigns \  
  -H "Authorization: Bearer $FIRSTSALES_API_KEY"  
curl https://api.app.firstsales.io/api/v1/organizations/ORG_ID/workspaces/WS_ID/contacts \  
  -H "Authorization: Bearer $FIRSTSALES_API_KEY"  
```
5. 5  
## Write idempotently  
On creates, send an `Idempotency-Key` header so a retried request never duplicates data — important for an autonomous agent that may retry on timeout:  
```  
curl -X POST \  
  https://api.app.firstsales.io/api/v1/organizations/ORG_ID/workspaces/WS_ID/contacts \  
  -H "Authorization: Bearer $FIRSTSALES_API_KEY" \  
  -H "Content-Type: application/json" \  
  -H "Idempotency-Key: codex-lead-2026-01" \  
  -d '{"email":"lead@acme.com","first_name":"Sam"}'  
```
6. 6  
## Keep Codex on the public surface  
Instruct Codex to use only public `/api/v1` endpoints. On an `unsupported_operation` response it must stop and report — never scrape the app or call private routes, provider callbacks, tracking pixels, unsubscribe handlers, or cron endpoints to force a result. Handle `401` (bad key), `422` (validation — body names the field), and `429` (back off) explicitly.

## Pro tips

Hard-won shortcuts that keep warm-up on track.

1

### Shell available? Prefer the CLI

If your Codex sandbox can run npm, the CLI removes a lot of boilerplate — auth, JSON, idempotency, and delete-confirmation are handled for you. Fall back to raw HTTP only when there's no shell.

2

### Key lives in the environment, not the prompt

Put FIRSTSALES\_API\_KEY in Codex's secret store and reference it. A key in the prompt ends up in logs and history.

3

### whoami is the cheapest safety check

One call confirms Codex is pointed at the right org and workspace before it writes anything. Skipping it is how data lands in the wrong workspace.

4

### Idempotency-Key on every create

Autonomous agents retry. A stable idempotency key turns a retried POST into a no-op instead of a duplicate contact or double charge.

## Frequently asked questions

Should Codex use the CLI or the API?

If Codex has shell access with npm, use the **CLI**. If it runs in a browser or a shell-less sandbox, call the **Developer API** over HTTPS. The API path is the default for browser-based agents.

How do I give Codex the key safely?

Store it as `FIRSTSALES_API_KEY` in Codex's environment/secret store and reference the variable in code. Don't paste the raw key into prompts or commit it.

What's the base URL and first call?

Base `https://api.app.firstsales.io`, Bearer auth. First call `GET /api/v1/whoami` to confirm org and workspace context before any writes.

How do I prevent duplicate writes on retries?

Send an `Idempotency-Key` header on create requests. A replay with the same key returns the original result instead of creating a second record.

What must Codex never do?

Never call app-private routes, provider callbacks, tracking pixels, unsubscribe handlers, or internal cron endpoints, and never scrape the app UI. Stay on public `/api/v1`; stop and report on `unsupported_operation`.

## Ready to put this into practice?

Start your FirstSales trial and launch a warmed, authenticated mailbox in minutes.

[Start for $1](https://app.firstsales.io)

[All tutorials](/tutorial/)