NewSee how
FirstSales
Home/Tutorials/Manage Contacts with the FirstSales CLI
Developer & CLI

Manage Contacts with the FirstSales CLI

CRUD contacts, lists, and tags from the command line — idempotent creates, bulk imports, exports, and deliberate deletes scoped to an org and workspace.

8 min read·Advanced·7 steps
  1. 1

    List and read contacts

    Everything is scoped to an org and workspace. Start read-only — list contacts, then fetch one by ID:

    firstsales contacts list --org ORG_ID --workspace WS_ID --json
    firstsales contacts get --org ORG_ID --workspace WS_ID --contact CONTACT_ID
  2. 2

    Create and update a contact

    Create with an idempotency key so retries don't duplicate; update patches only the fields you send:

    firstsales contacts create --org ORG_ID --workspace WS_ID \
      --data '{"email":"jane@acme.com","first_name":"Jane","company_name":"Acme"}' \
      --idempotency-key jane-acme-2026-01
    
    firstsales contacts update --org ORG_ID --workspace WS_ID \
      --contact CONTACT_ID --data '{"job_title":"VP Sales"}'
  3. 3

    Organize with lists

    Contact lists are how you segment who a campaign sends to. Create, rename, and delete lists from the CLI:

    firstsales contact-lists list --org ORG_ID --workspace WS_ID
    firstsales contact-lists create --org ORG_ID --workspace WS_ID \
      --data '{"name":"Q1 SaaS founders"}'
    firstsales contact-lists update --org ORG_ID --workspace WS_ID \
      --list LIST_ID --data '{"name":"Q1 SaaS founders (US)"}'
  4. 4

    Manage tags in bulk

    Tags are free-form labels across contacts. You can rename (which merges) or delete a tag everywhere it appears — deletion is destructive, so it needs --confirm:

    firstsales contact-tags list --org ORG_ID --workspace WS_ID
    firstsales contact-tags rename --org ORG_ID --workspace WS_ID \
      --data '{"from":"founder","to":"founders"}'
    firstsales contact-tags delete --org ORG_ID --workspace WS_ID \
      --data '{"tag":"stale"}' --confirm
  5. 5

    Bulk import

    Push a batch of contacts with an import job. Point it at a list; the platform de-duplicates by email server-side, so re-importing the same people won't create copies:

    firstsales contact-imports create --org ORG_ID --workspace WS_ID \
      --data-file ./leads.json \
      --idempotency-key import-2026-01
  6. 6

    Export what you filtered

    List your export jobs / pull contacts back out as CSV for reporting or backup:

    firstsales contact-exports list --org ORG_ID --workspace WS_ID
  7. 7

    Delete deliberately

    Removing a contact is destructive and requires --confirm. Prefer letting cleaning auto-suppress bad addresses over hard-deleting — deletion is permanent:

    firstsales contacts delete --org ORG_ID --workspace WS_ID \
      --contact CONTACT_ID --confirm

Pro tips

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

1

Segment with lists, label with tags

Lists decide who a campaign sends to; tags are cross-cutting labels for filtering. Use both — a contact can sit in one list and carry many tags.

2

Import is idempotent and de-duped

Server-side dedup by email means a re-run of an import won't double your list. Still pass --idempotency-key so the job itself isn't created twice.

3

Don't hard-delete to suppress

To stop emailing someone, let cleaning mark them dirty or rely on bounced/unsubscribed status — those auto-exclude. Reserve contacts delete --confirm for genuine removal.

4

rename merges tags

Renaming a tag to an existing name merges them. Handy for cleaning up 'founder' vs 'founders' — but it's not reversible, so check the target name first.

Frequently asked questions

How are contacts scoped?

To an organization and workspace. Every contact command takes --org and --workspace; the same contact IDs won't resolve in a different workspace.

How do I avoid duplicate contacts on import?

Imports de-duplicate by email server-side, so re-importing the same people adds them to the list without creating copies. Pass --idempotency-key so the import job itself is also safe to retry.

What's the difference between lists and tags?

Lists define the audience a campaign sends to; tags are free-form labels for filtering and segmentation. A contact belongs to lists and can carry many tags.

How do I remove a tag everywhere?

contact-tags delete --confirm removes it from all contacts, and contact-tags rename merges one tag into another. Both are destructive, so delete requires --confirm.

Can I export my contacts?

Yes — use contact-exports to pull contacts back out as CSV. In the app, export reflects your current filter/selection; via the API you work with export jobs.

Should I delete contacts that bounce?

Usually no. Bounced, unsubscribed, and cleaning-flagged (dirty) contacts are auto-excluded from sends, so deletion is rarely needed. Hard-delete only when you truly want the record gone, and it requires --confirm.

Ready to put this into practice?

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

Start for $1