Appearance
Connect Personio
Connect Personio so joiners, leavers, job and team changes, and pay changes reach Flowstate without anyone typing them in again. The forecast and budgets then work from the people you employ today.
You need access to integrations. Ask your Flowstate admin. First decide whether Personio is where people changes are made: see Get your people data into Flowstate.
How it connects
Flowstate reads your people from Personio's API, using API credentials you create in Personio. We recommend a scheduled sync for Personio: the credentials are exchanged for a token on each run, and Personio can list only the people and employments updated since the last run.
| Route | How it works | Choose it when |
|---|---|---|
| Scheduled sync (recommended) | A custom integration in Flowstate pulls from Personio's API on a schedule, from every 15 minutes to daily. | You want the sync to run inside Flowstate, with nothing of your own to host. |
| Event-driven | Your middleware, such as Workato, Boomi, MuleSoft, Make or n8n, receives Personio's webhooks and updates Flowstate through the REST API. | You already run middleware and want each change to arrive as it happens. |
What you need from Personio
- A Personio admin who can create integrations. Check with Personio that your plan includes API access.
- API credentials: a client ID and client secret, from a custom integration in Personio.
- Read access for those credentials to people, employments and compensation, plus recruiting if you want open jobs brought in as vacancies.
- Attribute access. If the credentials have a list of readable employee attributes, tick every attribute the sync needs, including custom attributes. Personio only returns the attributes you tick.
- For the event-driven route: webhooks created through Personio's API, sending to your middleware.
Set it up
In Personio
- Select Create custom integration and give it a name. Personio's help centre shows where this is for your account.
- Give it read access to people, employments, compensation and, if you need it, recruiting.
- If it has a list of readable employee attributes, tick the ones under What syncs.
- Copy the client ID and client secret.
In Flowstate
- Ask your Flowstate contact to switch on custom integrations for your organisation. They provide the hook for Personio and help your technical team configure it.
- Go to Settings → Integrations → Custom Integrations: select Browse catalog and open Custom Integrations.
- Select Create Integration. Enter a Name, such as Personio, and a Source System Key, such as
personio. Select Create. You can't change the key later. - Under Credentials, select Add Credential and store the client ID. Add the client secret as a second credential. Use the key names your Flowstate contact gives you.
- Under Hooks, select Create Hook. Choose Pull as the Hook Type and Employee as the Entity Type, then select Create. Add the hook's code and select Save Code. Add hooks for contractors and vacancies the same way if you bring them in.
- On the hook's Settings tab, turn on Run on schedule and choose an Interval. For Daily, choose a Preferred hour. Select Save Code.
- Select Test (Dry Run) and open Preview. Check that nobody already in Flowstate is about to be created a second time.
- Turn the hook on with the switch at the top of the editor, and confirm Enable Hook.
Each step in more detail: Manage a custom integration in Settings.
People already in Flowstate
If you loaded people by spreadsheet before connecting Personio, your technical team links each one to their Personio ID before the first run. See Adopt people who are already in Flowstate.
Event-driven instead
- In Flowstate, go to Settings → Users & Access → API Keys and create a key that can view, create and update employees, contractors and vacancies.
- Your technical team creates Personio webhooks that send to your middleware. See For your technical team.
- Your technical team has the middleware update Flowstate. See Sync people from an HR system with the REST API.
What syncs
| Personio | Flowstate |
|---|---|
| Person ID | External ID, which is how the sync recognises the person on every run. One person can have more than one employment in Personio. |
| First name, last name, email | Name and Email address |
| Position title | Role. A job title Flowstate hasn't seen before adds a job role. |
| Department or team | Current team |
| Supervisor | Line manager. A scheduled sync can't set it: set it in Flowstate, or send it from middleware. |
| Employment type: internal or external | Personio marks each employment as internal or external. Check that your contractors are set as external, or tell your Flowstate contact how you mark them, so they come in as contractors. |
| Weekly working hours, against full-time weekly hours | FTE on their team |
| Employment start date, end date and last working day | Employment dates |
| Compensation: fixed or hourly salary, amount, currency, monthly or yearly, and effective date | Salary changes, each from its effective date and in its own currency, on the Compensation tab |
| Recruiting jobs: name and department | Vacancies. Personio's jobs don't carry a status, office or headcount, so check those in Flowstate. |
| Office | Location. A scheduled sync can't set it: set it in Flowstate, or send it from middleware. |
| Not in Personio | Work type (Employment type on the person's record), which sets their overhead. Set it in Flowstate, or send it from middleware. |
To set location, work type or line manager in Flowstate, go to Resourcing → People and teams → People, open the person and change them under Employee details. Nothing goes back to Personio.
How changes arrive
- When. On the schedule you chose, from Every 15 minutes to Daily. With the event-driven route, as Personio sends each change.
- Edits made in Flowstate. Anything the sync sends, such as role, team, dates and pay, is set back to Personio's value on the next run. Make those changes in Personio. Location, work type and line manager stay as you set them. More in Edits made in Flowstate.
- Leavers. An end date or termination in Personio becomes the person's end date in Flowstate. They stay in past months of the forecast and effort. The sync never deletes anyone.
- Rehires. A returning employee keeps their old end date in Flowstate, because a sync can't clear one. Your technical team clears it through the REST API. See Undo a leaver.
- Future-dated pay. A pay change with a future effective date shows as Scheduled on the Compensation tab until that date. Personio's API returns compensation one month at a time, so ask your Flowstate contact how far ahead the sync reads.
Check it's working
- Open the hook and select Execution History.
- Find the latest run with Scheduled under Triggered By. It shows Completed, with a count under Records.
- If some records failed, the run's log has a line for each one, with the reason.
- Go to Resourcing → People and teams → People and compare a few people with Personio: a recent joiner, a recent leaver (Filter → Status → Include off-boarded) and someone with a recent pay change. Check Role, Current team, Employment dates and the Compensation tab.
If something's not right
Runs fail with an authentication error. The client secret was changed or the integration was removed in Personio. Create new credentials, then update the credential.
Some details are blank. The attribute isn't ticked in the credentials' readable employee attributes, or the credentials can't read that area. Tick it in Personio.
Runs fail when reading departments or teams. Personio's API refuses department and team requests while that feature is switched off in Personio. Switch it on, or ask your Flowstate contact to map teams another way.
Contractors show up as employees. Their employment is set as internal in Personio. Set it as external, or tell your Flowstate contact how you mark contractors.
For your technical team
API. Personio Public API v2, at the paths below. Take the base URL from Personio's API reference. Personio also documents v1 for employees.
Auth. POST /v2/auth/token, form-encoded, with grant_type=client_credentials and the client ID and secret. scope is optional; without it, every scope on the credentials is granted. expires_in defaults to 1 day, so cache the token in ctx.kv and send Authorization: Bearer <token>. Scopes include personio:persons:read, personio:employment:read and personio:recruiting:read.
Endpoints.
GET /v2/personsis cursor-paged (limit1–50, next page at_meta.links.next), with filtersupdated_at.gt,emailandstatus(ACTIVE,INACTIVE).GET /v2/persons/{person_id}/employmentsis cursor-paged and supportsupdated_at.gt. It's per person, and each call counts towards the hook's 50 HTTP requests per page, so size pages to suit.GET /v2/org-units?type=department|teamresolvesorg_units[]tonameandparent_id. It returns412if the feature is off in Personio.GET /v2/workplacesresolvesoffice.idto a name.GET /v2/compensations?start_date=&end_date=returnstype.category(FIXED_SALARY,HOURLY_SALARY,RECURRING,ONE_TIME,BONUS_PAYOUT),amount{value, currency},interval(MONTHLY,YEARLY,ONE_TIME),effective_fromandweekly_working_hours. The date window must be one month or less, so read pay history a month at a time.GET /v2/recruiting/jobsreturnsid,name,department,categoryandhiring_team.- v1:
GET /v1/company/employeespages bylimitandoffset, at most 100 a page;updated_sinceignoresemail,limitandoffset.GET /v1/company/employees/attributeslists the attributes the credentials may read, including customdynamic_<id>attributes. v2 returns custom attributes ascustom_attributes[].
Fields.
- Key on
persons.id. Employments have their ownid. - Employment:
position.title,org_units[] {type, id},supervisor.id(a person ID),office.id,type(INTERNAL,EXTERNAL,UNSPECIFIED),weekly_working_hours,full_time_weekly_working_hours,employment_start_date,employment_end_date,contract_end_date,termination{termination_date, last_working_day, type, reason}.
Rate limits. The v2 auth endpoint allows 150 requests per minute; once exceeded, it accepts 1 request per second for the next 60 seconds. v1 employees allows 300 requests per minute with a burst of 15 per second. Personio publishes no overall v2 limit.
Webhooks, for middleware.
- Create with
POST /v2/webhooks(an HTTPS URL andenabled_events). - Events:
person.created,person.updated,person.deleted,employment.created,employment.updated,employment.updated.cost-centers,employment.deleted, and the effective-datedemployment.startedandemployment.terminated. - Payloads carry IDs only (
company_id,occurred_at,event_name,payload, optionalmeta), so fetch the data from the API. - Verify
X-Personio-Webhook-Signature(lowercase hex): HMAC-SHA256 of"{timestamp}.{body}", keyed by the secret, with the timestamp fromX-Personio-Webhook-Timestamp.X-Personio-Webhook-Signature-Key-Idsnames the key. - The secret is returned once. Rotate it with
POST /v2/webhooks/{id}/signing-secret; the old secret keeps working for 7 days. - Acknowledge with a 2xx within 3 seconds. Personio retries up to 6 times over 3 days with exponential backoff, at most 14 requests in total. Inspect deliveries with
GET /v2/webhooks/{id}/activityand/events. - Map
employment.terminatedand deletions toendDatein Flowstate. Don't delete the person.
Personio docs.