Skip to navigation

Multiple Locations

Put one applicant at several locations, screen them once, and track each location separately.

An applicant often fits more than one of a registry’s locations. CONFIRM models that as one candidate with one application per location. Each application has its own status, and the applicant is screened once for all of them.

This page covers the whole cycle: sending an applicant to several locations, adding or moving a location later, recording your own outcome at one location, and the webhooks you receive along the way.

Send an applicant to several locations

Use location_refs (an array) instead of location_ref on POST /candidates:

curl https://api.confirm.global/partner/v1/candidates \
-H "Authorization: Bearer cfk_..." \
-H "Content-Type: application/json" \
-d '{
"external_ref": "cl_app_84323",
"location_refs": ["cl_loc_88213", "cl_loc_88214"],
"first_name": "Rosa",
"last_name": "Delgado",
"phone": "+18135550188",
"address": { "city": "Clearwater", "state": "FL", "postal_code": "33756" },
"consent": { "contact": true },
"webhook_url": "https://hooks.example.com/confirm/2d9e7b10-5c4a-4f3e-8a61-0b7c3e9f4d22"
}'

The response has one entry per location in applications, in the order you sent them:

{
"candidate_id": "6e1b4d27-90af-4c38-b5d2-7a3f8c1e0b94",
"external_ref": "cl_app_84323",
"deduped": false,
"portal_url": "https://app.confirm.global/c/suncoast-nurse-registry/candidates/6e1b4d27-90af-4c38-b5d2-7a3f8c1e0b94",
"applications": [
{
"location_ref": "cl_loc_88213",
"application_id": "a3c58e19-4b7d-4e02-9f61-2d8b0c7e5a13",
"deduped": false,
"screening": "enqueued",
"screening_hold": null,
"webhook_url": "https://hooks.example.com/confirm/2d9e7b10-5c4a-4f3e-8a61-0b7c3e9f4d22"
},
{
"location_ref": "cl_loc_88214",
"application_id": "f70d2b64-1e9c-4a85-b3d7-5c6e8a2f9014",
"deduped": false,
"screening": "enqueued",
"screening_hold": null,
"webhook_url": "https://hooks.example.com/confirm/2d9e7b10-5c4a-4f3e-8a61-0b7c3e9f4d22"
}
]
}

Store each application_id against its location. Every webhook about this applicant names the location it is about.

The rules

  • Exactly one of location_ref or location_refs. Both, or neither, is 400 invalid_request.
  • 1 to 20 locations. A ref repeated in the list is used once.
  • All in the same registry. Locations in different registries fail with 400 location_refs_span_organizations, and the error lists each ref with its organization_ref. Send one request per registry. organization_ref, if you send it, applies to every ref.
  • All or nothing on errors. An unknown ref (404 unknown_location_ref) or a closed location the applicant is not already at (409 location_closed) fails the whole request before anything is created.
  • Idempotent, per location. Each entry has its own deduped. The top-level deduped is true only when every application already existed. The status code is 201 when at least one application was created, 200 when none was.
  • Contact details, consent, address and webhook_url apply to every location in the request.

One screening call

The applicant gets one heads-up SMS and one AI screening call covering every location in the request. They are not called once per location.

  • Each location is scored on its own. After the call, each location gets its own screening.completed webhook, with its own result and tier. Knockout questions count per location: failing one location’s knockout question does not fail the others.
  • Distance is checked per location. If you send the applicant’s address, CONFIRM measures their commute to each location at intake. A location they live too far from is ruled out straight away: its entry reports screening: "skipped_ruled_out", its status becomes rejected (with a candidate.status_changed webhook), and it is left out of the call. The other locations go ahead.
  • Set each location’s pay. A location without a pay rate (pay on POST /locations) skips the pay question on screening calls.

If you send the same applicant again later with another location, and the screening call has not been placed yet, the new location joins that call. Once the call has happened, the new location gets a short follow-up call instead of a second full screening. See follow-up calls.

screening_hold on each entry is "calendar_not_connected" when that location’s call is queued but the workspace has no connected calendar yet, and null otherwise. See the calendar guide.

Add a location later

To put an applicant you already sent at another location, use POST /candidates/{external_ref}/locations:

curl https://api.confirm.global/partner/v1/candidates/cl_app_84321/locations \
-H "Authorization: Bearer cfk_..." \
-H "Content-Type: application/json" \
-d '{ "location_ref": "cl_loc_88214" }'
{
"candidate_id": "9f4c2e81-6d3a-4b7e-a1c2-8e5f0d743b16",
"application_id": "0b6e3f72-5a19-4d8c-a2e4-7c1d9f8b3a60",
"external_ref": "cl_app_84321",
"location_ref": "cl_loc_88214",
"created": true,
"status": "interview",
"screening": "reused",
"moved_from": null,
"portal_url": "https://app.confirm.global/c/suncoast-nurse-registry/candidates/9f4c2e81-6d3a-4b7e-a1c2-8e5f0d743b16"
}

It reuses the screening the applicant already has, and screening tells you how:

screeningMeaning
reusedThe applicant passed a screening that asked every question this location asks. They start at the step after screening here, and that step’s usual messages are sent (for example, an interview booking link). No call is placed.
pendingThere is a completed screening, but it failed, was partial, or doesn’t cover this location’s questions. The application starts at screening, and a follow-up call asks what is missing.
noneNo completed screening to reuse yet, or the applicant was already at this location (created: false). A new application is screened as described in follow-up calls.

screening describes the application when it was created. It does not change when a follow-up call runs; the result reaches you as webhooks.

The new application keeps the applicant’s webhook_url. You receive candidate.location_added. It returns 201 when it creates an application and 200 (created: false) when the applicant was already at that location, so it is safe to replay.

Follow-up calls for locations added later

A location added after the applicant’s screening call does not get a second full screening. It is handled the same way whether you add it (or move the applicant to it) with POST /candidates/{external_ref}/locations (screening of pending or none), send it with POST /candidates after the call happened, or the registry office adds it in CONFIRM:

  • The call hasn’t been placed yet: the new location joins it, and that one call covers it too.
  • The first call is still in progress: the new location waits for it to finish, then carries on as below.
  • Questions left to ask: a short follow-up call asks only the questions the applicant has not already answered.
  • Nothing left to ask: no call is placed. The outcome at the new location is decided from the earlier answers.

Earlier answers carry over only when the question is asked exactly the same way. Each location has its own questions. A question that names a different address (“…at the Clearwater office?” versus “…at the Largo office?”) is a different question and is asked again. A knockout question carries over only when the new location applies the same knockout rule to it, so a failed answer elsewhere counts here only for an identical question. Answers more than 180 days old are asked again.

What the applicant gets. No second heads-up SMS: the follow-up call is not a new application. The usual requirements still apply: the applicant needs contact consent and a valid phone, and the call is held while the workspace has no connected calendar.

What you get. The new location gets its own screening.completed and candidate.status_changed, like any screened location. When the outcome was decided from earlier answers with no call, screening.completed still fires for the new location, and its completed_at is the time of the call the answers came from.

Move an applicant

Add move_from_location_ref to move instead of add:

curl https://api.confirm.global/partner/v1/candidates/cl_app_84321/locations \
-H "Authorization: Bearer cfk_..." \
-H "Content-Type: application/json" \
-d '{ "location_ref": "cl_loc_88214", "move_from_location_ref": "cl_loc_88213" }'

The applicant gets an application at the new location, and the one at the old location is closed. A move is not a rejection: the applicant gets no message about it, and you receive one candidate.location_changed, with no candidate.status_changed → rejected for the location they left.

Both locations must be in the same registry, and the applicant must have an application at move_from_location_ref (404 no_application_at_location otherwise).

Take an applicant off one location

There is no DELETE. To record that an applicant is no longer going ahead at one location, set your outcome there with PATCH /candidates/{external_ref}:

curl -X PATCH "https://api.confirm.global/partner/v1/candidates/cl_app_84321?location_ref=cl_loc_88213" \
-H "Authorization: Bearer cfk_..." \
-H "Content-Type: application/json" \
-d '{ "outcome": "withdrawn", "reason": "Accepted a position closer to home." }'
{
"candidate_id": "9f4c2e81-6d3a-4b7e-a1c2-8e5f0d743b16",
"application_id": "51c0a7de-2f18-4a3e-96b7-1d0c8b2e4a77",
"external_ref": "cl_app_84321",
"location_ref": "cl_loc_88213",
"outcome": "withdrawn",
"status": "rejected",
"changed": true
}
outcomeUse it whenStatus at that location
withdrawnThe applicant pulled out.rejected
not_hiredThe office decided not to hire them.rejected
hiredThe office hired them.hired
  • Only that location changes. The applicant’s other locations carry on as before.
  • CONFIRM sends the applicant nothing about an outcome you set.
  • You get the status change back. It fires candidate.status_changed (rejected or hired) for that location, like any other status change. Deduplicate it against the change you just made.
  • Idempotent. Sending the outcome the application already has returns changed: false and fires nothing.
  • Do-not-contact is final. An applicant CONFIRM has marked do-not-contact returns 409 outcome_conflict.

Pass organization_ref as a second query parameter if the same location ref exists in more than one of your registries.

Placement

When the registry office decides where the applicant goes, they place them at a location in CONFIRM. You receive candidate.placed for that location, with placed_at and placed_via. Placing does not change the applicant’s status and does not close their other locations: another location can still hire the same person later. When the applicant is actually hired, record it with outcome: "hired" (or the registry does it in CONFIRM), and the hired status arrives as candidate.status_changed.

Webhooks at a glance

Every event is about one location and carries its location_ref and application_id. See the webhooks guide for full payloads.

What happenedEvent
The status at one location changed (including from your own PATCH)candidate.status_changed
A screening call’s results are ready, once per location in the callscreening.completed
The office placed the applicant at a locationcandidate.placed
The applicant was added to another locationcandidate.location_added
The applicant was moved between locationscandidate.location_changed