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

# Sending applications through posting inquiry

> Fetch the live application form for a job posting and submit a candidate application against it.

## Overview

A posting inquiry is the call you make at the moment a candidate wants to apply. It hands you the application form as it stands right now, together with a token that submits exactly that form, for one candidate. This is the default flow for AI Apply and has the benefit that it guarantees you use the most up-to-date version of the form and does not require you to implement complex sync logic.

This flow follows three steps:

1. You inquire about a specific job posting when a candidate opens the application form on your side. You receive the form to show to the candidate and a token for later submission.
2. You show the candidate the form and collect their answers.
3. You send the collected answers to Kombo using the submission token.

Kombo will then deliver the application and send you a [webhook](/ai-apply/webhooks#application-updated-webhook) once the application is completed.

This guide assumes the postings already exist. Get them there with [job feeds](/ai-apply/job-feeds) or by [creating them manually](/ai-apply/manual-management).

### When to use it

We recommend using this flow by default.

Use the [GET Job Postings Forms](/ai-apply/v1/get-postings-forms) endpoint and flow only when you specifically need to know *all* application forms before the candidate interacts with your product.

<Tip>
  Both paths end at the same [POST Apply](/ai-apply/v1/post-apply) call. The
  only difference is where the form and the token came from.
</Tip>

## How it works

```mermaid theme={null}
sequenceDiagram
    participant You
    participant Kombo
    You->>Kombo: POST inquire (posting id)
    Kombo-->>You: Application form + single-use token
    You->>You: Show the form, collect answers
    You->>Kombo: POST apply (token + answers)
    Kombo-->>You: Application id, status PENDING
    Kombo->>You: Application status updated webhook
```

## Syncing job postings

An inquiry requires the ID of an applyable posting, so your system needs a current list of the postings in your environment. Paginate through [GET Job Postings](/ai-apply/v1/get-postings) to build that list, and keep it current with the data-changed webhook and the `updated_after` filter as described in [Data fetching](/ai-apply/webhooks#data-changed-webhook).

## Getting the application form

[POST Inquiries](/ai-apply/v1/post-postings-posting-id-inquire) takes the posting ID in the path and returns the form with a token:

```json theme={null}
{
  "application_form": [
    {
      "block_type": "SECTION",
      "label": "Personal Information",
      "children": [
        {
          "block_type": "QUESTION",
          "question_id": "6VrjehyBk685vubNydiR1hSn",
          "label": "First name",
          "required": true,
          "question_type": "TEXT",
          "unified_key": "FIRST_NAME",
          "options": null,
          "display_when": null
        }
      ]
    }
  ],
  "submission_token": "<token>"
}
```

See [The Application Form](/ai-apply/introduction#the-application-form) for the full block structure, the unified keys, and how `display_when` drives conditional questions.

<Note>
  Inquiring re-checks the job posting's availability before returning. A posting
  that went offline since your last sync fails here rather than after the
  candidate has filled out the form.
</Note>

You do not need to specifically reconcile error responses due to unavailability with your stored data if you use the AI Apply data-changed webhook. You will receive a webhook instead.

## The token

The `submission_token` is a JWT bound to three things: the job posting, the exact form version you were handed, and your environment.

* **It is single use.** Once an application exists for it, submitting again fails.
* **It expires after two days.**
* **It belongs to one form.** Store it next to the form it arrived with. Your answers are validated against that exact version.

<Warning>
  Do not fetch a token ahead of time and hold it. A token is cheap to request
  and tied to a form that can change, so inquire it only when a candidate is
  actively interacting with the form on your page.
</Warning>

## Sending an application

[POST Apply](/ai-apply/v1/post-apply) takes the token and the answers:

```json theme={null}
{
  "submission_token": "<token>",
  "candidate_email": "john.doe@gmail.com",
  "screening_question_answers": [
    {
      "question_id": "6VrjehyBk685vubNydiR1hSn",
      "answer": "John"
    }
  ]
}
```

| Field                        | Required | Behavior                                                                                                                        |
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `submission_token`           | Yes      | The token from the inquiry, paired with the form you answered.                                                                  |
| `candidate_email`            | Yes      | Supply this from your own system. Do not ask for it on the form. It does not prevent duplicate applications.                    |
| `screening_question_answers` | Yes      | One entry per answered question. See [Candidate answers](/ai-apply/introduction#candidate-answers) for formats.                 |
| `query_params`               | No       | Appended to the job posting URL when applying. See [Query parameters](/ai-apply/introduction#query-parameters-in-applications). |
| `additional_clicks`          | No       | Simulates the job being opened this many extra times, scattered over 60 minutes by default.                                     |

Answers have to match the form the token was issued with. A question ID that is not in that form, or a missing required answer, is rejected rather than ignored.

## Return value and webhooks

Applying is asynchronous. The response confirms we accepted the application and queued it:

```json theme={null}
{
  "id": "ADbmw5XSkeCSE1fAucoxEGnwZ",
  "posting_id": "JDn252PEYa4rMhKbJBjtn3ng",
  "status": "PENDING",
  "created_at": "2025-01-01T00:00:00.000Z",
  "updated_at": "2025-03-02T23:12:32.000Z"
}
```

Keep the returned `id`. It is how you match this application to webhooks later on.

| Status      | Meaning                                                          |
| ----------- | ---------------------------------------------------------------- |
| `PENDING`   | We are applying, or the application is waiting on manual review. |
| `SUBMITTED` | The application reached the job site.                            |
| `DUPLICATE` | The ATS rejected it because this candidate had already applied.  |
| `FAILED`    | We established that the application cannot be submitted.         |

We emit the [application status updated webhook](/ai-apply/webhooks#application-updated-webhook) on every status except `PENDING`, so one arrives per application once it settles. [GET Applications](/ai-apply/v1/get-applications) is the polling alternative, and carries the same `updated_after` filter as the posting endpoints. See [Webhooks](/ai-apply/webhooks) for payloads.

<Note>
  `proxy_email` is only populated once an application is `SUBMITTED`. See
  [Candidate account creation](/ai-apply/candidate-account-creation) to learn
  when we create an account on the candidate's behalf.
</Note>

A failure does not reach you immediately. Every failed submission goes through Kombo's QA first, and we only report `FAILED` once we have confirmed we cannot submit the application in any way. See [QA Mode](/ai-apply/introduction#qa-mode) for more info.

## API reference

* [POST Inquiries](/ai-apply/v1/post-postings-posting-id-inquire)
* [POST Apply](/ai-apply/v1/post-apply)
* [GET Applications](/ai-apply/v1/get-applications)
* [GET Job Postings Forms](/ai-apply/v1/get-postings-forms)
