---
title: "Upload attachment"
method: POST
path: "/attachments"
tags: ["Attachments"]
---

# Upload attachment

`POST /attachments`

## Request

- Base URL: `https://api.100hires.com/v2`
- URL: `https://api.100hires.com/v2/attachments`
- Auth: HTTP bearer

Uploads a file and creates an attachment in the authenticated company.

Supported categories. The attachment is stored under `company_id` (if provided — must be accessible by the API key) or the authenticated company by default. The referenced `object_id` must belong to that same company (strict `company_id` match, no cross-company uploads).
- `voicemail` — audio file (wav/mp3, ≤20 MB). No `object_id` required. Returned `uuid` can be referenced as `attachment_uuid` in nurture-campaign voicemail steps.
- `candidate` — generic candidate file. `object_id` = candidate ID.
- `application` — application attachment (signed docs, offer letters, etc.). `object_id` = application ID.
- `candidate_comment` — attachment for a candidate comment. `object_id` = comment ID.
- `job_note` — attachment for a job note. `object_id` = job note ID.
- `company_favicon`, `company_header`, `company_link_preview` — company branding assets. `object_id` = company ID (must match the authenticated company or a client company the API key can access).

Returns `ApiAttachment`. Follow `url` with the same Bearer token to download the file later.

## Request body

- UploadApiAttachmentRequest
  - `category` 'voicemail' | 'candidate' | 'application' | 'candidate_comment' | 'job_note' | 'company_favicon' | 'company_header' | 'company_link_preview', required: Attachment category. Determines file-type validation rules and `object_id` requirements.
  - `company_id` integer, nullable: Target company ID. Required only for partner API keys that manage multiple client companies — pick the company the attachment belongs to. If omitted, defaults to the authenticated company. The attachment is stored under this company, and the referenced `object_id` (when present) MUST belong to this same company — mismatch returns 404.
  - `object_id` integer, nullable: Target object ID. Required for every category except `voicemail`. Resolves to candidate/application/comment/job-note/company per category. The object's company is strictly matched against `company_id` (or authenticated company when `company_id` omitted); no cross-company uploads.
  - `file` FileData, required
    - `data` string, required: Base64 content
    - `file_name` string, required: Original file name.
    - `mime_type` string, required: MIME type (e.g. application/pdf).
    - `size` integer: Optional for uploads, returned in responses

## Response `200`

Uploaded attachment

- ApiAttachment: Unified attachment shape returned by apiV2 endpoints (resumes, candidate files, application attachments, message attachments, call recordings, voicemail audio in nurture campaigns). `url` is an absolute URL served by the API host (`https://api.100hires.com/v2/attachments/{category}/{uuid}/{file_name}`) and serves the raw file bytes with `Authorization: Bearer <API_KEY>`. The response on `url` sets `Content-Disposition: attachment; filename="..."` with the human-readable filename. Use `uuid` to reference the attachment in other endpoints (e.g. nurture voicemail step).
  - `uuid` string, uuid, required: Unique attachment identifier. Stable across API calls; use in referencing endpoints.
  - `url` string, uri, nullable, required: Absolute download URL (e.g. `https://api.100hires.com/v2/attachments/application/{uuid}/{file_name}`). Hit with `Authorization: Bearer <API_KEY>`.
  - `relative_time` string, required: Human-readable time since upload (e.g. `"2 days ago"`).
  - `file` AttachmentFile, required
    - `is_image` boolean, nullable, required: Whether the file is an image.
    - `orig_file_name` string, required: Original file name.
    - `file_ext` string, required: File extension.
    - `file_type` string, required: File type category.
    - `readable_size` string, required: Human-readable file size.

## Other responses

- `400`: Validation error
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `415`: Content-Type must be application/json
- `429`: Too many requests

---

[API](https://skmtc.dev/100hires/apis/100hires-api.md) · [All operations](https://skmtc.dev/100hires/apis/100hires-api/llms.txt) · [OpenAPI document](https://skmtc.dev/100hires/apis/100hires-api/revisions/e63e2d3115f7?raw)
