---
title: "Add a work experience to a person"
method: POST
path: "/api/v1/people/{id}/experiences"
tags: ["People"]
---

# Add a work experience to a person

`POST /api/v1/people/{id}/experiences`

## Request

- Base URL: `https://api.recruitwithatlas.com`
- URL: `https://api.recruitwithatlas.com/api/v1/people/{id}/experiences`
- Auth: HTTP bearer
- TypeScript: <https://skmtc.dev/recruitwithatlas/apis/atlas-api/docs/api/v1/people/:id/experiences/post.ts> (a function with typed inputs; its response is checked against the schema)

Use this endpoint to add a single work-experience entry to an existing person.

Provide the company name (and optionally its website domain and/or LinkedIn company id) — Atlas resolves or creates the matching Company and links it. A match on the exact domain or LinkedIn company id links to that Company even when the supplied name differs. A different subdomain of a domain an existing Company already holds (e.g. `jobs.acme.com` when the Company has `careers.acme.com`) links only when the names are similar, and a `companyLinkedinId` sent with it is not added to that Company. Otherwise the experience is stored without a Company link, or, when a `companyLinkedinId` no Company holds is also sent, linked to a new Company with only that LinkedIn id. Supplying `companyId` instead links the exact existing Company and skips matching entirely. Sending `companyId: null` stores the employment as text only — the `companyName` is kept and no Company is matched or created (`companyDomain` / `companyLinkedinId` are then rejected with 422). The role, start date, and (optionally) end date and description complete the entry.

Unlike the bulk experience data on `POST /api/v1/people` (which is created asynchronously), this endpoint creates the experience **synchronously** and returns it. Adding an experience recalculates the person's headline.

## Path parameters

- `id` string, uuid, required: Atlas person ID

## Request body

- object
  - `companyName` string, required: Company name
  - `companyId` string, uuid, nullable: Chooses how the experience is linked to a company; when present (id or null) it takes precedence over `companyName` matching. Omitted: the company is resolved from `companyName` (plus `companyDomain` / `companyLinkedinId`), and a new one is created when none matches. An Atlas company ID: links that exact existing company — no company is created and name/domain/LinkedIn matching is skipped; an ID outside your agency returns 422. `null`: no company link — on create the employment is stored as text only (the `companyName` is kept, no company is matched or created, and `companyDomain` / `companyLinkedinId` must be omitted, else 422); on update the current company is unlinked.
  - `companyLinkedinId` string, nullable: Company LinkedIn ID
  - `companyDomain` string, nullable: Company website domain (bare domain; full URLs are accepted and normalized to their hostname)
  - `role` string, required: Job title/role
  - `description` string, nullable: Role description
  - `startDate` string, required: Start date (YYYY-MM-DD)
  - `endDate` string, nullable: End date (YYYY-MM-DD, null = current)

## Response `201`

Experience created

- object
  - `status` 'ok', required
  - `data` object, required
    - `id` string, uuid, required
    - `companyName` string, required
    - `companyId` string, uuid, nullable, required
    - `companyLinkedinId` string, nullable, required
    - `companyDomain` string, nullable, required
    - `role` string, required
    - `description` string, nullable, required
    - `startDate` string, nullable, required
    - `endDate` string, nullable, required

## Other responses

- `401`: Unauthorized - missing or invalid API key
- `404`: Person not found
- `422`: Validation error - the request failed schema validation (`errors.fieldErrors`) or a business rule (`errors.formErrors`)
- `429`: Too many requests - the caller has exceeded the per-agency rate limit for the tier this endpoint counts against (default per minute: 1200 read / 400 write / 60 upload). Inspect the `RateLimit-*` headers — returned on every response, not only on 429s — and back off until the window resets. See the "Rate limits" section of the introduction for details.
- `500`: Internal server error

## Changes

- **2026-10-03** `cd4bc8bbd95e`: 1 info
  - added the optional property `error` to the response with the `422` status

[Operation history](https://skmtc.dev/recruitwithatlas/apis/atlas-api/changes/api/v1/people/:id/experiences/post.md)

---

[API](https://skmtc.dev/recruitwithatlas/apis/atlas-api.md) - [All operations](https://skmtc.dev/recruitwithatlas/apis/atlas-api/llms.txt) - [OpenAPI document](https://skmtc.dev/recruitwithatlas/apis/atlas-api/revisions/158ee454751c?raw)
