> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paraform.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ParaAI matches sent to you by hiring managers

<Info>
  **Required scopes:** `candidates:read`, `roles:read`, `submissions:read`<br />
  **Rate limit:** `default` tier, 120 requests per minute per key
</Info>

ParaAI matches sent to you: a hiring manager looked at a candidate profile, asked for that specific candidate on a specific role, and Paraform routed the request to you because the candidate is in your CRM. This is a different list from `listRecommendedRolesForCandidate`, where Paraform's model suggests roles; here a person asked.

Each row carries the hiring manager's name and their note on why they want the candidate, the role with its pay and your fee, the candidate, and the deadline. A pending match expires 7 days after it is sent (`daysUntilExpiry`), and unresolved expired matches can pause ParaAI matching for you, so the oldest pending rows are the most urgent.

`actionBucket` says what to do: `new` means nobody has contacted the candidate, `needs_submission` means you marked them contacted but have not submitted, `expired` means the window closed, `closed` means submitted or passed.

`status` narrows the list: `pending` (default), `expired`, `dismissed`, `submitted`, or `all`. Pending matches on closed roles are left out; resolved matches are kept. Rows come back oldest first. A page holds at most 20 matches (`limit`, default 20). Pass `nextCursor` back as `cursor`, with the same `status`, for the next page; `nextCursor` is absent on the last page. The cursor marks a position, so acting on a match between pages does not skip or repeat rows.

`role.feePercent` is null when your agency hides payment from its members; agency owners always see it. `role.urls.recruit` is null until you are approved on the role.

When `role.company.confidentialSearch` is true the search is confidential: candidate-facing copy must refer to the employer as `role.company.anonymizedName` and must not name the company or quote copy that identifies it.

This endpoint is read-only; contacting, passing and submitting happen in the Paraform app.

## Query parameters

<ParamField query="status" type="string" default={"pending"}>
  Which matches to return: pending (default), expired, dismissed, submitted, or all.
  Allowed values: `pending`, `expired`, `dismissed`, `submitted`, `all`.
</ParamField>

<ParamField query="cursor" type="string">
  The `nextCursor` of the previous page, sent back verbatim. Omit for the first page.
  Constraints: min length 1, max length 2048.
</ParamField>

<ParamField query="limit" type="integer" default={"20"}>
  Matches per page, at most 20. A larger value returns 20.
  Constraints: minimum 1.
</ParamField>

## Response

<ResponseField name="recommendations" type="object[]" required>
  <Expandable title="recommendations properties">
    <ResponseField name="id" type="string" required />

    <ResponseField name="status" type="string" required>
      pending, submitted, dismissed or expired.
    </ResponseField>

    <ResponseField name="actionBucket" type="string" required>
      What to do next: new, needs\_submission, expired or closed. See the endpoint description.
      Allowed values: `new`, `needs_submission`, `expired`, `closed`.
    </ResponseField>

    <ResponseField name="sentAt" type="string" required>
      When the hiring manager sent the match (ISO 8601).
    </ResponseField>

    <ResponseField name="daysUntilExpiry" type="number | null" required>
      Whole days until a pending match expires, 0 on its last day; null once resolved.
    </ResponseField>

    <ResponseField name="reachedOutToCandidate" type="boolean" required>
      Whether you marked the candidate as contacted.
    </ResponseField>

    <ResponseField name="hiringManagerNote" type="string | null" required>
      The hiring manager's own words on why they want this candidate.
    </ResponseField>

    <ResponseField name="hiringManagerName" type="string" required>
      The hiring manager who sent the match.
    </ResponseField>

    <ResponseField name="candidate" type="object" required>
      <Expandable title="candidate properties">
        <ResponseField name="candidateId" type="string" required>
          Pass to getRecruiterCandidate for the full profile. That returns 404 if the candidate has since left your CRM.
        </ResponseField>

        <ResponseField name="name" type="string" required />

        <ResponseField name="title" type="string | null" required />

        <ResponseField name="oneLiner" type="string | null" required />

        <ResponseField name="location" type="string | null" required />

        <ResponseField name="linkedinUrl" type="string | null" required />
      </Expandable>
    </ResponseField>

    <ResponseField name="role" type="object" required>
      <Expandable title="role properties">
        <ResponseField name="id" type="string" required />

        <ResponseField name="name" type="string" required />

        <ResponseField name="urls" type="object" required>
          browse is the role page; recruit is your workspace on the role, null until you are approved.

          <Expandable title="urls properties">
            <ResponseField name="browse" type="string" required />

            <ResponseField name="recruit" type="string | null" required />
          </Expandable>
        </ResponseField>

        <ResponseField name="locations" type="string[]" required />

        <ResponseField name="company" type="object" required>
          <Expandable title="company properties">
            <ResponseField name="name" type="string" required />

            <ResponseField name="confidentialSearch" type="boolean" required>
              True for a confidential search: candidate-facing copy uses `anonymizedName`, never `name`.
            </ResponseField>

            <ResponseField name="anonymizedName" type="string | null" required>
              What to call the employer in candidate-facing copy; null unless confidential.
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name="compensation" type="object" required>
          <Expandable title="compensation properties">
            <ResponseField name="salaryLowerBound" type="number | null" required />

            <ResponseField name="salaryUpperBound" type="number | null" required />

            <ResponseField name="currency" type="string | null" required />
          </Expandable>
        </ResponseField>

        <ResponseField name="feePercent" type="number | null" required>
          Your placement fee as a percent of first-year salary, null when your agency hides payment.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="application" type="object" required>
      How far your submission got, once submitted.

      <Expandable title="application properties">
        <ResponseField name="progressLabel" type="string | null" required>
          Where the submission stands: Submitted, First round, Mid round, Final round, Offer, Hired or Rejected. Null until submitted.
        </ResponseField>

        <ResponseField name="rejectedAfterStage" type="string | null" required>
          For a rejected submission, the furthest stage it reached, as a progressLabel value. Null unless rejected.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="nextCursor" type="string">
  Absent on the last page. Opaque: send it back verbatim as `cursor`.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET "https://external-api.paraform.com/api/external/v1/recruiter/paraai-recommendations?status=pending&limit=20" \
    -H "Authorization: Bearer $PARAFORM_API_KEY"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "recommendations": [
      {
        "id": "string",
        "status": "string",
        "actionBucket": "new",
        "sentAt": "string",
        "daysUntilExpiry": 0,
        "reachedOutToCandidate": true,
        "hiringManagerNote": "string",
        "hiringManagerName": "string",
        "candidate": {
          "candidateId": "string",
          "name": "string",
          "title": "string",
          "oneLiner": "string",
          "location": "string",
          "linkedinUrl": "string"
        },
        "role": {
          "id": "string",
          "name": "string",
          "urls": {},
          "locations": [],
          "company": {},
          "compensation": {},
          "feePercent": 0
        },
        "application": {
          "progressLabel": "string",
          "rejectedAfterStage": "string"
        }
      }
    ]
  }
  ```
</ResponseExample>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.