# Company Career Portal / ATS Integration

## Purpose

Each company remains an independent tenant. The company keeps its own career portal and ATS. Only candidates that the company chooses to forward are created or mapped in the assessment platform.

The integrating company's backend authenticates with a Client ID and Client Secret issued from **Company Portal -> API Integrations**. The API client is permanently linked to one `company_id`. The caller never sends or selects `company_id` in the external API, so Company A credentials cannot request Company B data.

## Recommended flow

```text
Candidate applies on Company Career Portal
          |
          v
Company ATS stores resume/application
          |
          v
Company ATS shortlists candidate
          |
          v
Company BACKEND calls Assessment API
POST /api/integrations/v1/invitations
          |
          v
Assessment platform derives company_id from API credentials
          |
          +--> map/create candidate inside that company
          +--> resolve published paper by company + paper_code
          +--> create assignment idempotently
          |
          v
Response: login User ID + temporary password (new candidate only)
          + assessment_url
          |
          v
Company emails/SMSs credentials and assessment link
          |
          v
Candidate opens assessment_url
          |
          v
Numeric User ID + Password -> OTP -> Exam
          |
          v
Timed sections -> scoring/manual review
          |
          v
Signed webhook to Company ATS
          |
          v
Company ATS updates candidate stage
```

## 1. Obtain credentials

A Company Admin signs in to the Company Portal and opens **API Integrations**. Create an integration client and securely store:

- `X-Client-Id`
- `X-Client-Secret`
- Webhook secret

The Client Secret must stay on the company server. Never place it in React, browser JavaScript, Flutter, Android, iOS, or a public Git repository.

## 2. List published papers

```http
GET /api/integrations/v1/papers
X-Client-Id: cmp_xxxxx
X-Client-Secret: xxxxx
```

The company maps its job/requisition to one of the returned `paper_code` values.

Example mapping in the company ATS:

```text
JOB-1008 -> MERN-DEV-01
JOB-1009 -> QA-AUTOMATION-01
```

Paper codes are unique only inside a company, so another company may use the same code without conflict.

## 3. Forward a shortlisted candidate using one API call

```http
POST /api/integrations/v1/invitations
Content-Type: application/json
X-Client-Id: cmp_xxxxx
X-Client-Secret: xxxxx
```

```json
{
  "external_candidate_id": "ATS-CAND-88442",
  "external_assignment_id": "ATS-TEST-99210",
  "paper_code": "MERN-DEV-01",
  "first_name": "Rahul",
  "last_name": "Kumar",
  "email": "rahul@example.com",
  "phone": "9876543210",
  "job_title": "Software Engineer",
  "expires_at": "2026-09-01 23:59:59",
  "metadata": {
    "job_id": "JOB-1008",
    "application_id": "APP-49028",
    "source": "career_portal"
  }
}
```

For a new candidate the response contains a numeric login User ID and a one-time temporary password:

```json
{
  "success": true,
  "created": true,
  "assignment_id": 88,
  "external_assignment_id": "ATS-TEST-99210",
  "candidate_id": 25,
  "external_candidate_id": "ATS-CAND-88442",
  "login_user_id": 58241729,
  "temporary_password": "...",
  "assessment_url": "https://assess.example.com/exam/88",
  "login_url": "https://assess.example.com/login",
  "expires_at": "2026-09-01 23:59:59",
  "status": "assigned"
}
```

If the same `external_assignment_id` is sent again with the same company credentials, the API returns the existing assignment instead of creating a duplicate. This makes the handoff idempotent and safe to retry after a network failure.

If the candidate already exists under that company's `external_candidate_id`, the existing login is reused and `temporary_password` is `null`/omitted. The company should follow its established credential recovery/reset process rather than trying to create a second candidate account.

## 4. Candidate redirect behavior

The company may send the returned `assessment_url` directly to the candidate. If the candidate is not logged in, the React route guard sends the candidate to `/login`, stores the intended exam route, and returns the candidate to the correct assessment after numeric User ID + password + OTP verification.

Do not put the Client Secret or temporary password in URL query parameters.

## 5. Status polling fallback

```http
GET /api/integrations/v1/assignments/ATS-TEST-99210/status
X-Client-Id: ...
X-Client-Secret: ...
```

Possible statuses include:

- `assigned`
- `in_progress`
- `evaluation_pending`
- `completed`
- `expired`
- `cancelled`

## 6. Result retrieval

```http
GET /api/integrations/v1/assignments/ATS-TEST-99210/result
X-Client-Id: ...
X-Client-Secret: ...
```

The lookup is always `company_id + external_assignment_id`, so the same external ID may safely exist in another tenant.

## 7. Webhook update to the company's ATS

Configure a webhook URL such as:

```text
https://careers.company.com/api/webhooks/assessment
```

The assessment platform sends:

```http
X-Assessment-Event: assessment.completed
X-Assessment-Signature: <HMAC-SHA256>
```

The signature is HMAC-SHA256 over the exact raw JSON body using the webhook secret. Verify it before processing the event.

The webhook payload contains the `external_candidate_id` and `external_assignment_id`, allowing the company to update its own ATS record without storing the assessment platform's internal IDs.

## 8. Tenant isolation and assignment guarantees in v3

- Company staff users carry exactly one `company_id`.
- Platform Super Admin has no company tenant and uses separate platform routes.
- External API `company_id` is derived only from the authenticated API client.
- Candidate, question, paper, assignment, result and API-client queries are scoped by company.
- Manual answer scoring verifies the answer's assignment belongs to the reviewer company.
- Candidate exam access validates both the candidate and company tenant.
- Database composite foreign keys prevent an assignment from pairing a Company A candidate with a Company B paper.
- Paper codes are unique per company, not globally.
- Suspended companies cannot authenticate through staff login or API credentials.
- Random papers are frozen into `assignment_questions` when an assignment is created, so retries, refreshes, or later candidate sessions do not silently reshuffle that candidate.
- Candidate exam APIs return only candidate-safe metadata and never evaluator reference answers, rubrics, hidden coding test cases, or correct objective answers.

## 9. Company-side responsibilities

The company should store at minimum:

```text
external_candidate_id
external_assignment_id
paper_code
assessment_url
assessment_status
assessment_percentage
assessment_result
assessment_completed_at
```

The company should never store the Assessment API Client Secret in its frontend database payloads or browser local storage. Keep secrets in server environment variables or a secrets manager.
