Introduction
Welcome to the Polymer API documentation.
Polymer provides two APIs:
- Public API - Unauthenticated access to job listings for job board integrations
- Customer API - Authenticated access to your organization's hiring data for ATS integrations
Public API
The Public API provides unauthenticated access to job listings. These endpoints are rate-limited and intended for job board integrations.
Base URL: https://api.polymer.co/v1/hire
Get All Jobs
curl -H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/organizations/aperturelabs/jobs
The above command returns JSON structured like this:
{
"items": [
{
"city": "Charlotte",
"country": "US",
"created_at": "2020-09-13T14:31:31.364Z",
"created_at_timestamp": 1600007491,
"display_location": "Charlotte, NC",
"hash_id": "wUShs3ITY0br",
"id": 15394,
"job_category_name": "Design & User Experience",
"job_id": 15394,
"job_post_url": "https://jobs.polymer.co/aperturelabs/15394",
"kind_pretty": "Full-time",
"organization_name": "Aperture Labs",
"published_at": "2020-09-13T14:33:11.225Z",
"published_at_timestamp": 1600007591,
"remote_restriction_city": null,
"remote_restriction_city_google_place_id": null,
"remote_restriction_country_list": ["CA", "US"],
"remote_restriction_country_residency_is_required": false,
"remote_restriction_overlap_hours": 4,
"remote_restriction_overlap_hours_is_required": false,
"remote_restriction_timezone_utc_offset_seconds": null,
"remoteness_pretty": "Remote",
"state_region": "NC",
"title": "Senior Web Designer"
}
],
"meta": {
"count": 3,
"is_first": true,
"is_last": true,
"organization_name": "Aperture Labs",
"page": 1,
"total": 1
}
}
This endpoint retrieves all Jobs for an Organization.
HTTP Request
GET https://api.polymer.co/v1/hire/organizations/<organization_slug>/jobs
URL Parameters
| Parameter | Description |
|---|---|
| organization_slug | The url name of the Organization, example Aperture Labs is aperturelabs |
Get a Specific Job
curl -H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/organizations/aperturelabs/jobs/15397
The above command returns JSON structured like this:
{
"city": "Charlotte",
"closed_at": null,
"country": "US",
"created_at": "2020-09-13T14:32:01.757Z",
"created_at_timestamp": 1600007521,
"department": "Design",
"description": "Exposing new ways to evolve our design language...",
"display_location": "Charlotte, NC",
"hash_id": "FOHTgVyktkFK",
"id": 15397,
"job_application_description_url": "https://jobs.polymer.co/aperturelabs/15397",
"job_category_name": "Design & User Experience",
"job_id": 15397,
"job_post_url": "https://jobs.polymer.co/aperturelabs/15397",
"kind": "full_time",
"kind_pretty": "Full-time",
"organization_name": "Aperture Labs",
"published_at": "2020-09-13T14:32:54.747Z",
"published_at_pretty": "Sep 13th, 2020",
"published_at_timestamp": 1600007574,
"questions": [],
"remote_restriction_city": null,
"remote_restriction_city_google_place_id": null,
"remote_restriction_country_list": [],
"remote_restriction_country_residency_is_required": false,
"remote_restriction_overlap_hours": null,
"remote_restriction_overlap_hours_is_required": false,
"remote_restriction_timezone_utc_offset_seconds": null,
"remoteness_pretty": "No remote",
"settings": {
"cover_letter": "required",
"email": "required",
"first_name": "required",
"last_name": "required",
"linkedin_url": "optional",
"location": "optional",
"phone": "optional",
"resume": "optional",
"social_share_image_type": "default",
"website_url": "optional"
},
"state_region": "NC",
"title": "Senior Product Designer"
}
This endpoint retrieves a specific Job.
HTTP Request
GET https://api.polymer.co/v1/hire/organizations/<organization_slug>/jobs/<job_id>
URL Parameters
| Parameter | Description |
|---|---|
| organization_slug | The name of the Organization formatted for the job board URL, example Aperture Labs is aperturelabs |
| job_id | The numeric ID of the Job to retrieve |
Customer API
The Customer API provides authenticated access to your organization's hiring data including jobs, candidates, and applications. This API is intended for ATS integrations and internal tooling.
Base URL: https://api.polymer.co/v1/hire
Authentication
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/organization
The Customer API uses Bearer token authentication. Include your API key in the Authorization header with all requests.
Authorization: Bearer YOUR_API_KEY
Replace YOUR_API_KEY in the examples with your actual API key.
Pagination
All list endpoints return paginated results. Use the page and per_page query parameters to navigate through results.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.polymer.co/v1/hire/jobs?page=2&per_page=25"
Paginated response structure:
{
"items": [...],
"meta": {
"total_pages": 4,
"is_last": false,
"is_first": false,
"page": 2,
"next_page": 3,
"total_items": 167
}
}
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | The page number to return |
| per_page | integer | 50 | Number of items per page |
Meta Object
| Field | Type | Description |
|---|---|---|
| total_pages | integer | Total number of pages available |
| is_first | boolean | Whether this is the first page |
| is_last | boolean | Whether this is the last page |
| page | integer | Current page number |
| next_page | integer | Next page number, or null if on last page |
| total_items | integer | Total number of items across all pages |
Organization
Get Organization
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/organization
Response:
{
"id": 567,
"name": "Tablespace Games",
"careers_page": {
"id": 172,
"slug": "tablespace-games-inc",
"custom_domain": "games.codestitching.dev"
}
}
Retrieves a few identifying details about your organization. A simple way to verify your API key is working.
HTTP Request
GET https://api.polymer.co/v1/hire/organization
Organization Users
List Active Users
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/organization_users/active
Response:
{
"items": [
{
"id": 86,
"first_name": "Calvin",
"last_name": "Dodge",
"email": "calvin.dodge@example.com",
"role": "org_owner",
"deactivated": false,
"is_admin": true,
"created_at": "2022-07-23T22:07:30.279Z",
"updated_at": "2025-10-28T21:06:32.757Z"
},
{
"id": 87,
"first_name": "Myra",
"last_name": "York",
"email": "myra.york@example.com",
"role": "org_user",
"deactivated": false,
"is_admin": false,
"created_at": "2022-07-24T03:23:55.236Z",
"updated_at": "2026-02-26T00:50:43.536Z"
},
{
"id": 89,
"first_name": "Aaron",
"last_name": "Grant",
"email": "aaron.grant@example.com",
"role": "org_admin",
"deactivated": false,
"is_admin": true,
"created_at": "2022-07-24T21:52:07.339Z",
"updated_at": "2025-10-28T21:06:32.770Z"
}
],
"meta": {
"total_pages": 1,
"is_first": true,
"is_last": true,
"page": 1,
"next_page": null,
"total_items": 3
}
}
Retrieves all active (non-deactivated) users in your organization.
HTTP Request
GET https://api.polymer.co/v1/hire/organization_users/active
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| role | string | Filter by role (e.g., org_admin, org_user) |
| updated_since | ISO 8601 | Return users updated after this timestamp |
| page | integer | Page number (default: 1) |
| per_page | integer | Items per page (default: 50) |
User Roles
| Role | Description |
|---|---|
| org_owner | Organization owner — full access |
| org_admin | Admin — can manage settings and users |
| org_user | Standard team member |
| org_interviewer | Interviewer — limited to assigned candidates |
List Deactivated Users
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/organization_users/deactivated
Response:
{
"items": [
{
"id": 88,
"first_name": "Terri",
"last_name": "Palmer",
"email": "terri.palmer@example.com",
"role": "org_user",
"deactivated": true,
"is_admin": false,
"created_at": "2022-07-24T03:24:21.852Z",
"updated_at": "2026-01-13T19:34:09.601Z"
}
],
"meta": {
"total_pages": 1,
"is_first": true,
"is_last": true,
"page": 1,
"next_page": null,
"total_items": 1
}
}
Retrieves all deactivated users in your organization. Useful for resolving organization_user_id references on older comments, reviews, or hiring stage events.
HTTP Request
GET https://api.polymer.co/v1/hire/organization_users/deactivated
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| updated_since | ISO 8601 | Return users updated after this timestamp |
| page | integer | Page number (default: 1) |
| per_page | integer | Items per page (default: 50) |
Get an Organization User
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/organization_users/90
Response:
{
"id": 90,
"first_name": "Calvin",
"last_name": "Dodge",
"email": "calvin.dodge@example.com",
"role": "org_user",
"deactivated": false,
"is_admin": false,
"created_at": "2022-07-27T00:08:18.440Z",
"updated_at": "2026-02-26T00:50:34.138Z"
}
Retrieves a specific organization user by ID. Works for both active and deactivated users.
HTTP Request
GET https://api.polymer.co/v1/hire/organization_users/<organization_user_id>
URL Parameters
| Parameter | Description |
|---|---|
| organization_user_id | The numeric ID of the Organization User |
Jobs
List Jobs
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/jobs
Response:
{
"items": [
{
"id": 2075,
"hash_id": "muioieicngd8",
"created_at": "2025-12-10T00:46:42.883Z",
"updated_at": "2025-12-14T02:41:42.370Z",
"title": "Senior Front-end Developer",
"status": "published",
"hidden": false,
"kind": "full_time",
"kind_pretty": "Full-time",
"..."
},
"...remaining items"
],
"meta": {
"total_pages": 3,
"is_first": true,
"is_last": false,
"page": 1,
"next_page": 2,
"total_items": 150
}
}
Retrieves all jobs for your organization.
HTTP Request
GET https://api.polymer.co/v1/hire/jobs
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| status | string | Filter by status: published, draft, archived, public (job is published and is not hidden) |
| updated_since | ISO 8601 | Return jobs updated after this timestamp |
| page | integer | Page number (default: 1) |
| per_page | integer | Items per page (default: 50) |
Get a Job
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/jobs/1149
Response:
{
"id": 1149,
"hash_id": "cjoyfsgjqxiq",
"created_at": "2024-10-07T19:51:02.601Z",
"updated_at": "2026-01-31T01:18:13.412Z",
"title": "Senior Back-end Developer",
"description": "<p>Job description HTML content...</p>",
"status": "published",
"hidden": false,
"published_at": "2025-12-17T21:42:15.227Z",
"archived_at": null,
"remoteness": "Remote friendly",
"kind": "full_time",
"kind_pretty": "Full-time",
"country": "US",
"state_region": "NC",
"city": "Raleigh",
"display_location": "Raleigh, NC",
"organization_name": "Tablespace Games",
"job_post_url": "https://jobs.polymer.co/tablespace-games-inc/1149",
"salary_min": "75000.0",
"salary_max": "95000.0",
"salary_currency": "USD",
"salary_unit": "YEAR",
"salary_pretty": "75K - 95K USD a year",
"job_category_id": 1268,
"job_category_name": "Software Development",
"remote_restriction_country_residency_is_required": true,
"remote_restriction_country_list": ["CA", "US"],
"remote_restriction_overlap_hours_is_required": false,
"remote_restriction_overlap_hours": 3,
"remote_restriction_city": "New York, NY, USA",
"remote_restriction_city_google_place_id": "ChIJOwg_06VPwokRYv534QaPC8g",
"remote_restriction_timezone_utc_offset_seconds": -14400,
"application_form_standard_fields": {
"name": "required",
"email": "required",
"phone": "optional",
"location": "optional",
"linkedin_url": "hidden",
"github_url": "hidden",
"twitter_url": "hidden",
"dribbble_url": "hidden",
"website_url": "hidden",
"resume": "required"
},
"questions": [
{
"id": 363,
"question_text": "Your last company",
"kind": "text_short",
"requirement_setting": "optional",
"options": {
"data": []
},
"position": 1,
"visibility_setting": "visibility_public"
},
{
"id": 364,
"question_text": "Why are you interested in Tablespace Games and this role, and why are you a good fit?",
"kind": "text_long",
"requirement_setting": "required",
"options": {
"data": []
},
"position": 2,
"visibility_setting": "visibility_public"
},
{
"id": 366,
"question_text": "Will you now or in the future require sponsorship for employment visa status (e.g., H-1B, etc.)?",
"kind": "single_select",
"requirement_setting": "required",
"options": {
"data": ["yes", "no"]
},
"position": 4,
"visibility_setting": "visibility_public"
}
],
"hiring_stages": [
{
"id": 2285,
"name": "Inbox",
"position": 0,
"job_applications_count": 109,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2286,
"name": "Screen",
"position": 1,
"job_applications_count": 21,
"has_active_message_automation": true,
"hiring_stage_message_automations": [
{
"id": 339,
"enabled": true,
"frequency": "once",
"hiring_stage": {
"id": 2286,
"name": "Screen"
},
"channel_message_template": {
"id": 139,
"name": "Thank you for applying"
}
}
]
},
{
"id": 3356,
"name": "Technical Interview",
"position": 2,
"job_applications_count": 3,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2287,
"name": "Panel Interview",
"position": 3,
"job_applications_count": 2,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2288,
"name": "Decide",
"position": 4,
"job_applications_count": 1,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2289,
"name": "Offer",
"position": 5,
"job_applications_count": 0,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2290,
"name": "Hired",
"position": 6,
"job_applications_count": 0,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2291,
"name": "Archived",
"position": 7,
"job_applications_count": 45,
"has_active_message_automation": true,
"hiring_stage_message_automations": [
{
"id": 340,
"enabled": true,
"frequency": "once",
"hiring_stage": {
"id": 2291,
"name": "Archived"
},
"channel_message_template": {
"id": 141,
"name": "Rejection"
}
}
]
}
]
}
Retrieves a specific job by ID.
HTTP Request
GET https://api.polymer.co/v1/hire/jobs/<job_id>
URL Parameters
| Parameter | Description |
|---|---|
| job_id | The numeric ID of the Job |
Get Hiring Stages
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/jobs/1149/hiring_stages
Response:
[
{
"id": 2285,
"name": "Inbox",
"position": 0,
"job_applications_count": 109,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2286,
"name": "Screen",
"position": 1,
"job_applications_count": 21,
"has_active_message_automation": true,
"hiring_stage_message_automations": [
{
"id": 339,
"enabled": true,
"frequency": "once",
"hiring_stage": {
"id": 2286,
"name": "Screen"
},
"channel_message_template": {
"id": 139,
"name": "Thank you for applying"
}
}
]
},
{
"id": 3356,
"name": "Technical Interview",
"position": 2,
"job_applications_count": 3,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2287,
"name": "Panel Interview",
"position": 3,
"job_applications_count": 2,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2288,
"name": "Decide",
"position": 4,
"job_applications_count": 1,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2289,
"name": "Offer",
"position": 5,
"job_applications_count": 0,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2290,
"name": "Hired",
"position": 6,
"job_applications_count": 0,
"has_active_message_automation": false,
"hiring_stage_message_automations": []
},
{
"id": 2291,
"name": "Archived",
"position": 7,
"job_applications_count": 45,
"has_active_message_automation": true,
"hiring_stage_message_automations": [
{
"id": 340,
"enabled": true,
"frequency": "once",
"hiring_stage": {
"id": 2291,
"name": "Archived"
},
"channel_message_template": {
"id": 141,
"name": "Rejection"
}
}
]
}
]
Retrieves the hiring pipeline stages configured for a specific job.
HTTP Request
GET https://api.polymer.co/v1/hire/jobs/<job_id>/hiring_stages
URL Parameters
| Parameter | Description |
|---|---|
| job_id | The numeric ID of the Job |
Start Resume Export
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/jobs/1149/resume_export_job
Response:
{
"status": "pending",
"message": "Export started. Poll GET endpoint for status.",
"total_resume_count": 181,
"processed_resume_count": 0
}
Starts a new resume export job. This is an asynchronous operation - poll the GET endpoint to check progress.
HTTP Request
POST https://api.polymer.co/v1/hire/jobs/<job_id>/resume_export_job
URL Parameters
| Parameter | Description |
|---|---|
| job_id | The numeric ID of the Job |
Get Resume Export
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/jobs/1149/resume_export_job
Response (no export):
{
"status": "none",
"message": "No export exists. POST to start one."
}
Response (queued):
{
"status": "queued",
"total_resume_count": 46,
"processed_resume_count": 0,
"message": "Export is queued."
}
Response (in progress):
{
"status": "processing",
"total_resume_count": 181,
"processed_resume_count": 50,
"message": "Export is in progress."
}
Response (completed):
{
"status": "completed",
"total_resume_count": 181,
"processed_resume_count": 181,
"message": "Export is ready.",
"download_url": "https://inflow-production.s3.amazonaws.com/exports/..."
}
Retrieves the status of a resume export job. When completed, includes a download URL for the ZIP file.
HTTP Request
GET https://api.polymer.co/v1/hire/jobs/<job_id>/resume_export_job
URL Parameters
| Parameter | Description |
|---|---|
| job_id | The numeric ID of the Job |
Export Statuses
| Status | Description |
|---|---|
| none | No export exists for this job. POST to start one. |
| queued | Export is waiting for other exports to complete. Will retry for 30 minutes, then fail. |
| processing | Export is actively being processed. |
| completed | Export is ready. download_url is included in the response. |
| failed | Export failed after timeout. Start a new export. |
ZIP File Structure
The downloaded ZIP file is named {Job-Title}-resumes-{timestamp}.zip (e.g., Senior-Back-end-Developer-resumes-20260131-012126.zip).
Inside the ZIP, each resume is named {Candidate-Name}-{JobApplicationId}.pdf (e.g., John-Doe-1463.pdf).
Candidates
A candidate can be thought of as a contact—their personal information (name, email, phone, etc.) is stored on the candidate record. Each candidate can have multiple job applications, one for each job they've applied to, been manually added to, or been copied to.
List Candidates
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/candidates
Response:
{
"items": [
{
"id": 1403,
"hash_id": "i4firdv4fz4z",
"created_at": "2024-10-07T21:23:28.146Z",
"updated_at": "2026-02-01T02:30:14.066Z",
"first_name": "Treena",
"last_name": "Reinger",
"email": "treena.reinger@example.com",
"phone": "(919) 555-0142",
"location": "Durham, NC, USA",
"linkedin_url": "https://linkedin.com/in/treena-reinger",
"github_url": null,
"twitter_url": null,
"dribbble_url": null,
"website_url": "https://treenareinger.com",
"created_via": "created_via_api",
"privacy_status": "public",
"job_application_ids": [1557]
},
{
"id": 1402,
"hash_id": "jymhswx2haoz",
"created_at": "2024-10-07T21:23:27.857Z",
"updated_at": "2026-02-01T02:29:20.107Z",
"first_name": "Willard",
"last_name": "Cremin",
"email": "willard.cremin@example.com",
"phone": "(415) 555-0198",
"location": "San Francisco, CA, USA",
"linkedin_url": "https://linkedin.com/in/willard-cremin",
"github_url": "https://github.com/wcremincode",
"twitter_url": null,
"dribbble_url": null,
"website_url": null,
"created_via": "created_via_api",
"privacy_status": "public",
"job_application_ids": [1556]
},
"...remaining items"
],
"meta": {
"total_pages": 4,
"is_first": true,
"is_last": false,
"page": 1,
"next_page": 2,
"total_items": 197
}
}
Retrieves all candidates for your organization.
HTTP Request
GET https://api.polymer.co/v1/hire/candidates
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| string | Filter by exact email address (URL-encoded) | |
| updated_since | ISO 8601 | Return candidates updated after this timestamp |
| page | integer | Page number (default: 1) |
| per_page | integer | Items per page (default: 50) |
Get a Candidate
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/candidates/1231
Response:
{
"id": 1231,
"hash_id": "8k0ey7iyylhh",
"created_at": "2024-03-03T05:34:33.330Z",
"updated_at": "2026-02-01T17:58:46.996Z",
"first_name": "Jeremiah",
"last_name": "Clark",
"email": "jeremiah.clark@example.com",
"phone": "7178778121",
"location": "Franklin, TN",
"linkedin_url": null,
"github_url": null,
"twitter_url": null,
"dribbble_url": null,
"website_url": null,
"created_via": "created_via_api",
"privacy_status": "public",
"job_application_ids": [1367, 1398]
}
Retrieves a specific candidate by ID.
HTTP Request
GET https://api.polymer.co/v1/hire/candidates/<candidate_id>
URL Parameters
| Parameter | Description |
|---|---|
| candidate_id | The numeric ID of the Candidate |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| include | string | Include related data. Supported: job_applications |
Get a Candidate with Job Applications
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.polymer.co/v1/hire/candidates/1231?include=job_applications"
Response:
{
"id": 1231,
"hash_id": "8k0ey7iyylhh",
"created_at": "2024-03-03T05:34:33.330Z",
"updated_at": "2026-02-01T17:58:46.996Z",
"first_name": "Jeremiah",
"last_name": "Clark",
"email": "jeremiah.clark@example.com",
"phone": "7178778121",
"location": "Franklin, TN",
"linkedin_url": null,
"github_url": null,
"twitter_url": null,
"dribbble_url": null,
"website_url": null,
"created_via": "created_via_api",
"privacy_status": "public",
"job_application_ids": [1367, 1398],
"job_applications": [
{
"id": 1398,
"hash_id": "wrueurpksrsn",
"job_id": 1110,
"job_title": "Talent Pool",
"hiring_stage_id": 1977,
"hiring_stage_name": "Inbox",
"applied_at": "2024-07-25T00:04:12.693Z",
"date_moved_to_current_stage": "2024-07-25T00:04:12.798Z",
"source": null,
"created_via": "created_via_job_board",
"resume_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../Jeremiah_Clark_Resume.pdf",
"files": [
{
"filename": "Jeremiah_Clark_Resume.pdf",
"content_type": "application/pdf",
"file_type": "resume",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../Jeremiah_Clark_Resume.pdf"
}
],
"question_responses": []
},
{
"id": 1367,
"hash_id": "ebgprp17rqgc",
"job_id": 1103,
"job_title": "Product Manager",
"hiring_stage_id": 1926,
"hiring_stage_name": "Inbox",
"applied_at": "2024-03-03T05:34:33.360Z",
"date_moved_to_current_stage": null,
"source": null,
"created_via": "created_via_job_board",
"resume_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../Jeremiah_Clark_Resume.pdf",
"files": [
{
"filename": "Jeremiah_Clark_Resume.pdf",
"content_type": "application/pdf",
"file_type": "resume",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../Jeremiah_Clark_Resume.pdf"
},
{
"filename": "Coverletter.docx",
"content_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"file_type": "uploaded",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../Coverletter.docx"
}
],
"question_responses": [
{
"question_id": 289,
"question_text": "Can you describe a product you launched or managed that you are proud of?",
"response_type": "text_long",
"body": "I worked on a feature within a game that was essentially a second game. It was a sanctuary where users could play the main game to gain items in order to progress through different milestones.",
"response_array": []
}
]
}
]
}
When include=job_applications is specified, the response includes a job_applications array with each application's details.
HTTP Request
GET https://api.polymer.co/v1/hire/candidates/<candidate_id>?include=job_applications
URL Parameters
| Parameter | Description |
|---|---|
| candidate_id | The numeric ID of the Candidate |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| include | string | Include related data. Supported: job_applications |
Job Applications
List Job Applications
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications
Response:
{
"items": [
{
"id": 1585,
"hash_id": "uzifeztdmshg",
"created_at": "2025-09-13T20:32:51.803Z",
"updated_at": "2026-01-31T01:41:02.060Z",
"job_id": 1149,
"job_hash_id": "cjoyfsgjqxiq",
"job_title": "Senior Back-end Developer",
"candidate_id": 1431,
"candidate_first_name": "Jefferey",
"candidate_last_name": "Wilderman",
"candidate_email": "jefferey.wilderman@example.com",
"candidate_phone": "(980) 971-7489",
"candidate_location": "East Bentown, Illinois, USA",
"candidate_linkedin_url": "https://linkedin.com/in/jefferey-wilderman",
"candidate_github_url": null,
"candidate_twitter_url": null,
"candidate_dribbble_url": null,
"candidate_website_url": null,
"hiring_stage_id": 2291,
"hiring_stage_name": "Archived",
"current_hiring_stage": {
"id": 2291,
"name": "Archived",
"has_active_message_automation": true
},
"next_hiring_stage": null,
"applied_at": "2025-09-13T20:32:51.803Z",
"date_moved_to_current_stage": "2025-10-07T20:18:55.320Z",
"source": null,
"created_via": "created_via_job_board",
"resume_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../resume.pdf",
"files": [
{
"filename": "resume.pdf",
"content_type": "application/pdf",
"file_type": "resume",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../resume.pdf"
}
],
"question_responses": []
},
"...remaining items"
],
"meta": {
"total_pages": 5,
"is_first": true,
"is_last": false,
"page": 1,
"next_page": 2,
"total_items": 205
}
}
Retrieves all job applications for your organization.
HTTP Request
GET https://api.polymer.co/v1/hire/job_applications
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| job_id | integer | Filter by job ID |
| hiring_stage_id | integer | Filter by hiring stage ID |
| candidate_id | integer | Filter by candidate ID |
| updated_since | ISO 8601 | Return applications updated after this timestamp |
| page | integer | Page number (default: 1) |
| per_page | integer | Items per page (default: 50) |
Get a Job Application
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596
Response:
{
"id": 1596,
"hash_id": "lhssnjxdwl0r",
"created_at": "2025-09-10T21:15:51.431Z",
"updated_at": "2025-10-07T21:30:51.472Z",
"job_id": 1149,
"job_hash_id": "cjoyfsgjqxiq",
"job_title": "Senior Back-end Developer",
"candidate_id": 1442,
"candidate_first_name": "Marcus",
"candidate_last_name": "Johnston",
"candidate_email": "marcus.johnston@example.com",
"candidate_phone": "653-939-1474",
"candidate_location": "Lake Brenton, Delaware, USA",
"candidate_linkedin_url": "https://linkedin.com/in/marcus-johnston",
"candidate_github_url": null,
"candidate_twitter_url": null,
"candidate_dribbble_url": null,
"candidate_website_url": null,
"hiring_stage_id": 2287,
"hiring_stage_name": "Panel Interview",
"current_hiring_stage": {
"id": 2287,
"name": "Panel Interview",
"has_active_message_automation": false
},
"next_hiring_stage": {
"id": 2288,
"name": "Decide",
"has_active_message_automation": false
},
"applied_at": "2025-09-10T21:15:51.431Z",
"date_moved_to_current_stage": "2025-10-07T20:19:47.003Z",
"source": null,
"created_via": "created_via_job_board",
"resume_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../resume.pdf",
"files": [
{
"filename": "resume.pdf",
"content_type": "application/pdf",
"file_type": "resume",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../resume.pdf"
}
],
"question_responses": [
{
"question_id": 363,
"question_text": "Your last company",
"response_type": "text_short",
"body": "Roblox",
"response_array": []
},
{
"question_id": 364,
"question_text": "Why are you interested in Tablespace Games and this role, and why are you a good fit?",
"response_type": "text_long",
"body": "I am a very self-driven and self-organized software engineer. I pick up new tech stacks quickly and have great problem solving skills and technical abilities in both frontend and backend development.",
"response_array": []
}
]
}
Retrieves a specific job application by ID.
HTTP Request
GET https://api.polymer.co/v1/hire/job_applications/<job_application_id>
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Import a Job Application
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/import \
-d '{
"job_id": 1149,
"first_name": "Fatima",
"last_name": "Al-Rashid",
"email": "fatima.alrashid@example.com",
"phone": "+44-20-7946-0312",
"location": "London, UK",
"source": "linkedin_scrape",
"resume": {
"base64": "JVBERi0xLjQK...",
"filename": "fatima-alrashid-resume.pdf"
}
}'
Response:
{
"id": 8210,
"hash_id": "ivuludoqrf2j",
"created_at": "2026-02-26T02:20:29.821Z",
"updated_at": "2026-02-26T02:20:29.913Z",
"job_id": 1149,
"job_hash_id": "cjoyfsgjqxiq",
"job_title": "Senior Back-end Developer",
"candidate_id": 3125,
"candidate_first_name": "Fatima",
"candidate_last_name": "Al-Rashid",
"candidate_email": "fatima.alrashid@example.com",
"candidate_phone": "+44-20-7946-0312",
"candidate_location": "London, UK",
"candidate_linkedin_url": null,
"candidate_github_url": null,
"candidate_twitter_url": null,
"candidate_dribbble_url": null,
"candidate_website_url": null,
"hiring_stage_id": 2285,
"hiring_stage_name": "Inbox",
"current_hiring_stage": {
"id": 2285,
"name": "Inbox",
"has_active_message_automation": false
},
"next_hiring_stage": {
"id": 2286,
"name": "Screen",
"has_active_message_automation": true
},
"applied_at": "2026-02-26T02:20:29.821Z",
"date_moved_to_current_stage": null,
"source": "linkedin_scrape",
"created_via": "created_via_customer_api_import",
"resume_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../fatima-alrashid-resume.pdf",
"files": [
{
"filename": "fatima-alrashid-resume.pdf",
"content_type": "application/pdf",
"file_type": "resume",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../fatima-alrashid-resume.pdf"
}
],
"question_responses": []
}
Imports a candidate into a job without requiring application form fields or question responses. This is useful for migrating candidates from another system or adding sourced candidates who did not apply through the job board.
The application is placed in the job's Inbox stage. Unlike the Apply endpoint, there is no option to send a candidate confirmation email — one is never sent for imported applications.
HTTP Request
POST https://api.polymer.co/v1/hire/job_applications/import
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| job_id | integer | yes | The ID of the job to import into |
| first_name | string | yes | Candidate's first name |
| last_name | string | no | Candidate's last name |
| string | yes | Candidate's email address | |
| phone | string | no | Candidate's phone number |
| location | string | no | Candidate's location |
| source | string | no | How the candidate was sourced (free-form text, e.g., linkedin_scrape) |
| resume | object | no | Resume file. See Resume Object under Apply for a Job |
Error Details
| HTTP Status | Code | Message |
|---|---|---|
| 409 | duplicate_application |
A candidate with email '...' already has an application for this job. Response includes existing_job_application_id |
| 422 | validation_error |
first_name: "is required" |
| 422 | validation_error |
email: "is required" |
| 422 | validation_error |
question_responses: "Question responses are not accepted on the import endpoint. Use the apply endpoint to submit applications with question responses." |
Apply for a Job
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/apply \
-d '{
"job_id": 1149,
"first_name": "Marcus",
"last_name": "Chen",
"email": "marcus.chen@example.com",
"phone": "+1-415-555-0147",
"location": "San Francisco, CA",
"linkedin_url": "marcuschen",
"github_url": "marcuschen",
"twitter_url": "marcuschen",
"website_url": "marcuschen.dev",
"source": "partner_referral",
"send_candidate_confirmation_email": true,
"question_responses": [
{
"question_id": 364,
"body": "Led a complete redesign of the checkout flow that increased conversion by 22%."
},
{
"question_id": 366,
"body": "No"
},
{
"question_id": 2087,
"response_array": ["Figma", "Sketch", "Adobe Illustrator"]
},
{
"question_id": 1317,
"custom_file": {
"filename": "cover-letter.pdf",
"content_type": "application/pdf",
"base64": "JVBERi0xLjQK..."
}
}
],
"resume": {
"filename": "marcus-chen-resume.pdf",
"base64": "JVBERi0xLjQK..."
}
}'
Response:
{
"id": 8205,
"hash_id": "tqfqls4x4odl",
"created_at": "2026-02-26T01:05:27.266Z",
"updated_at": "2026-02-26T01:05:27.365Z",
"job_id": 1149,
"job_hash_id": "cjoyfsgjqxiq",
"job_title": "Senior Back-end Developer",
"candidate_id": 3120,
"candidate_first_name": "Marcus",
"candidate_last_name": "Chen",
"candidate_email": "marcus.chen@example.com",
"candidate_phone": "+1-415-555-0147",
"candidate_location": "San Francisco, CA",
"candidate_linkedin_url": "https://linkedin.com/in/marcuschen",
"candidate_github_url": "https://github.com/marcuschen",
"candidate_twitter_url": "https://x.com/marcuschen",
"candidate_dribbble_url": null,
"candidate_website_url": "https://marcuschen.dev",
"hiring_stage_id": 2285,
"hiring_stage_name": "Inbox",
"current_hiring_stage": {
"id": 2285,
"name": "Inbox",
"has_active_message_automation": false
},
"next_hiring_stage": {
"id": 2286,
"name": "Screen",
"has_active_message_automation": true
},
"applied_at": "2026-02-26T01:05:27.266Z",
"date_moved_to_current_stage": null,
"source": "partner_referral",
"created_via": "created_via_customer_api_apply",
"resume_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../marcus-chen-resume.pdf",
"files": [
{
"filename": "marcus-chen-resume.pdf",
"content_type": "application/pdf",
"file_type": "resume",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../marcus-chen-resume.pdf"
},
{
"filename": "cover-letter.pdf",
"content_type": "application/pdf",
"file_type": "question_response_file",
"download_url": "https://app.polymer.co/rails/active_storage/blobs/redirect/.../cover-letter.pdf"
}
],
"question_responses": [
{
"question_id": 364,
"question_text": "Why are you interested in Tablespace Games and this role, and why are you a good fit?",
"response_type": "text_long",
"body": "Led a complete redesign of the checkout flow that increased conversion by 22%.",
"response_array": null
},
{
"question_id": 366,
"question_text": "Will you now or in the future require sponsorship for employment visa status (e.g., H-1B, etc.)?",
"response_type": "single_select",
"body": "No",
"response_array": null
},
{
"question_id": 2087,
"question_text": "Name top 3 tools",
"response_type": "multi_select",
"body": null,
"response_array": [
"Figma",
"Sketch",
"Adobe Illustrator"
]
},
{
"question_id": 1317,
"question_text": "Upload a cover letter or a note to the hiring team",
"response_type": "file_upload",
"body": null,
"response_array": null
}
]
}
Submits a new job application. The application is placed in the job's Inbox stage. The response returns the full job application object.
Which fields are required depends on the job's configuration — use the Get a Job endpoint to check application_form_standard_fields and questions for a specific job.
HTTP Request
POST https://api.polymer.co/v1/hire/job_applications/apply
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| job_id | integer | yes | The ID of the job to apply to |
| first_name | string | yes | Candidate's first name |
| string | yes | Candidate's email address | |
| send_candidate_confirmation_email | boolean | yes | Whether to send the candidate a confirmation email. Must be true or false (not a string) |
| last_name | string | no | Candidate's last name |
| phone | string | conditional | Candidate's phone number. Required if set to required in application_form_standard_fields |
| location | string | conditional | Candidate's location. Required if set to required in application_form_standard_fields |
| linkedin_url | string | conditional | LinkedIn profile. Can be a full URL or just the handle (e.g., marcuschen becomes https://linkedin.com/in/marcuschen) |
| github_url | string | conditional | GitHub profile. Handle or full URL |
| twitter_url | string | conditional | X/Twitter profile. Handle or full URL |
| dribbble_url | string | conditional | Dribbble profile. Handle or full URL |
| website_url | string | conditional | Personal website. Domain or full URL (e.g., marcuschen.dev becomes https://marcuschen.dev) |
| source | string | no | How the candidate found the job (free-form text, e.g., partner_referral, linkedin) |
| resume | object | conditional | Resume file. Required if set to required in application_form_standard_fields. See Resume Object below |
| question_responses | array | conditional | Responses to the job's application questions. Required questions must be answered. See Question Response Object below |
Resume Object
| Field | Type | Required | Description |
|---|---|---|---|
| base64 | string | yes | Base64-encoded file contents |
| filename | string | no | The file name including extension (e.g., resume.pdf) |
Question Response Object
The format depends on the question type. Use the Get a Job endpoint to see each question's kind and available options.
| Field | Type | When to use |
|---|---|---|
| question_id | integer | Always required — the question's ID |
| body | string | For text_short, text_long, and single_select questions |
| response_array | array | For multi_select questions — array of selected option strings |
| custom_file | object | For file_upload questions — see File Upload Object below |
File Upload Object
| Field | Type | Required | Description |
|---|---|---|---|
| base64 | string | yes | Base64-encoded file contents |
| filename | string | recommended | The file name including extension |
| content_type | string | recommended | MIME type (e.g., application/pdf, image/jpeg) |
Error Details
| HTTP Status | Code | Message |
|---|---|---|
| 409 | duplicate_application |
A candidate with email '...' already has an application for this job. Response includes existing_job_application_id |
| 422 | validation_error |
field: "is required" |
| 422 | validation_error |
email: "is invalid" |
| 422 | validation_error |
send_candidate_confirmation_email: "must be a boolean (true or false)" |
| 422 | validation_error |
question_responses: "question with id {id} does not belong to this job" |
Job Application Comments
Get Job Application Comments
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/comments
Response:
[
{
"id": 112,
"job_application_id": 1596,
"organization_user_id": 11,
"body": "<p>Good at first glance</p>",
"created_via": "created_via_in_app",
"author_type": "user",
"created_at": "2025-09-16T09:15:42.042Z"
},
{
"id": 135,
"job_application_id": 1596,
"organization_user_id": 10,
"body": "<p>Strong communication skills noted in interview</p>",
"created_via": "created_via_customer_api",
"author_type": "api_integration",
"created_at": "2025-10-01T16:30:37.574Z"
}
]
Retrieves all comments on a job application.
HTTP Request
GET https://api.polymer.co/v1/hire/job_applications/<job_application_id>/comments
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Create a Comment
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/8180/comments \
-d '{
"body": "<p>Strong portfolio — particularly impressed by the fintech dashboard redesign.</p>",
"author_type": "api_key_owner"
}'
Response:
{
"id": 5972,
"organization_user_id": 4,
"body": "<p>Strong portfolio — particularly impressed by the fintech dashboard redesign.</p>",
"created_via": "created_via_customer_api",
"author_type": "api_key_owner",
"created_at": "2026-02-24T17:29:37.071Z",
"job_application": {
"id": 8180,
"job_id": 8,
"job_title": "Product Designer",
"current_hiring_stage": {
"id": 51,
"name": "Screen"
},
"candidate": {
"id": 3108,
"first_name": "Marcus",
"last_name": "Rivera",
"email": "marcus.rivera@example.com",
"phone": "+1-503-555-0147",
"location": "Portland, OR",
"linkedin_url": "https://linkedin.com/in/marcusrivera"
}
}
}
Creates a new comment on a job application. The body field accepts HTML content.
HTTP Request
POST https://api.polymer.co/v1/hire/job_applications/<job_application_id>/comments
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| body | string | yes | The comment content. Accepts HTML (e.g., <p>, <strong>, <ul>, <ol>, <a>) |
| author_type | string | no | Who the comment is attributed to. Default: api_integration. See Author Types below |
Author Types
| author_type | Description |
|---|---|
| api_integration | Comment appears as posted by the API integration (default) |
| api_key_owner | Comment appears as posted by the team member who owns the API key |
Error Details
| HTTP Status | Code | Message |
|---|---|---|
| 422 | validation_error |
body: "can't be blank" |
| 422 | validation_error |
author_type: "must be api_integration or api_key_owner" |
| 403 | forbidden |
You cannot update a comment authored by another user |
| 403 | forbidden |
You cannot delete a comment authored by another user |
Update a Comment
curl -X PUT -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/8180/comments/5991 \
-d '{
"body": "<p>Updated: Very strong portfolio. Recommend fast-tracking to interview.</p>"
}'
Response:
{
"id": 5991,
"organization_user_id": 4,
"body": "<p>Updated: Very strong portfolio. Recommend fast-tracking to interview.</p>",
"created_via": "created_via_customer_api",
"author_type": "api_integration",
"created_at": "2026-02-24T19:11:25.874Z",
"job_application": {
"id": 8180,
"job_id": 8,
"job_title": "Product Designer",
"current_hiring_stage": {
"id": 51,
"name": "Screen"
},
"candidate": {
"id": 3108,
"first_name": "Marcus",
"last_name": "Rivera",
"email": "marcus.rivera@example.com",
"phone": "+1-503-555-0147",
"location": "Portland, OR",
"linkedin_url": "https://linkedin.com/in/marcusrivera"
}
}
}
Updates an existing comment on a job application. You can update any comment that belongs to the team member who owns the API key.
HTTP Request
PUT https://api.polymer.co/v1/hire/job_applications/<job_application_id>/comments/<comment_id>
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
| comment_id | The numeric ID of the Comment |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| body | string | yes | The updated comment content. Accepts HTML (e.g., <p>, <strong>, <ul>, <ol>) |
Delete a Comment
curl -X DELETE -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/comments/112
Response:
{
"id": 112,
"deleted": true
}
Deletes a comment from a job application. You can only delete comments that belong to the team member who owns the API key.
HTTP Request
DELETE https://api.polymer.co/v1/hire/job_applications/<job_application_id>/comments/<comment_id>
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
| comment_id | The numeric ID of the Comment |
Job Application Reviews
Get Job Application Reviews
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/reviews
Response:
[
{
"id": 117,
"job_application_id": 1596,
"organization_user_id": 8,
"body": "<p>Good technical skills demonstrated</p>",
"rating": "weak_yes",
"created_via": "created_via_in_app",
"author_type": "user",
"created_at": "2025-09-22T14:45:01.470Z",
"updated_at": "2025-09-22T14:52:22.179Z"
},
{
"id": 21488,
"job_application_id": 1596,
"organization_user_id": 11,
"body": "<p>Scores<br><br>Friendliness: 4/5<br>Critical thinking: 4/5<br>Startup experience: 2/5<br>Leadership: 3/5<br><br>Total 13/20</p>",
"rating": "weak_yes",
"created_via": "created_via_customer_api",
"author_type": "api_integration",
"created_at": "2025-10-02T10:30:52.109Z",
"updated_at": "2025-10-02T10:45:55.691Z"
}
]
Retrieves all reviews (scorecards) for a job application.
HTTP Request
GET https://api.polymer.co/v1/hire/job_applications/<job_application_id>/reviews
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Create a Review
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/8180/reviews \
-d '{
"body": "<h3>Review by John Davis</h3><h3>Technical Assessment — 4/5</h3><p>Completed the take-home project with clean architecture. Used React Query for server state and Emotion for styling, which aligns with our stack.</p><ul><li>Component composition was excellent</li><li>Error handling could be more thorough</li><li>Test coverage was above average</li></ul><h3>Communication — 5/5</h3><p>Articulate and collaborative. Asked clarifying questions before diving into the problem.</p><ol><li>Recommend offer at Senior level</li><li>Potential tech lead track in 12-18 months</li><li>Start date flexible — available in 2 weeks</li></ol>",
"rating": "strong_yes"
}'
Response:
{
"id": 5995,
"organization_user_id": 4,
"body": "<h3>Review by John Davis</h3><h3>Technical Assessment — 4/5</h3><p>Completed the take-home project with clean architecture. Used React Query for server state and Emotion for styling, which aligns with our stack.</p><ul><li>Component composition was excellent</li><li>Error handling could be more thorough</li><li>Test coverage was above average</li></ul><h3>Communication — 5/5</h3><p>Articulate and collaborative. Asked clarifying questions before diving into the problem.</p><ol><li>Recommend offer at Senior level</li><li>Potential tech lead track in 12-18 months</li><li>Start date flexible — available in 2 weeks</li></ol>",
"rating": "strong_yes",
"created_via": "created_via_customer_api",
"author_type": "api_integration",
"created_at": "2026-02-24T20:02:30.808Z",
"updated_at": "2026-02-24T20:02:30.808Z",
"job_application": {
"id": 8180,
"job_id": 8,
"job_title": "Product Designer",
"current_hiring_stage": {
"id": 51,
"name": "Screen"
},
"candidate": {
"id": 3108,
"first_name": "Marcus",
"last_name": "Rivera",
"email": "marcus.rivera@example.com",
"phone": "+1-503-555-0147",
"location": "Portland, OR",
"linkedin_url": "https://linkedin.com/in/marcusrivera"
}
}
}
Creates a new review (scorecard) on a job application. The body field accepts HTML content — we recommend starting with a heading that identifies the reviewer, such as <h3>Review by John Davis</h3>, since API-created reviews are attributed to the integration rather than an individual user.
HTTP Request
POST https://api.polymer.co/v1/hire/job_applications/<job_application_id>/reviews
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| body | string | yes | The review content. Accepts HTML (e.g., <h3>, <p>, <strong>, <ul>, <ol>) |
| rating | string | no | The overall rating for the candidate. Default: no_rating. See Rating Values below |
| author_type | string | no | Who the review is attributed to. Default: api_integration. See Author Types under Create a Comment |
Rating Values
| Rating | Description |
|---|---|
| strong_yes | Strongly recommend this candidate |
| weak_yes | Lean towards recommending |
| weak_no | Lean towards not recommending |
| strong_no | Strongly recommend against |
| no_rating | No rating provided (default) |
Error Details
| HTTP Status | Code | Message |
|---|---|---|
| 422 | validation_error |
body: "can't be blank" |
| 422 | validation_error |
rating: "must be one of: strong_no, weak_no, weak_yes, strong_yes, no_rating" |
| 403 | forbidden |
You cannot update a review authored by another user |
| 403 | forbidden |
You cannot delete a review authored by another user |
Update a Review
curl -X PUT -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/8180/reviews/5996 \
-d '{
"body": "<p>Revised after panel discussion. Still strong but some concerns about collaboration style.</p>",
"rating": "weak_yes"
}'
Response:
{
"id": 5996,
"organization_user_id": 4,
"body": "<p>Revised after panel discussion. Still strong but some concerns about collaboration style.</p>",
"rating": "weak_yes",
"created_via": "created_via_customer_api",
"author_type": "api_integration",
"created_at": "2026-02-24T20:03:55.585Z",
"updated_at": "2026-02-24T20:05:01.699Z",
"job_application": {
"id": 8180,
"job_id": 8,
"job_title": "Product Designer",
"current_hiring_stage": {
"id": 51,
"name": "Screen"
},
"candidate": {
"id": 3108,
"first_name": "Marcus",
"last_name": "Rivera",
"email": "marcus.rivera@example.com",
"phone": "+1-503-555-0147",
"location": "Portland, OR",
"linkedin_url": "https://linkedin.com/in/marcusrivera"
}
}
}
Updates an existing review. You can update the body, rating, or both. You can update any review that belongs to the team member who owns the API key.
HTTP Request
PUT https://api.polymer.co/v1/hire/job_applications/<job_application_id>/reviews/<review_id>
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
| review_id | The numeric ID of the Review |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| body | string | no | The updated review content. Accepts HTML |
| rating | string | no | The updated rating. See Rating Values above |
Delete a Review
curl -X DELETE -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/reviews/117
Response:
{
"id": 117,
"deleted": true
}
Deletes a review from a job application. You can only delete reviews that belong to the team member who owns the API key.
HTTP Request
DELETE https://api.polymer.co/v1/hire/job_applications/<job_application_id>/reviews/<review_id>
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
| review_id | The numeric ID of the Review |
Job Application Stages
Move Stage
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
https://api.polymer.co/v1/hire/job_applications/1596/move_stage \
-d '{
"hiring_stage_id": 2287,
"skip_message_automations": true
}'
Response:
{
"message": "Job application moved successfully",
"job_application_id": 1596,
"previous_stage": {
"id": 2286,
"name": "Screen",
"has_active_message_automation": true
},
"current_stage": {
"id": 2287,
"name": "Panel Interview",
"has_active_message_automation": false
},
"skip_message_automations": true
}
Moves a job application to a different hiring stage. Use the Get Hiring Stages endpoint to see the available stages and their IDs for a job.
HTTP Request
POST https://api.polymer.co/v1/hire/job_applications/<job_application_id>/move_stage
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| hiring_stage_id | integer | yes | The ID of the target hiring stage. Must belong to the same job |
| skip_message_automations | boolean | yes | Whether to skip message automations configured on the target stage. Must be true or false (not a string) |
Error Details
| HTTP Status | Code | Message |
|---|---|---|
| 422 | missing_parameter |
hiring_stage_id is required |
| 422 | validation_error |
skip_message_automations: "is required" |
| 422 | validation_error |
skip_message_automations: "must be a boolean (true or false)" |
| 422 | invalid_request |
Job application is already in this hiring stage |
Archive
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/archive
Response:
{
"message": "Job application archived successfully",
"job_application_id": 1596,
"previous_stage": {
"id": 2287,
"name": "Panel Interview",
"has_active_message_automation": false
},
"current_stage": {
"id": 2291,
"name": "Archived",
"has_active_message_automation": true
}
}
Archives a job application by moving it to the Archived stage.
HTTP Request
POST https://api.polymer.co/v1/hire/job_applications/<job_application_id>/archive
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Get Hiring Stage Events
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/hiring_stage_events
Response:
[
{
"id": 1239,
"job_application_id": 1596,
"source_hiring_stage_id": null,
"current_hiring_stage_id": 2285,
"current_hiring_stage_name_at_move": "Inbox",
"moved_by_organization_user_id": null,
"created_at": "2025-09-10T21:15:51.498Z"
},
{
"id": 1240,
"job_application_id": 1596,
"source_hiring_stage_id": 2285,
"current_hiring_stage_id": 2286,
"current_hiring_stage_name_at_move": "Screen",
"moved_by_organization_user_id": 349,
"created_at": "2025-09-15T14:30:14.468Z"
},
{
"id": 1253,
"job_application_id": 1596,
"source_hiring_stage_id": 2286,
"current_hiring_stage_id": 3356,
"current_hiring_stage_name_at_move": "Technical Interview",
"moved_by_organization_user_id": 349,
"created_at": "2025-09-22T10:45:27.414Z"
},
{
"id": 1254,
"job_application_id": 1596,
"source_hiring_stage_id": 3356,
"current_hiring_stage_id": 2287,
"current_hiring_stage_name_at_move": "Panel Interview",
"moved_by_organization_user_id": 349,
"created_at": "2025-10-01T16:20:47.003Z"
}
]
Retrieves the history of hiring stage transitions for a job application.
HTTP Request
GET https://api.polymer.co/v1/hire/job_applications/<job_application_id>/hiring_stage_events
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Job Application Messages
Get Job Application Messages
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.polymer.co/v1/hire/job_applications/1596/messages
Response:
[
{
"id": 2020,
"job_application_id": 1596,
"created_at": "2025-09-10T14:23:45.000Z",
"sent_by": "sent_by_organization",
"source": "source_in_app",
"created_by_organization_user_id": null,
"body": "<p>Hello Marcus,</p><p>This is a confirmation that your application for the Senior Back-end Developer position with Tablespace Games was submitted successfully.</p>",
"body_plain_text": "Hello Marcus,\n\nThis is a confirmation that your application for the Senior Back-end Developer position with Tablespace Games was submitted successfully."
},
{
"id": 2021,
"job_application_id": 1596,
"created_at": "2025-09-12T10:15:22.000Z",
"sent_by": "sent_by_user",
"source": "source_in_app",
"created_by_organization_user_id": 349,
"body": "<p>Hi Marcus,</p><p>Thanks for your interest in Tablespace Games! We'd like to set up an initial 30-minute video chat to discuss your background and the role.</p><p>Are you available this Friday at 2 PM EST, or Monday at 10 AM EST?</p><p>Best,<br>Myra</p>",
"body_plain_text": "Hi Marcus,\n\nThanks for your interest in Tablespace Games! We'd like to set up an initial 30-minute video chat to discuss your background and the role.\n\nAre you available this Friday at 2 PM EST, or Monday at 10 AM EST?\n\nBest,\nMyra"
},
{
"id": 2022,
"job_application_id": 1596,
"created_at": "2025-09-12T15:42:18.000Z",
"sent_by": "sent_by_candidate",
"source": "source_email",
"created_by_organization_user_id": null,
"body": "<p>Hi Myra,</p><p>Thanks for reaching out! Friday at 2 PM EST works perfectly for me.</p><p>I'm really excited to learn more about the game development work you're doing at Tablespace. See you then!</p><p>Best,<br>Marcus</p>",
"body_plain_text": "Hi Myra,\n\nThanks for reaching out! Friday at 2 PM EST works perfectly for me.\n\nI'm really excited to learn more about the game development work you're doing at Tablespace. See you then!\n\nBest,\nMarcus"
}
]
Retrieves all messages (emails) associated with a job application.
HTTP Request
GET https://api.polymer.co/v1/hire/job_applications/<job_application_id>/messages
URL Parameters
| Parameter | Description |
|---|---|
| job_application_id | The numeric ID of the Job Application |
Message Sender Types
| sent_by | Description |
|---|---|
| sent_by_user | Message sent by a team member |
| sent_by_candidate | Message sent by the candidate |
| sent_by_organization | Message sent by an automation (e.g., auto-confirmation) |
HTML Body Format
The body field for comments and reviews accepts HTML content. The API sanitizes all HTML input to ensure safe, consistent rendering. Plain text is also accepted and will be automatically wrapped in paragraph tags.
Allowed HTML Elements
| Category | Elements |
|---|---|
| Block | p, h1, h2, h3, h4, h5, h6, blockquote, pre |
| Lists | ul, ol, li |
| Table | table, thead, tbody, tr, th, td |
| Inline | strong, b, em, i, a, code, br |
| Separator | hr |
Sanitization Rules
The API normalizes submitted HTML for consistent rendering:
- Plain text is automatically wrapped in
<p>tags — e.g.,Just plain textbecomes<p>Just plain text</p> <div>tags with inline content are converted to<p>tags; nested divs are unwrapped recursively<span>tags are stripped — inner text is preserved- Bare text adjacent to block elements is wrapped in
<p>tags — e.g.,<h3>Title</h3>some textbecomes<h3>Title</h3><p>some text</p> - Disallowed elements (
section,article,header,footer,nav,body, etc.) are stripped — inner text is preserved and wrapped in<p>tags - Empty elements (whitespace-only or empty HTML tags) are removed
Content Validation
The body must contain actual text content after sanitization. The following will return a 422 validation error:
- Empty or whitespace-only content (e.g.,
<p> </p>) - Tags with no text (e.g.,
<div><span></span></div>) <br>or<hr>alone without accompanying text
Errors
The Polymer API uses conventional HTTP response codes to indicate the success or failure of an API request.
| Code | Status | Description |
|---|---|---|
| 400 | Bad Request | Invalid request parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | You do not have permission to modify the requested resource |
| 404 | Not Found | The requested resource does not exist |
| 409 | Conflict | The request conflicts with existing data |
| 422 | Unprocessable Entity | Request validation failed |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Something went wrong on our end |
Error Response Format
All errors return JSON with an error object containing code and message fields. Some errors also include a details object with field-level validation messages.
Error Object
| Field | Type | Description |
|---|---|---|
| code | string | A machine-readable error code for programmatic handling |
| message | string | A human-readable description of the error |
| details | object | Field-level error messages (only on validation_error) |
Missing API key (401 Unauthorized):
{
"error": {
"code": "missing_api_key",
"message": "API key is required"
}
}
Invalid API key (401 Unauthorized):
{
"error": {
"code": "invalid_api_key",
"message": "API key is invalid"
}
}
Invalid query parameter (400 Bad Request):
{
"error": {
"code": "invalid_parameter",
"message": "bogus is not a valid query parameter"
}
}
Resource not found (404 Not Found):
{
"error": {
"code": "resource_not_found",
"message": "Job not found"
}
}
The message field will specify which resource was not found (e.g., "Job not found", "Candidate not found", "Job application not found", "Comment not found", "Review not found", "Hiring stage not found for this job").
Forbidden (403 Forbidden):
{
"error": {
"code": "forbidden",
"message": "You cannot update a comment authored by another user"
}
}
Returned when attempting to update or delete a comment or review that belongs to a different team member.
Duplicate application (409 Conflict):
{
"error": {
"code": "duplicate_application",
"message": "A candidate with email 'marcus.chen@example.com' already has an application for this job",
"existing_job_application_id": 37562
}
}
Returned by the Apply and Import endpoints when a candidate with the same email already has an application for the specified job. The existing_job_application_id field provides the ID of the existing application.
Missing required parameter (422 Unprocessable Entity):
{
"error": {
"code": "missing_parameter",
"message": "hiring_stage_id is required"
}
}
Invalid request (422 Unprocessable Entity):
{
"error": {
"code": "invalid_request",
"message": "Job application is already in this hiring stage"
}
}
Validation error (422 Unprocessable Entity):
{
"error": {
"code": "validation_error",
"message": "Validation failed",
"details": {
"email": ["is invalid"],
"resume": ["is required"],
"question_responses": [
"question with id 2087 is required"
]
}
}
}
Validation errors include a details object where each key is a field name and the value is an array of error messages for that field.
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
| missing_api_key | 401 | No API key provided in the Authorization header |
| invalid_api_key | 401 | The provided API key is not valid |
| invalid_parameter | 400 | An unrecognized query parameter was sent |
| resource_not_found | 404 | The requested resource does not exist |
| forbidden | 403 | You do not have permission to modify this resource |
| duplicate_application | 409 | A candidate already has an application for this job |
| missing_parameter | 422 | A required parameter was not provided |
| invalid_request | 422 | The request is invalid for the current state |
| validation_error | 422 | One or more fields failed validation (see details) |