Artur
Artur
Founder

n8n Personio Integration: Connect the API v2 and Alert Slack on New Hires (2026)

October 26, 2026

n8n-personiopersonio-apihr-automationhttp-request-noden8n-slack

TL;DR: n8n has no built-in Personio node in 2026, so the connection is the HTTP Request node plus a generic OAuth2 credential set to the Client Credentials grant, pointed at https://api.personio.de/v2/auth/token. The credential fetches and caches the bearer token (valid 24 hours), and every Personio v2 endpoint (/v2/persons, /v2/absence-periods, /v2/attendance-periods) works from there. The workflow below polls Personio every 15 minutes for newly created people, looks up their employment, and posts the hire to Slack.

The file above is an importable starting workflow: eight nodes, credentials referenced by placeholder only. Create the two credentials described below, attach them, set your Slack channel, and activate it.

Does n8n have a Personio node?

No. There is no Personio node or credential type in n8n's core node package, and n8n.io/integrations/personio returns a 404. Use the HTTP Request node with a generic OAuth2 credential. That covers every endpoint in Personio's v2 API, not just the subset a wrapper node exposes.

Third-party community packages do exist on npm (@nativeship/n8n-nodes-personio and n8n-nodes-personio-hr, both published in 2026). They save some clicks, but they put someone else's code between your instance and your employee records, and they can lag behind Personio's API changes. For HR data, the HTTP Request node is the better default: you see every request, and nothing extra needs installing or auditing. If you have not used the node's credential and pagination options before, the HTTP Request node guide covers them.

How does Personio API v2 authentication work?

Personio v2 uses the OAuth 2.0 Client Credentials grant. You POST a form-encoded body with grant_type=client_credentials, client_id and client_secret to https://api.personio.de/v2/auth/token and get back a bearer token with a papi- prefix. It is valid for 24 hours (expires_in: 86400) and can be reused for parallel calls.

The raw exchange, so you can test credentials before touching n8n:

curl -X POST "https://api.personio.de/v2/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Accept: application/json" \
  -d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"

A successful response contains access_token, token_type: "Bearer", expires_in and scope. The optional scope parameter is a space-delimited list. Leave it out and the token gets every scope the credential was granted in Personio.

Three details from Personio's docs matter in practice:

  • The token endpoint is rate limited to 150 requests per minute. Go over it and you are throttled to one request per second for the next 60 seconds. This is why you let the n8n credential cache the token instead of requesting a new one in every execution.

  • Credentials come from Personio, not n8n. In Personio, go to Marketplace > Connected integrations and click Create custom integration. Grant only the read access the workflow needs: persons and employments. Personio documents personio:persons:read for GET /v2/persons; the employments endpoint lists no scope of its own, so if Get employments returns 403 while List new persons works, check the integration's employment read access.

  • v1 auth is being phased out. Sending credentials as query-string parameters to POST /v1/auth is deprecated: from 4 December 2026 it returns 403 for credentials created after 1 June 2026, and existing credentials must move to body parameters by 4 January 2027. The v1 attendance and project endpoints are deprecated in favour of v2, with a final date of 31 January 2027. Build on v2 now.

How do you set up the Personio credential in n8n?

Create a credential of type OAuth2 API (the generic one) and set Grant Type to Client Credentials. n8n then requests the token itself, stores it, and attaches Authorization: Bearer ... to every HTTP Request node that uses the credential.

FieldValue
Grant TypeClient Credentials
Access Token URLhttps://api.personio.de/v2/auth/token
Client IDyour Personio client_id
Client Secretyour Personio client_secret
Scopeempty (the token gets every scope granted to the integration)
AuthenticationBody

n8n defaults Authentication to Header (HTTP Basic). Switch it to Body, because Personio's spec documents client_id and client_secret as form fields in the request body. Leave Scope empty unless you know the exact scope names: a token restricted to personio:persons:read alone may not cover the employments call. Then, in each HTTP Request node, set Authentication to Generic Credential Type, then OAuth2 API, then this credential.

Personio also strongly recommends an X-Personio-App-ID header on every request, in UPPER_SNAKE_CASE. It does not affect authentication. Without it, their support may not be able to trace your calls. The workflow sends X-Personio-App-ID: N8N_NEW_HIRE_SLACK.

What does the new-hire-to-Slack workflow do, node by node?

Every 15 minutes it asks Personio for people created since the last run. For each one it fetches their employments, builds a one-message summary (name, email, position, start date, status) and posts it to a Slack channel. It stops with an error rather than silently skipping data, and it only advances its time window after every message was posted.

  1. Every 15 minutes (Schedule Trigger). Fifteen minutes is fast enough for a "someone new is joining" notice and makes 96 runs a day.
  2. Time window (Code). Reads the last saved window end from workflow static data and returns since and until as UTC timestamps without milliseconds (2023-01-01T12:00:00Z), the precision Personio uses for created_at. Personio only offers created_at.gt and created_at.lt, both exclusive, so the node also returns createdAfter, one second before since. Without that, a person created in exactly the boundary second would fall between two runs. Static data only persists on production runs of an active workflow, not on manual test runs.
  3. List new persons (HTTP Request). GET https://api.personio.de/v2/persons with created_at.gt set to createdAfter, created_at.lt set to until, and limit=50. Fifty is the documented maximum per page, and the default is 10.
  4. Extract persons (Code). Unpacks the _data array into one item per person. If _meta.links.next is present, more than 50 people were created in one window. The node then throws instead of dropping the rest. If the window holds nobody, this node saves it as done and the run ends here.
  5. Get employments (HTTP Request). GET /v2/persons/{id}/employments. Personio returns them most recent first, so _data[0] is the new contract, with employment_start_date, position.title and status.
  6. Build message (Code). Composes the Slack text and throws if a person has no employment at all.
  7. Post to Slack (Slack node, bot token credential). The channel is set to #new-hires. Change it to yours. The "Include Link to Workflow" footer is switched off so the message does not carry your n8n URL. Channel setup and scopes are in the n8n Slack integration guide.
  8. Save window (Code). Stores until in static data, so the next run starts there.

The window is saved at the end, not at the start, because n8n writes static data even when an execution fails. Saving it up front would mean a failed run (Slack down, more than 50 hires, a person without an employment) permanently skips that window's hires. Saving it last means the next run retries the whole window. The trade-off: if Slack fails after two of three messages, those two are posted again. A duplicate notice is better than a missing one.

The persons list carries no start date. A person record holds identity fields (first_name, last_name, preferred_name, email, status, custom_attributes) plus a list of employment IDs. The start date, position and supervisor live on the employment. That is why the workflow makes a second call.

The workflow's settings turn off saving successful executions. Every saved run would otherwise keep a copy of employee names and emails in n8n's database. Failed runs are still saved, so you can debug them. Pair the workflow with an error workflow so a failure alerts someone; the error handling guide shows the pattern.

Should you poll Personio or use its webhooks?

Poll for a new-hire notice. Use webhooks when you need changes within seconds or want to react to updates and deletions. Personio v2 does have webhooks, but they need a public HTTPS endpoint, a reply within 3 seconds, and HMAC signature checks. For a notice that is useful any time before the start date, polling is less to build and less to break.

What Personio's webhooks offer, if you do need them:

  • Events: person.created, person.updated, person.deleted, employment.created, employment.updated, and employment.started, which fires at 00:00 UTC on the hire date. Also employment.terminated, absence-period.created / .updated.status / .updated.timerange / .deleted, attendance-period.* and document.*.

  • Thin payloads. An event carries only IDs, for example payload.person.id, so you still call the API for the details, exactly as the polling workflow does.

  • Delivery rules. The endpoint must be HTTPS. Requests do not follow redirects. A delivery that is not acknowledged within 3 seconds, or gets a 5xx response other than 501, is retried with growing delays: up to 6 attempts over 3 days, 14 HTTPS requests at most.

  • Signatures. Each delivery carries X-Personio-Webhook-Timestamp and X-Personio-Webhook-Signature, an HMAC-SHA256 of {timestamp}.{raw_body} keyed with the webhook's signing secret. During a secret rotation the header holds two comma-separated signatures; accept either. You must verify against the exact raw bytes received, not a re-serialized JSON object, and Personio recommends rejecting timestamps more than 5 minutes old.

  • Management is API-only. Webhooks are created and edited through POST /v2/webhooks and related endpoints, which need the personio:webhooks:read / :write scopes.

In n8n, the 3-second rule means a Webhook node set to respond immediately, with the work done after the 200 is sent. The raw-body requirement means enabling the Webhook node's raw body option before you can check signatures. The Webhook node guide covers both settings.

What else can you build from the same credential?

The same credential reaches absences and attendances. GET /v2/absence-periods filters by person.id, absence_type.id, starts_from.date_time.gte / .lte, ends_at.date_time.gte / .lte and updated_at.gte / .lte, with up to 100 results per page. Syncing approved time off into a shared team calendar is the obvious next workflow. It follows the same pattern: a time window, a list call, then one write per item.

GET /v2/attendance-periods is the v2 replacement for the deprecated v1 attendances endpoint. Note that v2 periods can run overnight, so the start and end dates can fall on different days. If you only need hours worked, use the duration field rather than computing it from start and end.

When should you not use n8n for Personio?

Skip n8n when an off-the-shelf integration already does the job, or when the job is identity provisioning that needs an audit trail.

  • A Marketplace integration already exists. Personio's Marketplace has a Slack integration; its documented features are channel updates for absences, birthdays and work anniversaries, plus Slack status updates during time off. If a vendor-maintained connector does what you need, use it. It has no workflow for you to maintain.

  • Account provisioning and deprovisioning. Creating and, more importantly, revoking accounts in Entra ID or Google Workspace when someone leaves is an access-control process. A dedicated HRIS-to-directory sync tool gives you reconciliation and audit logs that a polling workflow does not. Use n8n for the notifications and side tasks around it, not as the system that decides who has access.

  • Payroll and compensation data. The API exposes compensations behind separate scopes. Unless your n8n instance is hardened and execution data saving is off, keep salary data out of general-purpose workflows.

Use n8n when the job crosses Personio and two or three other tools in a way no Marketplace connector covers, for example: new hire, then a Slack notice, then an onboarding checklist in your project tool, then an equipment request to IT.

FAQ

Is there an official n8n Personio node?

No. n8n's core node package has no Personio node or credential in 2026, and the integrations page for Personio returns a 404. Connect with the HTTP Request node and a generic OAuth2 API credential using the Client Credentials grant.

What is the Personio API v2 token endpoint?

POST https://api.personio.de/v2/auth/token, form-encoded, with grant_type=client_credentials, client_id and client_secret. The returned bearer token has a papi- prefix and is valid for 24 hours.

Why do I get a 403 from Personio in n8n?

Usually the token is valid, but the API credential lacks the scope for that endpoint. Each v2 endpoint documents its scope, such as personio:persons:read for persons or personio:webhooks:write for creating webhooks. Edit the integration in Personio under Marketplace > Connected integrations and add the missing scope.

How many records does Personio return per request?

GET /v2/persons returns 10 by default and at most 50. GET /v2/absence-periods returns up to 100. Both use cursor pagination: the next page's URL is in _meta.links.next.href.

Can n8n receive Personio webhooks?

Yes, through a Webhook node on a public HTTPS URL. Personio needs a 2xx reply within 3 seconds, so set the node to respond immediately. To verify the HMAC-SHA256 signature you need the raw request body, not the parsed JSON.

Do I still need the Personio v1 API?

Not for new builds. v1 query-string authentication is being removed and the v1 attendance and project endpoints are deprecated in favour of v2. Persons, employments, absence periods, attendance periods and webhooks are all in v2.

Need it wired into your stack?

The workflow above handles one job: telling a channel that someone new is joining. Connecting Personio to onboarding checklists, IT requests and calendars, with error handling and the data kept off disk, is the kind of build n8n Logic does for European teams.


n8n Personio Integration: Connect the API v2 and Alert Slack on New Hires (2026) | n8nlogic