NewSee how
FirstSales
Home/Tutorials/FirstSales API Quickstart
Developer & CLI

FirstSales API Quickstart

Generate an API key and make your first calls — create contacts, enroll them in campaigns, and pull replies from the inbox over the REST API.

9 min read·Advanced·7 steps
  1. 1

    Generate a Developer API key

    In the app go to Settings → API and create a Developer API key. Set its scopes and access level (read vs read-write) to the minimum the integration needs. The secret is shown once — copy it into a secret manager immediately; the app only stores a redacted form.

    Revoke and regenerate on the same page if a key ever leaks.

  2. 2

    Verify identity with whoami

    The base URL is https://api.app.firstsales.io. Auth is a Bearer token. Always start by confirming the key resolves to the org and workspace you expect — GET /api/v1/whoami:

    curl https://api.app.firstsales.io/api/v1/whoami \
      -H "Authorization: Bearer $FIRSTSALES_API_KEY"
  3. 3

    Find your org and workspace IDs

    Every resource is scoped to an organization and a workspace, so most paths look like /api/v1/organizations/{orgId}/workspaces/{workspaceId}/…. List them:

    # Organizations you can access
    curl https://api.app.firstsales.io/api/v1/organizations \
      -H "Authorization: Bearer $FIRSTSALES_API_KEY"
    
    # Workspaces inside an org
    curl https://api.app.firstsales.io/api/v1/organizations/ORG_ID/workspaces \
      -H "Authorization: Bearer $FIRSTSALES_API_KEY"
  4. 4

    Create a contact (idempotently)

    POST a contact into a workspace. Pass an Idempotency-Key header so a retried request never creates a duplicate — safe to replay on network failure.

    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: jane-acme-2026-01" \
      -d '{ "email": "jane@acme.com", "first_name": "Jane", "company_name": "Acme" }'
  5. 5

    Read campaign analytics

    Pull funnel and engagement metrics for a campaign to sync results into your own reporting — no scraping the dashboard:

    curl https://api.app.firstsales.io/api/v1/organizations/ORG_ID/workspaces/WS_ID/campaigns/CAMPAIGN_ID/analytics \
      -H "Authorization: Bearer $FIRSTSALES_API_KEY"
  6. 6

    Read replies from the inbox

    List inbox threads to pull sends, opens, replies, and bounces into your systems. Thread bodies are redacted in the list view; fetch a single thread for detail. This is how you route positive replies into a CRM while native connectors are still coming.

    curl https://api.app.firstsales.io/api/v1/organizations/ORG_ID/workspaces/WS_ID/inbox/threads \
      -H "Authorization: Bearer $FIRSTSALES_API_KEY"
  7. 7

    Stay inside the public surface

    The API only exposes the public /api/v1 surface. Don't call app-private routes, provider callbacks, tracking pixels, unsubscribe handlers, or internal cron routes — they aren't part of the contract and will break. If a call returns unsupported_operation, stop and treat it as "not available via the API," not something to work around.

    Standard status codes apply: 401 bad/revoked key, 422 validation (body names the field), 429 rate-limited (back off and retry).

Pro tips

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

1

whoami before you write

Confirm the key resolves to the org/workspace you intend before any mutating call. A key scoped to the wrong workspace is the most common way to write data into the wrong place.

2

Always send an Idempotency-Key on creates

Network retries happen. An Idempotency-Key makes a replayed POST a no-op instead of a duplicate contact or double charge.

3

Store the key once, never print it

The secret is shown a single time and stored redacted. Put it straight into a secret manager; never log it, commit it, or ship it in a client bundle.

4

Treat unsupported_operation as a hard stop

If the API returns unsupported_operation, the thing you want isn't in the public contract. Don't reach for app-private routes to force it — report the limitation.

Frequently asked questions

Where do I get an API key?

Settings → API. Create a Developer API key with the scopes and access level you need; it's shown once, so copy it immediately. Revoke and regenerate on the same page if it's exposed.

What's the base URL and auth?

Base URL https://api.app.firstsales.io; authenticate with Authorization: Bearer $FIRSTSALES_API_KEY and send JSON. Start with GET /api/v1/whoami to confirm context.

Why are the paths so long?

Resources are scoped to an org and workspace, so paths are /api/v1/organizations/{orgId}/workspaces/{workspaceId}/…. Get the IDs from /api/v1/organizations and its /workspaces sub-resource (or from whoami).

How do I avoid duplicate writes?

Send an Idempotency-Key header on create requests. A retried request with the same key returns the original result instead of creating a second record — safe to replay after a timeout.

Can I read campaign metrics and replies?

Yes — GET …/campaigns/{id}/analytics for funnel/engagement, and GET …/inbox/threads for conversation activity. Thread bodies are redacted in the list; fetch a single thread for full detail.

Is there a Zapier or CRM integration instead?

No Zapier connector, and native CRM connectors (Salesforce, HubSpot, Pipedrive) are still coming. Until they ship, the REST API — or the CLI — is the supported way to integrate and sync.

What does unsupported_operation mean?

The requested action isn't part of the public /api/v1 contract. Stop and report it — don't call app-private routes, callbacks, pixels, or internal endpoints to work around it; those aren't supported and will break.

Ready to put this into practice?

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

Start for $1