Overview
GLYDE Unity provides a unified integration with erecruit's WebApi (API v2, erecruit 3.1+), exposing candidate records, internally posted positions, candidate applications, and the full application→submission→placement pipeline through a single ATS-agnostic API layer.
The integration spans the full GLYDE ecosystem: Microsoft Teams, Copilot for Microsoft 365,
Power Automate, the GLYDE Unity SDK, and the Model Context Protocol (MCP) for AI agent
consumption. All operations are tenant-isolated using client_uuid and
authenticated via OAuth2 client-credentials tokens with fully automatic token management.
erecruit data flows through GLYDE Unity's index-centric normalization pipeline,
ensuring consistent data representation across all consumers regardless of erecruit's native
conventions — PascalCase payloads, integer entity IDs, and the merged Match
pipeline record that collapses application, submission, and placement into one expanding type.
POST {site-origin}/t/token (grant_type=client_credentials); tokens expire every
10 minutes and are renewed automatically. There is no global fallback credential: every client must
have tenant credentials plus a per-tenant service_url provisioned in Azure Key Vault /
IntegrationData.Product Demos
Short walkthroughs of the GLYDE experience across the surfaces this integration powers.
Watch it work
1 / 5Architecture & Data Flow
GLYDE Unity acts as an orchestration layer between consuming platforms (Teams, Copilot, Power Platform, SDK) and the erecruit WebApi REST API. Requests are authenticated, normalized, and routed through the integration adaptor which handles entity-specific business logic, data mapping, and error classification. The erecruit WebApi exposes no API for registering webhooks, so change events are received through a webhook created manually in the erecruit ATS UI pointing at GLYDE (see Events & Webhooks below); until that is set up, index freshness is maintained through scheduled and on-demand cache refresh rather than inbound events.
Teams / Copilot / Power Platform / SDK / MCP Client
|
v
┌─────────────────────────────────────┐
│ GLYDE Unity REST API │
│ api.glydeunity.com/api/unity/* │
│ │
│ ┌─ Auth Middleware ─────────────┐ │
│ │ API Key / JWT / Trusted App │ │
│ │ Role-based access control │ │
│ └──────────────────────────────┘ │
│ │
│ ┌─ Workflow Route Handler ──────┐ │
│ │ Validation + Orchestration │ │
│ └──────────────────────────────┘ │
│ | │
│ v │
│ ┌─ erecruit Integration Adaptor┐ │
│ │ candidates.ts / applications│ │
│ │ Template Method Pattern │ │
│ │ Index-centric data mapping │ │
│ └──────────────────────────────┘ │
│ | │
│ v │
│ ┌─ erecruit External Connector ─┐ │
│ │ erecruit-connector.ts │ │
│ │ ConnectorAuthManager (Bearer)│ │
│ │ OpenAPI-driven operations │ │
│ │ ICanonicalEntityOperations │ │
│ └──────────────────────────────┘ │
│ (inbound events via manual │
│ ATS-UI webhook + scheduled │
│ cache refresh) │
└──────────────|──────────────────────┘
|
v
┌──────────────────────────────────────┐
│ erecruit WebApi REST API │
│ https://.erecruitcloud.com │
│ │
│ Candidate | Position | │
│ CandidateApplication | Match | │
│ Company | Contact | Attachment │
└──────────────────────────────────────┘
Teams, Copilot, Power Automate, or the SDK sends a request to the GLYDE Unity API (e.g., GET /api/unity/candidates/:candidateUUID) with API key + user context headers.
Unity validates the API key, resolves client_uuid and user_uuid, checks role-based access, and routes to the appropriate workflow handler.
The workflow handler calls getIntegrationAdaptor('erecruit') to obtain the erecruit-specific adaptor based on the client's configured ATS integration type.
The ConnectorAuthManager automatically mints short-lived bearer tokens for the client's erecruit tenant via POST {site-origin}/t/token (grant_type=client_credentials, client_id + client_secret). Sessions are cached in Redis and rotated before the 10-minute token expiry.
The erecruit connector executes the operation against the WebApi using the cleaned OpenAPI specification for request validation and dynamic operation handling. All calls carry Authorization: Bearer {access_token}.
Response data flows through the index-centric pipeline: ATS response → CandidateDataMapper / JobDataMapper / ApplicationDataMapper (driven by types/erecruit/mapping-profile.ts) → canonical index schema. PascalCase fields, _expanded hydration, and integer IDs are resolved entirely inside the mapping profile.
The normalized response is returned to the consuming platform in the GLYDE Unity standard response format, with consistent snake_case field names and structures regardless of erecruit's PascalCase conventions.
Once the manual ATS-UI webhook is configured, candidate/position/application change events flow into the GLYDE event pipeline and keep the Azure AI Search indexes current. Without the webhook, the indexes are maintained through TTL-based cache capabilities (14,400s hint) and scheduled/on-demand refresh via the ATS search-cache pipeline.
Authentication
OAuth2 Client Credentials (POST {site-origin}/t/token)
erecruit's WebApi (API v2, erecruit 3.1+) uses OAuth2 client-credential token auth.
GLYDE Unity's ErecruitConnectorAuthManager (extending BaseBearerTokenAuthManager) handles
the complete token lifecycle automatically: it POSTs a form-encoded
grant_type=client_credentials&client_id=…&client_secret=…&scope={site-origin} body to
{site-origin}/t/token and uses the returned access_token as the bearer token on every
subsequent call (Authorization: Bearer {access_token}). Clients never need to manage tokens directly.
Credentials are API service credentials for an application registered in the erecruit control panel; per-call
permissions are provisioned via Manage API Permissions.
Naming note: the swagger document's info.version string reads "v1" — that is the
DOC version, not the legacy RESTServices API v1 product (a separate XML/cookie surface at
/RestServices, available only for erecruit 3.0 and earlier). The /webapi swagger
is the WebApi product documentation, and POST {site-origin}/t/token was verified live on
the Nelson Connects sandbox (standard OAuth2 unauthorized_client response for dummy credentials);
the checked-in cleaned spec matches the live tenant path-for-path (198 paths / 230 operations).
Credential Fields
| Field | Description | Required |
|---|---|---|
client_id |
Client ID of the application registered in the erecruit control panel | Yes |
client_secret |
Client secret issued for the registered application | Yes |
service_url |
Base URL for the tenant's erecruit WebApi, e.g. https://nelsonupgrade.erecruitcloud.com/webapi — erecruit hosts are per-tenant, so this is effectively required (ERECRUIT_API_URL env is a deployment-level fallback only) | Yes |
tenant |
Optional tenant EntityID — legacy v1 context only; NOT required for v2 token auth | No |
Session Management
Sessions are cached in Redis with the key pattern session:client:{client_uuid}:integration:erecruit.
The session stores the bearer access token, expiration timestamp, resolved base URL, and optional entity id. There is no
global fallback credential — every tenant must have credentials provisioned in Azure Key Vault / IntegrationData
(getDefaultAuthConfig throws).
Token Refresh
Access tokens expire every 10 minutes per the Bullhorn KB; the token response's
expires_in is honored (600s default when omitted). Sessions rotate automatically: the 5-minute validity
buffer re-mints the token well before expiry, and a 401 from the ATS triggers clearRedisSessionOnly()
and a single retry with a freshly minted token.
Capabilities
📦 Two API layers, one integration
This integration exposes erecruit through two distinct layers, and every capability below tells you which layer it runs on. Reading the table without this context is the most common source of confusion, so here is the distinction:
1. GLYDE Unity workflow endpoints (the Endpoint column) are GLYDE's own, ATS-agnostic APIs
(/api/unity/*). They are the recommended path for every consumer — Teams, Copilot, Power Automate, the Chrome Extension, and the SDK.
Each one is an orchestrated workflow: GLYDE handles authentication, tenant isolation, validation, data normalization into GLYDE's canonical format,
database sync, and search indexing. You talk to GLYDE in GLYDE's vocabulary; GLYDE talks to the ATS behind the scenes.
2. ATS proxied calls (the ATS Op column) are the raw erecruit REST operations the workflow
invokes under the hood. You normally never call these directly — but you can, through the
ATS proxy (/api/unity/proxy/erecruit/:operationId and the discover/inspect meta-operations).
The proxy executes any operation from erecruit's OpenAPI specification verbatim: request and response shapes are the vendor's own,
no GLYDE normalization is applied. Use it for advanced or niche operations GLYDE has not (yet) wrapped in a workflow — it inherits GLYDE's
authentication, tenant isolation, and OAuth token management, but you are speaking the vendor's dialect, so field names, casing, and payloads match
the erecruit spec exactly.
Rule of thumb: start with the workflow layer; drop to the proxy only when a workflow for what you need does not exist.
Status badges on each capability card grade the workflow layer coverage for that entity:
- full — complete workflow coverage: create, read, update (where the ATS API allows it), and GLYDE-side persistence/indexing all work.
- partial — the entity is supported, but one or more workflow operations are unavailable, not supported by the ATS API itself, or served differently (e.g. reads resolved from the GLYDE search index instead of a live ATS call, missing job-note support, or a
NOT_IMPLEMENTEDupdate). Read each operation's notes for the specific gap. The raw operations may still be reachable through the ATS proxy. - proxy only — no GLYDE workflow wraps this entity; access is exclusively via raw proxied ATS calls with vendor-native payloads.
- not supported — neither a workflow nor a usable proxy operation exists for this entity.
| Operation | Endpoint | ATS Op |
|---|---|---|
| Get Candidate Index-first retrieval by GLYDE UUID or ATS candidate ID with live/Redis cache merge |
GET /api/unity/candidates/:candidateUUID |
Candidate_Get |
| Search Candidates (Live Reinforcement) Weighted search fusing GLYDE indexes with a live erecruit candidate list |
POST /api/unity/search/searchCandidates |
Candidate_List |
| Find Candidate (Dedup Lookup) Deterministic lookup (email → phone → name) used by create-or-reuse flows |
internal internal (createOrReuseCandidate) |
Candidate_List / Candidate_ByName |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Search Jobs (Live Reinforcement) Weighted search fusing the GLYDE jobs index with live internally posted positions |
POST /api/unity/search/searchJobs |
Position_GetInternallyPosted |
| Get Job Retrieved from the GLYDE search index (no live get-by-id fetch hook on the adaptor) |
GET /api/unity/jobs/:jobUUID |
None (index-only) |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Create Application Link a candidate to a position with a new CandidateApplication record |
POST /api/unity/applications |
CandidateApplication_Post |
| List Applications by Candidate Canonical candidate-scoped application list feeding the ATS search-cache pipeline |
internal internal (ats-search-cache pipeline) |
CandidateApplication_GetByCandidateId |
| List Applications by Position Position-scoped application list — reachable through the ATS proxy |
proxy /api/unity/proxy/erecruit/CandidateApplication_GetByPositionId |
CandidateApplication_GetByPositionId |
| Find Application Candidate- or job-scoped application lookup on the ATS-agnostic filter surface |
POST /api/unity/applications/find |
CandidateApplication_GetByCandidateId / GetByPositionId |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Pipeline Records by Candidate Application→submission→placement pipeline records for one candidate |
proxy /api/unity/proxy/erecruit/Match_GetByCandidateId |
Match_GetByCandidateId |
| Pipeline Record by ID Read one match (pipeline) record by integer ID |
proxy /api/unity/proxy/erecruit/Match_GetById |
Match_GetById |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Send Email Send email via Mailgun through the base messages adaptor |
POST /api/unity/messages/send-email |
Mailgun (no erecruit activity write-back) |
| Send SMS Send SMS via Twilio through the base messages adaptor |
POST /api/unity/sms/send |
Twilio (no erecruit activity write-back) |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Search Companies Search the GLYDE company/client directory (name, industry, status, location) across connected tenants |
POST /api/unity/search/searchCompanies |
GLYDE directory index (ats-cache-company-index) |
| Search Contacts Search the GLYDE contact directory (names, emails, phones, titles) with denormalized company references |
POST /api/unity/search/searchContacts |
GLYDE directory index (ats-cache-company-index) |
| Company / Contact Pickers value/label option lists powering dynamic lookup dropdowns in Power Automate and Make.com |
POST /api/unity/directory/companyOptions + /api/unity/directory/contactOptions |
Directory search legs |
| Import Directory Rows Merge parsed company/contact rows into the directory from any source format (CSV, TSV, pasted text, Excel copied as text) — the calling model converts the source into structured rows |
POST /api/unity/directory/ingest |
Directory index mergeOrUpload (origin: import) |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Weighted Candidate Search Fused GLYDE index + live erecruit candidate search with ranking |
POST /api/unity/search/searchCandidates |
Candidate_List (live reinforcement) |
| Weighted Job Search Fused GLYDE index + live erecruit position search with ranking |
POST /api/unity/search/searchJobs |
Position_GetInternallyPosted (live reinforcement) |
| Conversational AI Search Natural-language search across candidates and jobs using GLYDE AI |
POST /api/unity/search/conversationalAISearch |
Azure AI Search Index (not direct ATS) |
| Index Query Structured OData queries against tenant-scoped GLYDE indexes |
POST /api/unity/search/aiSearchIndex |
Azure AI Search Index |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Discover Operations List all available erecruit WebApi operations (230 across 198 paths) with schemas and metadata |
GET /api/unity/proxy/discover/erecruit |
OpenAPI spec introspection |
| Inspect Operation Full specification for one erecruit operation |
GET /api/unity/proxy/inspect/erecruit/:operationId |
OpenAPI schema introspection |
| Execute Operation Execute any of the 230 erecruit spec operations dynamically with vendor-native payloads |
POST /api/unity/proxy/erecruit/:operationId |
Dynamic (per operationId) |
| Entity Metadata Field-level metadata for an erecruit entity type, including designer-bound lookup catalogs |
GET /api/unity/proxy/meta/erecruit/:entity |
OpenAPI schema + fieldValueOperations |
| Operation | Endpoint | ATS Op |
|---|---|---|
| Receive Event Webhook Inbound erecruit change events via a webhook created manually in the erecruit ATS UI (the WebApi has no subscription-registration endpoints) |
POST /api/unity/events/webhook/:client_uuid/erecruit |
Manual ATS-UI webhook (Candidate.* / Position.* / CandidateApplication.*) |
Platform Access
GLYDE Unity provides unified access to erecruit across multiple Microsoft 365 and developer platforms.
Access erecruit data through the GLYDE Unity bot in Teams channels and chats.
Access: Teams Bot Framework → GLYDEBuddy Proxy → Unity REST API → erecruit Adaptor
- Search candidates and jobs via conversational AI
- View candidate profiles with live erecruit field merge
- Review application status and the Match pipeline stage
- Send emails and SMS through GLYDE-native channels
Use natural language to interact with erecruit data through the GLYDE Copilot declarative agent.
Access: Copilot Agent → MCP Bridge (GLYDEBuddy) → Unity REST API → erecruit Adaptor
- Natural language queries ("Show me internally posted positions")
- Tier-1 weighted searches with live erecruit reinforcement
- ATS proxy operations for advanced queries (discover → inspect → execute)
- Entity aliasing resolves GLYDE terms to erecruit vocabulary (job → Position, submission/placement → Match) via atsProfile
- Operation hints steer agents to the right list/read operation (Candidate_List vs Candidate_Get, etc.)
Automate erecruit workflows using the GLYDE Unity Power Platform connector.
Access: Power Platform Connector → Unity REST API → erecruit Adaptor
- Create applications linking candidates to positions
- Run weighted candidate and job searches
- Execute any erecruit spec operation through the ATS proxy
- Designer-bound dropdowns for StatusID / TypeID / RatingID and other lookups via cached inspect inputs
- Note: ATS change triggers depend on the manual ATS-UI webhook being configured (see Events & Webhooks); without it, use polling schedules
Programmatic access via the @glydeunity/glyde-api-client npm package.
Access: SDK Client → Unity REST API → erecruit Adaptor
- Type-safe TypeScript API client with Zod validation
- FlexibleUnityApi for multiple input formats (UUID, ATS ID, object)
- Direct workflow operations and ATS proxy access
- Automatic authentication and session management
- OpenAPI-generated client with full IntelliSense
AI agents and LLMs access erecruit operations through the MCP interface.
Access: MCP Client → Unity MCP Endpoints → Workflow Handlers → erecruit Adaptor
- 100+ discoverable tools auto-generated from workflow routes
- ATS proxy tools for dynamic operation discovery and execution
- Entity metadata tools for field-level schema inspection
- Filtered schemas (x-NoMCP fields excluded for security)
- JSON-RPC and REST invocation protocols
Voice-based interaction for candidate screening and job discovery (ATS-agnostic).
Access: Voice SDK → Unity Voice API → Deepgram → Function Execution
- Voice-powered candidate screening interviews
- Job discovery and application via voice
- Real-time candidate creation during conversations
- OTP verification for candidate identity
Entity Mappings
erecruit uses different entity names and field conventions. GLYDE Unity normalizes these through the index-centric data pipeline.
Candidate → Candidate
| Unity Field | erecruit Field | Direction | Notes |
|---|---|---|---|
first_name |
First |
Read | — |
last_name |
Last |
Read | — |
middle_name |
Middle |
Read | — |
last_job_title |
Title |
Read | — |
last_employer |
CurrentEmployer |
Read | — |
availability |
DateAvailable |
Read | — |
email |
_expanded.Communications[] |
Read | Primary-wins, Category-labelled (email) |
phone |
_expanded.Communications[] |
Read | Primary-wins, Category-labelled (phone/mobile) |
city / state / zip / address |
_expanded.DefaultAddress.{City,State,PostalCode,AddressLine1} |
Read | Requires the expand query parameter |
country |
_expanded.DefaultAddress.Country |
Read | — |
employment_type_preferences |
IsLookingForPerm / IsLookingForContract / IsLookingForContractToPerm |
Read | Boolean flags folded into a preferences array |
ats_candidate_id |
ID |
Read | Integer; candidate_uuid resolved via ExternalMappings |
StatusID / RatingID / AdSource |
StatusID / RatingID / AdSource |
Read | Tracked as lookups (NamedValue catalogs) — not flattened into the index |
Job → Position (PostedPositionResponse)
| Unity Field | erecruit Field | Direction | Notes |
|---|---|---|---|
title |
Title / PositionTitle |
Read | — |
ats_job_id |
ID |
Read | Integer |
description |
WebDescription |
Read | Falls back to _expanded.Description.Text |
status |
_expanded.Status.Name |
Read | StatusID is the raw integer ref; the label only appears when expanded |
employment_type |
PositionType / _expanded.Type.Name |
Read | — |
department |
PrimaryDepartmentName |
Read | — |
company_name / company |
CompanyName / _expanded.Company.Name |
Read | — |
company_id / contact_id |
CompanyID / ContactID |
Read | — |
external_id |
ExternalPositionID |
Read | — |
min_bill_rate / max_bill_rate |
MinBillRate / MaxBillRate |
Read | — |
min_pay_rate / max_pay_rate |
MinPayRate / MaxPayRate |
Read | — |
salary_min / salary_max |
HourlyMin / AnnualMin · HourlyMax / AnnualMax |
Read | — |
start_date / end_date |
StartDate / EndDate |
Read | — |
date_posted / updated |
DatePosted / DateLastOpened |
Read | — |
recruiter_name |
RecruiterName |
Read | — |
city / state / zip / address |
PrimaryAddress.{City,State,PostalCode,AddressLine1} |
Read | Also _expanded.DefaultAddress on PositionResponse |
Application → CandidateApplication
| Unity Field | erecruit Field | Direction | Notes |
|---|---|---|---|
ats_application_id |
ID |
Read | Integer (PascalCase) |
ats_candidate_id |
CandidateID |
Read | — |
ats_job_id |
PositionID |
Read | — |
ats_match_id |
MatchID |
Read | Links to the pipeline (Match) record |
status / ats_status |
Status |
Read | String label (unlike Candidate/Position integer StatusIDs) |
rejection_reason |
RejectionReason |
Read | — |
rejected_on |
RejectedOn |
Read | — |
application_source |
AdSource |
Read | — |
note |
Note |
Read | — |
created / modified |
CreatedOn |
Read | CreatedOn feeds both; no separate modified timestamp |
CandidateID / PositionID (create) |
CandidateApplicationRequest |
Write | Create posts { CandidateID, PositionID, ApplicationSourceID?, ApplicationNote? } to CandidateApplication_Post |
Placement / Submission → Match
| Unity Field | erecruit Field | Direction | Notes |
|---|---|---|---|
(pipeline stage) |
MatchResponse.Status |
Read | Application→submission→placement as ONE expanding record; Status is the stage label ("Submitted", "Placed") |
(hydrated context) |
MatchResponse._expanded |
Read | Carries Candidate / Position / Company / DefaultAddress when expanded |
(link) |
CandidateApplication.MatchID |
Read | Applications link to their pipeline record via MatchID |
Endpoint Reference
| Method | Unity Endpoint | Description | ATS Operation | Auth |
|---|---|---|---|---|
GET |
/api/unity/candidates/:uuid |
Get candidate by ID (live Candidate_Get + cache merge) | Candidate_Get |
API Key + User UUID |
POST |
/api/unity/search/searchCandidates |
Weighted candidate search with live reinforcement | Candidate_List |
API Key + User UUID |
POST |
/api/unity/search/searchJobs |
Weighted job search with live reinforcement | Position_GetInternallyPosted |
API Key + User UUID |
POST |
/api/unity/search/conversationalAISearch |
AI-powered natural language search (GLYDE index) | Azure AI Search |
API Key + User UUID |
POST |
/api/unity/search/searchCompanies |
Search the company/client directory (live erecruit search + GLYDE index) | erecruit directory search |
API Key + User UUID |
POST |
/api/unity/search/searchContacts |
Search the contact directory with denormalized company refs | erecruit directory search |
API Key + User UUID |
POST |
/api/unity/directory/companyOptions |
Company picker options for dynamic lookup | Directory search legs |
API Key + User UUID |
POST |
/api/unity/directory/contactOptions |
Contact picker options, optionally company-scoped | Directory search legs |
API Key + User UUID |
POST |
/api/unity/directory/ingest |
Import parsed company/contact rows (any source format) into the directory | Directory index mergeOrUpload |
API Key + User UUID |
POST |
/api/unity/search/aiSearchIndex |
Structured OData index query | Azure AI Search |
API Key + User UUID |
POST |
/api/unity/applications |
Create application (CandidateApplication_Post) | CandidateApplication_Post |
API Key + User UUID |
POST |
/api/unity/applications/find |
Find applications by candidate/job filter | CandidateApplication_GetByCandidateId / GetByPositionId |
API Key + User UUID |
POST |
/api/unity/messages/send-email |
Send email (Mailgun, no ATS activity write-back) | Mailgun |
API Key + User UUID |
POST |
/api/unity/sms/send |
Send SMS (Twilio, no ATS activity write-back) | Twilio |
API Key + User UUID |
GET |
/api/unity/proxy/discover/erecruit |
Discover all 230 erecruit operations | OpenAPI introspection |
API Key + User UUID |
GET |
/api/unity/proxy/inspect/erecruit/:opId |
Inspect one operation (full spec) | Schema introspection |
API Key + User UUID |
POST |
/api/unity/proxy/erecruit/:opId |
Execute any erecruit spec operation (e.g. Match_GetByCandidateId, Position_GetPosition) | Dynamic |
API Key + User UUID |
GET |
/api/unity/proxy/meta/erecruit/:entity |
Get entity metadata + lookup catalogs | Schema + fieldValueOperations |
API Key + User UUID |
Events & Webhooks
Inbound erecruit change events are supported through a webhook that is created
manually in the erecruit ATS UI — the erecruit WebApi exposes no endpoint for registering
subscriptions programmatically (remote_subscription_supported: false), so a one-time manual
setup in the ATS administration UI is required. Events are processed through the GLYDE ATS event pipeline:
they keep the candidate/job indexes current (gated by the tenant's
event_system.processing.update_ats_cache setting) and are the
primary way candidate records first flow into GLYDE, because the WebApi has no
candidate-enumeration search (listing requires vendor/status/owner filters or an exact name).
Manual webhook setup:
- In the erecruit ATS administration UI, create a webhook (event subscription) for Candidate, Position, and CandidateApplication change events.
- Point it at the GLYDE event receiver for this tenant:
POST https://api.glydeunity.com/api/unity/events/webhook/{client_uuid}/erecruit— the tenant's GLYDEclient_uuidis embedded in the URL, so no tenant resolution is required in the payload. (An alternative form,POST /api/unity/events/webhook/erecruit, exists for senders that pass theclientUuidquery parameter instead.) - Ask GLYDE support to enable the
erecruit-core-eventssubscription on the tenant — it is born disabled on purpose (events arriving before the webhook exists are rejected with 404). After enabling, runPOST /api/unity/activation/verify— the events phase should report healthy and go-live (initial index population) can proceed.
| Event | Trigger | Payload | Automatic Actions |
|---|---|---|---|
Candidate.* |
Candidate record created/updated/deleted in erecruit | Candidate change payload (passthrough-normalized into the GLYDE ATS event format) | Candidate cache refresh: profile re-fetched from the WebApi, normalized, and re-indexed (gated by event_system.processing.update_ats_cache) — also the initial-population path that mints candidate records into the GLYDE index |
Position.* |
Position (job) record changed in erecruit | Position change payload (passthrough-normalized) | Job index refresh + jobs-index ingest so weighted job search reflects the change |
CandidateApplication.* |
Application / Match pipeline record changed in erecruit | CandidateApplication change payload (passthrough-normalized) | Candidate cache refresh + application/pipeline data refresh for the affected candidate and position |
Configuration Requirements
-
erecruit API Service Credentials (Client ID / Client Secret)REQUIRED
Client ID + client secret for an application registered in the erecruit control panel, with the needed calls enabled under Manage API Permissions (per-call permissions). These must be stored in Azure Key Vault via the GLYDE Unity client configuration; there is no global fallback credential.
client_id: "glu-integration-app" -
Tenant service_url (WebApi Base URL)REQUIRED
Per-tenant erecruit WebApi base URL — must include the
/webapipath (e.g.https://<agency>.erecruitcloud.com/webapi): data calls are made against this base, while the token endpoint is derived from the site origin ({origin}/t/token), so a URL missing/webapistill mints tokens but fails every data call. Resolution order: tenantservice_url→ERECRUIT_API_URLenv. The activation wizard’s verification pass (POST /api/unity/activation/verify) live-probes stored credentials with one cheap read call, so a malformed base URL is caught at setup time instead of at first use.service_url: "https://nelsonupgrade.erecruitcloud.com/webapi" -
EntityID (Tenant Identifier, optional)
Legacy v1 context only — NOT required for v2 token auth. Stored as
UnityCredentials.tenantwhen provided.tenant: "3" -
Integration TypeREQUIRED
The client's integration_type must be set to "erecruit" in the GLYDE client configuration for the adaptor router to select the correct integration.
integration_type: "erecruit"
Known Limitations
- Events require manual webhook setup. The erecruit WebApi has no subscription-registration endpoints, so the inbound webhook must be created manually in the erecruit ATS UI pointing at
POST /api/unity/events/webhook/{client_uuid}/erecruit, and theerecruit-core-eventssubscription enabled by GLYDE support (it is born disabled). Until then, index freshness relies on TTL + scheduled cache refresh, and candidate records only enter GLYDE through searches and explicit reads. - No candidate-enumeration search.
Candidate_Listrequires at least one ofVendorID/StatusIDs/OwnerID, andCandidate_ByNameis an exact First+Last lookup — the WebApi has no "list all candidates" operation, which is why inbound events are the primary initial-population path for candidates. - No server-side pagination on core lists.
Candidate_List,Position_GetInternallyPosted, and the CandidateApplication list operations return the FULL list — filter client-side. - No keyword search. Search is structured-filter only (
VendorID,StatusIDs,OwnerID, name parts).searchCapabilities.supportsKeywordSearchisfalse; keyword-style discovery is served from the GLYDE Azure AI Search index. - Field names are PascalCase (
First,Last,ID,StatusID) — not camelCase or snake_case. All mapping lives intypes/erecruit/mapping-profile.ts. - Entity IDs are integers; Match/CandidateApplication cross-reference them via
CandidateID/PositionID/MatchID. - Match is the pipeline record: application → submission → placement as ONE expanding record (
Statusis the stage label). There is no separate GLYDE placement entity — Match is registered withcanonicalEntity: "other". - Auth uses API service credentials (client_id + client_secret for an application registered in the control panel, permissions via Manage API Permissions);
POST {site-origin}/t/tokenreturns the beareraccess_token. - Access tokens expire every 10 minutes — sessions rotate automatically off the response
expires_in(600s default) and the 5-minute validity buffer. - Status labels require expansion. Candidate/Position records carry integer
StatusIDrefs; labels only appear in_expanded.Status.Name(requires theexpandquery parameter). Applications are the exception — they carry stringStatuslabels directly. - Statuses/types are
NamedValue { ID, Name }lookups (Position_GetStatuses/Position_GetTypes/Candidate_GetRatings/AdSource_GetAdSources, etc.) consumed viafieldValueOperationsfor designer dropdowns. - Candidate create/update are not implemented at the workflow layer (the adaptor inherits the base not-supported defaults). Candidate records flow in through list/get and the search-cache pipeline; use the ATS proxy for vendor-native writes.
- Job create/update are not implemented and live job get-by-id resolves from the GLYDE index; live single-position reads are available via
Position_GetPositionthrough the ATS proxy. - No ATS activity write-back for messages. Email/SMS delivery is GLYDE-native (Mailgun/Twilio); no erecruit activity note is created. Use the ATS proxy for vendor-native note operations.
- Addresses use
PostalCode/AddressLine1(notZip/Address1). HireDate/ReHireDateon candidates are placement dates, NOT record timestamps — deliberately never mapped to created/updated.EducationLeveIDis a vendor typo onCandidateResponseand is unmapped by design.- Outbound create/update field mapping beyond
CandidateApplication_Postis not yet implemented in the mapping profile — it defines the inbound field maps used by the ATS search-index pipeline.
Version History
- Documented the manual ATS-UI webhook events model end to end: the WebApi has no subscription-registration endpoints, so the inbound webhook is created manually in the erecruit ATS UI pointing at
POST https://api.glydeunity.com/api/unity/events/webhook/{client_uuid}/erecruit, and theerecruit-core-eventssubscription (born disabled) is enabled by GLYDE support once the webhook exists. Refreshed the Events section, architecture summary, diagram, endpoint table, and Power Platform notes that previously stated "no webhooks". - Clarified
service_urlMUST include the/webapipath — the token endpoint is origin-derived so a malformed base still mints tokens while data calls fail; documented the activation live credential probe (token mint + one cheap read) that now catches this at setup time. - Documented that inbound events are the primary initial-population path for candidates (no candidate-enumeration search in the WebApi:
Candidate_Listrequires vendor/status/owner filters,Candidate_ByNameis exact-match). - Proxy operations for erecruit are default-allowed at the platform operation-permission gate (a missing per-ATS entry previously denied every direct ATS operation with 403 before the connector was invoked).
- Migrated authentication from the legacy v1 user login (
User/ValidateCredentialswith UserName + Password + mandatory EntityID) to the WebApi v2 OAuth2 client-credentials flow per the official Bullhorn KB:POST {site-origin}/t/tokenwith client_id + client_secret, beareraccess_token, 10-minute expiry honored viaexpires_in. - Credentials are now API service credentials (client_id + client_secret stored as
UnityCredentials.client_id/client_secret); EntityID became optional context andservice_urlis effectively required (per-tenant hosts). - Documented control-panel application registration + Manage API Permissions prerequisites; refreshed configuration requirements, known limitations, and gotchas accordingly.
- Companies & Contacts: directory search endpoints added —
searchCompanies/searchContactsover the GLYDE directory index, picker endpoints for Power Automate/Make.com dynamic lookup, andunityIngestDirectoryDatafor parsed imports from any source format (recruiter + support agents). Live erecruit company/contact reads remain available via the proxy (Company_Filter/Contact_Filter).
- Initial integration guide creation
- Documented bearer-token authentication via User_ValidateCredentials (UserName + Password + mandatory EntityID)
- Documented candidate retrieval with live/cache merge and weighted search live reinforcement
- Documented job (Position) search via Position_GetInternallyPosted and index-only get-by-id
- Documented application create/find/list operations (CandidateApplication_Post, GetByCandidateId, GetByPositionId)
- Documented the Match pipeline record (application→submission→placement as one expanding type)
- Documented ATS proxy discovery/inspection/execution across all 230 spec operations
- Documented the NamedValue lookup catalogs feeding designer dropdowns
- Documented the no-webhook event model with TTL + scheduled cache refresh
- Documented platform access patterns (Teams, Copilot, Power Platform, SDK, MCP, Voice)
- Documented entity mappings (Candidate, Position, CandidateApplication, Match)
- Documented configuration requirements and known limitations