# Emplorea HR Platform Emplorea is an HR-as-a-Service platform for businesses of every size in Australia, New Zealand and the United Kingdom. It pairs a human-first web app with a fully agent-first API surface: everything a company admin can do in the UI, an agent can do programmatically. Marketing site: emplorea.com - HR-as-a-Service for businesses of every size in AU, NZ and the UK. Self-service SaaS or a managed HR service with a named advisor. Plans: Free, Essentials ($12), Growth ($39), Command ($79) per employee per month. ## Explore the site - Home: https://emplorea.com/ - How it works (the managed service): https://emplorea.com/how-it-works - Pricing: https://emplorea.com/pricing - Meet Vera (the HR assistant): https://emplorea.com/vera - Platform overview: https://emplorea.com/product - Leave, Documents, Compliance, Payroll, Performance, Recruitment and the Employee portal each have a page at https://emplorea.com/product/ - Industries: https://emplorea.com/industries - healthcare, hospitality, retail, construction, professional-services, technology, not-for-profit, education and manufacturing each at https://emplorea.com/industries/ - Blog: https://emplorea.com/blog (RSS: https://emplorea.com/blog/feed.xml) - Integrations: https://emplorea.com/integrations - Roadmap: https://emplorea.com/roadmap ## What Emplorea can do today (live via API and MCP) - Read company context (name, plan, jurisdiction, currency, financial year, and the admin's "About your business" Vera context - read-only; it is edited in settings) - Domain security: read primary_domain, allowed_domains and domain_enforcement_enabled on GET /company; set the allowlist + enforcement toggle on PATCH /company (admin scope). primary_domain is detected at sign-up and is not writable; a blocked personal domain in the allowlist is refused. When enforcement is on, a new team member can only be invited on an allowed domain. Changes fire the company.settings_updated webhook. - Read billing status: plan, subscription status, trial, seat counts and active add-ons (read-only - plan changes are web-only, never over the API or MCP) - Read setup completeness: whether onboarding is done and what is left to finish (employees added, team invited, leave types, a document, a pay schedule) - useful when helping a client get set up. Read-only, any plan; the per-user walkthrough state is web-only and never exposed. - Manage employees: list, get, update, terminate, invite (records are always kept - terminations soft-delete for compliance; invite emails the employee a branded link to set a password and access the portal). Creating an employee is web-only - the agent surface starts at invite, once the record exists - Manage leave end to end: request (with automatic working-day counts that exclude weekends and public holidays, half days, auto-approval for configured types, non-blocking warnings), approve, decline, cancel - Read leave balances - jurisdiction-aware entitlements (AU and NZ 4 weeks annual, UK 5.6 weeks / 28 days; AU and UK accrue from day one, NZ crystallises on the employment anniversary; sick AU and NZ 10 days, UK 0 as SSP is managed) - Read leave types and their rules (approval, half days, notice) - Read public holidays for AU (national + state), NZ and UK (England & Wales); 2026-2028 where officially published - Manage documents: upload (multipart - contracts PDF only, 10MB max), list/filter, download via 15-minute signed URLs, soft delete, and payslip upload (employee_id + pay_period) - E-sign in-house: POST /documents/{id}/send-for-signature creates a one-time 7-day signing link; signing records timestamp, IP and user agent for a legally defensible record - Manage webhooks: subscribe HTTPS endpoints to employee.*, leave.*, document.*, compliance.*, payroll.*, performance.*, engage.*, wellbeing.*, learn.*, payslip.available and email.bounced / email.complained events, HMAC-SHA256 signed deliveries with retries ## Jurisdictions Australia, New Zealand and the United Kingdom are live. Jurisdiction is a parameter, not a separate product - leave entitlements, public holidays and statutory minimums follow the company's jurisdiction. Statutory rates, award and compliance-rule ingestion are Emplorea-managed (web-only, fold_admin) and not writable over the API. UK clients accept a data processing agreement (IDTA/SCCs) at onboarding before any UK employee data is created. ## HR Q&A (Vera) Ask HR questions about Australian employment law, leave entitlements, Fair Work Act obligations and HR best practice. Vera tokenises company data before any model call, so never send real names, salaries or tax file numbers. POST /api/v1/ask-hr (write scope, Essentials plan or above) { "question": "How much annual leave does a full-time employee accrue?", "conversation_id": "" } -> { "data": { "answer": "...", "conversationId": "", "cached": true } } GET /api/v1/ask-hr -> the company's conversations GET /api/v1/ask-hr/{id} -> one conversation with all messages (tokenised) MCP tools: ask_hr_question, list_hr_conversations, get_hr_conversation Notes: 10 answered questions per conversation (start a new one to continue); stable policy answers are cached for 24 hours. ## Compliance A knowledge-driven engine scores the company out of 100 across four categories - Pay, Records, Safety, Leave - and tracks open items. It checks award/minimum pay (below the published minimum, or cannot-verify - never a false green), probation reviews, contract expiry, missing details, leave entitlement, required policies, mandatory training (incl. expiry) and open incidents. Any open finding caps the score below 100; unverifiable pay below 85; any open critical at 60. A daily job re-checks every company; results are snapshotted for traceability. This is guidance, not legal advice. Award and rule data is Emplorea-managed and never writable here. GET /api/v1/compliance (read, Essentials+) score (with category breakdown) + open items (each with category + detail) + recently resolved GET /api/v1/compliance/policies (read) policies + acknowledgement coverage GET /api/v1/compliance/training (read) required training + coverage + expiries GET /api/v1/compliance/incidents (read) the WHS/HR incident register GET /api/v1/compliance/results (read) recent run snapshots (the score trend); ?jurisdiction=AU|NZ|UK for a single jurisdiction's series (else blended) POST /api/v1/compliance/{id}/resolve (write) marks one item resolved POST /api/v1/compliance/refresh (write) re-runs the checks, returns the score POST /api/v1/compliance/incidents (write) logs an incident, returns its reference POST /api/v1/compliance/incidents/{id} (write) updates an incident's status/resolution MCP tools: list_compliance_items, resolve_compliance_item, refresh_compliance, list_policies, list_training, list_incidents, log_incident, get_compliance_results Webhooks: compliance.item_created, compliance.item_resolved, compliance.incident_logged, compliance.incident_resolved, compliance.policy_acknowledged, compliance.score_threshold_crossed ## Payroll Managed payroll: the Emplorea team runs each pay for the company off-platform and the results flow into the product as engine-ready records (integer cents). Read the company's payroll state, schedule, full run list and per-run payslip rows. The client sets their own pay cycle (set_pay_schedule) - that is the one payroll write on the API. Processing runs (entering figures, advancing status, uploading payslips) is the Emplorea team's managed responsibility and stays web-only, so there are no managed-write endpoints or MCP tools. Payslip files are never returned over the API - the employee downloads them from their portal. GET /api/v1/payroll (read scope, Essentials plan or above) -> { "data": { "schedule": {...}, "next_pay_date": "...", "current_run": {...}, "upcoming": [...], "recent_paid": [...] } } GET /api/v1/payroll/schedule (read scope) the pay cycle POST /api/v1/payroll/schedule (write scope) set or reset the pay cycle { "frequency": "monthly", "first_pay_date": "2026-07-01" } GET /api/v1/payroll/runs (read scope) every run with figures (integer cents) GET /api/v1/payroll/runs/{id} (read scope) one run + per-employee payslip rows MCP tools: get_payroll, get_pay_schedule, list_pay_runs, get_pay_run, set_pay_schedule Webhooks: payroll.run_ready, payroll.run_paid, payroll.pay_date_approaching, payslip.available (payslip.available also emails the employee) ## Performance Reviews, probation, goals and 1:1s (Growth plan and above). Reads are agent-accessible; career-affecting writes (completing a probation review, sharing a review, an employee acknowledging one) are web-only - API keys are company-scoped with no role. Goals are the one pillar with safe agent writes. GET /api/v1/performance/probation open probation cases + recorded decisions GET /api/v1/performance/reviews shared reviews (drafts are never returned) GET /api/v1/performance/reviews/{id} one shared review with its body GET /api/v1/performance/goals the company's goals POST /api/v1/performance/goals create a goal (write scope) GET /api/v1/performance/goals/{id} one goal PATCH /api/v1/performance/goals/{id} update progress/status (write scope) GET /api/v1/performance/one-on-ones 1:1s - SHARED fields only MCP tools: list_probation_reviews, list_performance_reviews, get_performance_review, list_goals, get_goal, create_goal, set_goal_progress, list_one_on_ones Webhooks: performance.probation_completed, performance.review_shared, performance.review_acknowledged, performance.goal_created, performance.goal_status_changed, performance.one_on_one_logged, performance.goal_overdue, performance.one_on_one_overdue Private 1:1 manager notes are never exposed over the API. ## Recruitment (core ATS) Hire end to end (Growth plan + the Recruitment add-on): open roles, a configurable kanban pipeline, candidates and structured offers. Candidate personal details are NEVER returned on the API/MCP - the pipeline exposes each application as an opaque reference; reading a candidate's identity or CV, and accepting an offer (which creates an employee), are web-only. GET /api/v1/recruitment/roles list roles (no candidate PII) POST /api/v1/recruitment/roles create a role GET /api/v1/recruitment/roles/{id} one role + per-stage counts PATCH /api/v1/recruitment/roles/{id} update a role's status/fields GET /api/v1/recruitment/roles/{id}/pipeline stages + applications as opaque refs GET /api/v1/recruitment/stages the configurable pipeline stages POST /api/v1/recruitment/candidates add a candidate (PII in, id out) PATCH /api/v1/recruitment/applications/{id}/stage move a candidate (not to Hired) POST /api/v1/recruitment/offers create a structured offer (integer cents) MCP tools: list_job_roles, get_job_role, create_job_role, get_pipeline, list_pipeline_stages, move_application_stage, create_offer Webhooks: recruitment.role_created, recruitment.role_closed, recruitment.candidate_applied, recruitment.candidate_stage_changed, recruitment.offer_sent, recruitment.offer_accepted, recruitment.offer_declined, recruitment.employee_created ## Offboarding Wind a leaver down (Growth plan): a checklist of tasks plus an exit interview. Reads and completing an ordinary task are on the API/MCP. Exit-interview RESPONSES are private and NEVER returned (only the interview status is). Initiating a plan and completing the offboarding (which terminates the employee) are web-only. GET /api/v1/offboarding/plans list plans (metadata only) GET /api/v1/offboarding/plans/{id} one plan + tasks + interview status PATCH /api/v1/offboarding/plans/{id}/tasks/{taskId} complete/reopen an ordinary task MCP tools: list_offboarding_plans, get_offboarding_plan, complete_offboarding_task Webhooks: offboarding.plan_created, offboarding.task_completed, offboarding.plan_completed, offboarding.exit_interview_completed ## Branding Per-client white-label branding (Growth plan and above): a logo, primary and accent colours and a brand name that flow through the app shell, the browser tab title and transactional email. Branding holds no PII and logos are served from a public bucket, so it is fully agent-accessible for the caller's OWN company. A fold_admin managing another client's branding is web-only on /admin. Colours are 6-digit hex; the logo is uploaded as multipart (PNG/JPEG/WEBP/SVG, 2MB max - SVG is sanitised server-side). Updates publish immediately. GET /api/v1/company/branding (read) the branding config + logo URL PUT /api/v1/company/branding (write) set colours / brand name / email toggle POST /api/v1/company/branding/logo (write) upload a logo (multipart 'file') DELETE /api/v1/company/branding/logo (write) remove the logo, revert to the mark POST /api/v1/company/branding/reset (write) reset all branding to defaults MCP tools: get_company_branding, update_company_branding, reset_company_branding Webhooks: branding.published, branding.reset ## Engage (surveys + recognition) Measure and lift engagement (Growth plan and above): eNPS, pulse and check-in surveys, plus peer and manager recognition. Survey results are AGGREGATES ONLY - the API never returns an individual response or a respondent id, and below the k-anonymity floor it returns no breakdown at all. ANONYMOUS surveys can only be answered in the app: a company-scoped API key is refused, so it can never fabricate anonymous responses at scale. The recognition feed returns PUBLIC posts only for a roleless key - private posts are never exposed. POST /api/v1/surveys create a draft survey (write scope) GET /api/v1/surveys/{id}/results aggregate results only (read scope) POST /api/v1/surveys/{id}/respond submit a response (write) - anonymous refused, attributed needs employee_id GET /api/v1/recognition the feed - public posts only (read scope) POST /api/v1/recognition post recognition (write scope) MCP tools: create_survey_draft (Vera drafts a survey - writes nothing), get_survey_results, post_recognition, list_recognition Webhooks: engage.survey.sent, engage.survey.completed, engage.survey.closed, engage.recognition.posted (all webhook-only, no email; survey.completed carries no respondent identity) ## Wellbeing Team wellbeing insight (Growth plan and above): an aggregate wellbeing score, team absence patterns, a WHS incident register and a published EAP support directory. The score and absence reads are AGGREGATES ONLY - the API never returns an individual's wellbeing score or absence flag. The score endpoint refuses an employee_id outright (an individual score is the most sensitive read outside payroll and is company_admin web-only). The EAP directory is published support information; per-employee EAP access is never recorded. GET /api/v1/wellbeing/score (read, Growth+) aggregate team/company score; team_key for one team, omit for the company; an employee_id param is refused (403) GET /api/v1/wellbeing/absence-patterns (read, Growth+) aggregate TEAM absence flags GET /api/v1/wellbeing/resources (read, Growth+) the EAP support directory POST /api/v1/wellbeing/incidents (write, Growth+) log a WHS incident, returns its reference - reuses the compliance incident register (category whs) MCP tools: get_team_wellbeing_score (aggregate only), get_absence_patterns (aggregate TEAM flags only), get_eap_resources, log_whs_incident Webhooks: wellbeing.score.updated, wellbeing.incident.action_completed (both webhook-only, no email; no PII - IDs and aggregate counts only) ## Learn Training and development (Growth plan + the Learn add-on): a course library (company courses plus the global Emplorea-published library), assignments with deadlines, lesson completions and verifiable certificates. A course read over the API is always a LEARNER read - every quiz lesson's answer key (correct_index and explanation) is stripped server-side, so the API never exposes quiz answers. Certificate verification is token-only: the high-entropy token is the capability. GET /api/v1/learn/courses (read) the library (own + global-published) POST /api/v1/learn/courses (write) create a draft company course GET /api/v1/learn/courses/{id} (read) one course + lessons (quiz keys stripped) POST /api/v1/learn/assignments (write) assign a course to employees (idempotent) POST /api/v1/learn/completions (write) mark a lesson complete (employee_id in body) GET /api/v1/learn/certificates/{id} (read) certificate metadata + the verify URL MCP tools: list_courses, assign_course, get_completion_report (aggregate coverage by course/team), verify_certificate (by token) Webhooks: learn.course.assigned, learn.lesson.completed, learn.course.completed, learn.certificate.issued, learn.assignment.overdue (all webhook-only, no email; no PII - IDs only) ## People analytics Headcount, turnover and tenure insight (Growth plan and above; the extended layer is the Analytics add-on). AGGREGATES ONLY: department breakdowns below the k-anonymity floor (5 people) are suppressed - with a complementary cell so a hidden one cannot be back-solved from the total - and turnover is shown PER JURISDICTION, never blended (turnover and leave norms differ by country). The same suppressed figures the dashboard and any export show. Headcount and turnover are reconstructed point-in-time from employment dates, so they are exact and need no history to build. Sensitive (family/domestic-violence) leave never enters any figure - the seal removes it at source. GET /api/v1/analytics (read scope, Growth plan or above) -> { "data": { "company": { "current": { headcount, active, on_leave, probation }, "headcountTrend": [...], "avgTenureDays": N }, "perJurisdiction": [ { "jurisdiction": "AU", "turnover": { ratePct, leavers, voluntary, involuntary }, "byDepartment": [...floored...] } ], "training": { mandatoryTotal, completionPct, overdueCount, "byDepartment": [...floored: per-dept completionPct, floored on distinct employees...] } } } GET /api/v1/analytics/export (read scope, Growth+) the headcount/turnover summary as a CSV download - the floor carries through (a hidden cell is "<5 - hidden", never blank, never the number) MCP tools: get_analytics_summary (aggregate only) Webhooks: analytics.report_ready, analytics.threshold_crossed (planned) ## Vera Plus (bespoke generation) Vera Plus ($4/employee/month, Essentials and above) is the add-on where Vera builds bespoke artefacts tailored to a company: learning paths (ordered course sets for a role or goal), survey programmes (tuned survey sets plus a cadence) and, later, insight reports. Generation and publishing are WEB-ONLY: a company-scoped API key has no user role, so it can neither generate (a paid call) nor publish - it can only read what a company_admin has already published. Check whether a company has it via the vera_plus flag in get_billing_status. GET /api/v1/learning-paths (read) the company's PUBLISHED learning paths GET /api/v1/survey-programmes (read) the company's PUBLISHED survey programmes MCP tools: list_learning_paths, list_survey_programmes (both read-only) Webhooks: vera.learning_path.published, vera.survey_programme.published (webhook-only, no email; IDs only) ## Permissions A per-user permission layer on top of the four roles (Growth and above): named presets (team_lead, hr_manager) and per-company capability overrides. READ-ONLY on the agent surface - changing a user's preset or a company's overrides is web-only by construction (a company-scoped key carries no role and never weakens RLS). GET /api/v1/permissions/presets (read) the presets and their capabilities GET /api/v1/permissions/company (read) this company's role overrides GET /api/v1/permissions/users/{id} (read) one user's effective permissions MCP tools: list_permission_presets, get_company_permission_overrides, get_user_permissions Webhooks: permissions.preset_changed, permissions.feature_toggled ## Advisor messaging The managed-service channel between a company admin and their named HR advisor (Growth and above, behind a per-company launch flag). METADATA ONLY on the agent surface - message CONTENT is never returned, and replying is web-only. The advisor is the company_admin's channel; employees do not message the advisor directly. GET /api/v1/messaging/conversation (read) conversation metadata only - no message bodies MCP tools: get_advisor_conversation (metadata only) Webhooks: messaging.message.sent, messaging.message.read ## Blog Public HR articles for businesses of every size in AU, NZ and the UK live at https://emplorea.com/blog (RSS feed: /blog/feed.xml; included in the sitemap). Articles are written by the Emplorea team, with optional Vera drafting, and published from the internal Content tool. The blog is public reading, not an API resource. ## Coming soon (documented in the OpenAPI spec with x-status: coming-soon) - Public careers page and unauthenticated application form (Phase 3) ## Authentication, SSO & MFA Team members sign in with email/password or "Continue with Google / Microsoft" (company-level SSO; an unknown SSO email is bounced - there is no auto-provisioning). Two-factor (TOTP) is mandatory for company admins and the Emplorea team, optional for others unless a company requires it. Auth forms are protected by Cloudflare Turnstile. GET /api/v1/auth/policy (read scope) -> { sso_required, sso_domain, mfa_required } This is the ONLY auth endpoint. SSO/MFA setup, session revocation and recovery are web-only, session-authenticated actions and are deliberately absent from the API and MCP: a company key carries a company + scope but no user identity, so personal security actions cannot be attached to it (the same rule that keeps create_employee web-only). Webhooks: auth.sso.enabled, auth.mfa.enrolled, auth.session.revoked. ## API access Base URL: https://app.emplorea.com/api/v1 Auth: Bearer token - an API key created in Settings - Integrations (Authorization: Bearer emp_live_...) Scopes: read, write, admin, webhooks Rate limit: 100 requests/minute per key (X-RateLimit-* headers) Errors: always {"error": {"code", "message", "field?"}} Conventions: money is integer cents; dates are ISO YYYY-MM-DD Docs: https://app.emplorea.com/docs OpenAPI spec: https://app.emplorea.com/openapi.json (also /openapi.yaml) Interactive reference: https://app.emplorea.com/docs/api-reference ## MCP server Connect at: https://app.emplorea.com/mcp (Streamable HTTP, JSON-RPC) Manifest: https://app.emplorea.com/.well-known/mcp.json Auth: the same API key as a Bearer token on the connection Tools: get_company_info, get_billing_status, get_setup_status, list_employees, get_employee, update_employee, terminate_employee, list_leave_requests, get_leave_balances, request_leave, approve_leave, decline_leave, cancel_leave, list_leave_types, list_public_holidays, list_documents, get_document, get_document_url, send_document_for_signature, upload_document (returns the REST upload instructions - binary goes over HTTP), ask_hr_question, list_hr_conversations, get_hr_conversation, list_compliance_items, resolve_compliance_item, refresh_compliance, get_compliance_results, list_policies, list_training, list_incidents, log_incident, get_payroll, get_pay_schedule, list_pay_runs, get_pay_run, set_pay_schedule, list_permission_presets, get_company_permission_overrides, get_user_permissions, get_advisor_conversation, list_job_roles, get_job_role, create_job_role, get_pipeline, list_pipeline_stages, move_application_stage, create_offer, list_offboarding_plans, get_offboarding_plan, complete_offboarding_task, list_probation_reviews, list_performance_reviews, get_performance_review, list_goals, get_goal, create_goal, set_goal_progress, list_one_on_ones, get_company_branding, update_company_branding, reset_company_branding, get_team_wellbeing_score, get_absence_patterns, log_whs_incident, get_eap_resources, list_courses, assign_course, get_completion_report, verify_certificate, get_analytics_summary ## CLI Install: npm install -g emplorea-cli (or npx emplorea-cli) Auth: emplorea auth login --key emp_live_... Examples: emplorea employees list --json emplorea leave request --employee --type \ --start 2026-07-14 --end 2026-07-18 Help: emplorea --help ## Common agent workflows 1. Invite a new team member: Employee records are created in the web app (or by the Emplorea team) - the agent surface does not create employees. Once the record exists, POST /employees/{id}/invite to email them a link to set a password and access the portal. 2. Request leave for someone: GET /leave-types (pick leave_type_id), GET /leave/balances?employee_id= (check entitlement), POST /leave. Read warnings in the response - they never block. 3. Clear the approval queue: GET /leave?status=pending then PATCH /leave/{id}/approve or PATCH /leave/{id}/decline with a reason. 4. Get a contract signed: POST /documents (multipart, type contract, employee_id), then POST /documents/{id}/send-for-signature, share origin + sign_path with the signer, and listen for the document.signed webhook. 5. Stay in sync: POST /webhooks with the events you care about; verify the X-Emplorea-Signature header (HMAC-SHA256 of the raw body with your endpoint secret, format "sha256="). ## Admin (internal) Emplorea's internal command centre (client roster, advisor assignment, plan and feature-flag overrides, impersonation, and blog/content management) is fold_admin web tooling only. It is not available over the API or MCP. ## Authentication instructions for agents Ask the company admin to create an API key: Settings - Integrations - Create key. Choose scopes (read for reporting, write for managing employees and leave, webhooks for subscriptions). The key is shown once. Send it on every request: Authorization: Bearer emp_live_...