Partner Integration Guide
Everything you need to integrate your platform with Oitchau (Day.io) through the External API — authentication, endpoints, SSO, and real-time events, with worked examples you can copy.
Introduction
Building accurate Time & Attendance across multiple countries is hard. Every country has its own labor laws, holiday calendars, absence rules, overtime tiers, and tax ID formats. Managing all of that — and delivering clean, pre-classified attendance data to a payroll processor before each payroll run — requires a platform that understands these rules natively.
Oitchau is a Time & Attendance platform designed for companies with distributed workforces. It tracks work hours, manages payroll periods, applies country-specific labor rules automatically, and exports structured attendance reports ready for payroll processing.
The External API gives you programmatic access to the same capabilities available in the UI: creating and managing companies, legal entities, employees, and subscriptions to real-time attendance events.
- A partner token — your API credential
- The base URL for each environment (staging and production)
Integration Directions
The integration works in two directions:
Your system Oitchau (Day.io) ┌──────────────┐ REST API (token) ┌──────────────────┐ │ Backend │ ──────────────────▶ │ External API │ │ │ ◀────────────────── │ │ └──────────────┘ Webhooks (signed) └──────────────────┘
- You → Oitchau (REST API): Create and manage companies, legal entities, employees, and configuration by calling REST endpoints with your token.
- Oitchau → You (Webhooks / Events): Subscribe to real-time events so your system stays in sync whenever data changes — employee updates, schedule assignments, attendance reports.
Access Channels
Employees and admins can interact with Oitchau through four channels. Your integration uses the External API; end users typically use the web or mobile interface, accessible via SSO from your platform.
| Channel | Description |
|---|---|
| Mobile web | Mobile-optimized browser experience. No app install required. |
| Kiosk | Physical punch terminal (POS/tablet) for in-person clock-in/out. |
| External API | Programmatic access for partners and direct integrators. |
Platform Overview
How Oitchau Is Structured
Oitchau organizes companies using a Company → Legal Entity → Employee hierarchy. This model is designed for companies that operate across multiple countries, with each jurisdiction carrying its own configuration — holidays, absence types, tax rules, pay policy defaults — without creating separate accounts.
Company (your client account)
└── Legal Entity: Acme Italy (IT)
│ ├── Locations
│ ├── Employees
│ ├── Schedules
│ ├── Pay Policies
│ └── Pay Group
└── Legal Entity: Acme Brazil (BR)
├── Locations
├── Employees
├── Schedules
├── Pay Policies
└── Pay Group
Core Concepts
| Concept | Description |
|---|---|
| Company | An Oitchau account representing one of your clients. When you onboard a client, you create a Company on their behalf. One Company holds one or more Legal Entities and maps to your externalCompanyId. |
| Legal Entity | A country-specific operating unit within a Company. Carries its own registered address, tax ID, holiday calendar, pay policy defaults, and payroll groups. |
| Location | A physical site (office, warehouse, etc.) tied to one Legal Entity. |
| Employee | A member of a Legal Entity. Each employee is assigned to exactly one entity and inherits its country configuration: holiday calendar, absence types, and default pay policy. |
| Schedule | Defines when employees are expected to work. Templates are country-aware and include jurisdiction-specific break rules. |
| Pay Policy | Rules governing overtime, night shift premiums, and hour caps. Each policy is scoped to one Legal Entity and pre-filled with the statutory defaults for that country. |
| Pay Group | A group of employees sharing a payroll frequency. Scoped to one Legal Entity. |
| Punch | A clock-in or clock-out event recorded via kiosk, web, or mobile. |
| Payroll Locking | The process of closing a payroll period, finalizing attendance data for export. |
Quickstart
The fastest path to a working integration: create a company, add a legal entity, create one employee, and generate an SSO link.
# Oitchau provides: <PARTNER_TOKEN> and the base URL ($PUB) # Step 1 — Create a company (returns company token — store it) curl -X POST "$PUB/v1/external-api/public/company" \ -H "Authorization: Bearer <PARTNER_TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "externalCompanyId": "acme-001", "name": "Acme", "locale": "en", "owner": { "email": "owner@acme.com", "fullName": "Ana Owner", "externalId": "acme-user-1" } }' # → { "uuid": "96e0…", "externalId": "acme-001", "token": "<COMPANY_TOKEN>" } # Step 2 — Create a Legal Entity # Country config (holidays, absence types, pay policy) is auto-assigned curl -X POST "$PUB/v1/external-api/public/company/acme-001/legal-entities" \ -H "Authorization: Bearer <COMPANY_TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Italy S.r.l.", "externalId": "acme-le-it", "country": "IT", "registrationNumber": "MI-12345", "taxIdentificationNumber": "IT12345678901" }' # → { "legalEntityId": "b31537c5-8040-433d-88a9-29f5da2c151e", … } # Step 3 — Create an employee in that Legal Entity curl -X POST "$PUB/v1/external-api/public/company/acme-001/employee" \ -H "Authorization: Bearer <COMPANY_TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "name": "Marco Rossi", "externalId": "acme-emp-42", "email": "marco@acme.com", "legalEntityExternalId": "acme-le-it", "taxId": "RSSMRC80A01H501Z" }' # Step 4 — Generate an SSO link for the employee curl "$PUB/v1/external-api/public/company/acme-001/employee/acme-emp-42/auth-url" \ -H "Authorization: Bearer <COMPANY_TOKEN>" # → { "url": "https://…?ot_token=…&page=punches" } # Redirect the user's browser to this URL — they land inside Oitchau, fully authenticated
Authentication
Every request must include your token in the Authorization header:
Authorization: Bearer <your-token>
<your-token> is a placeholder — replace it with your actual partner token or company token
depending on which endpoint you are calling.
Token Types
| Token | Issued by | Scope | Used to… |
|---|---|---|---|
| Partner token | Oitchau team | Your integration account | Create and deactivate companies. |
| Company token | Returned on company creation | A single company | Manage legal entities, employees, SSO, and webhooks for that company. |
Common Error Responses
| HTTP | Meaning | What to check |
|---|---|---|
| 401 | Missing or unknown token | Is the Authorization: Bearer <token> header present and correct? |
| 403 | Invalid token / forbidden | Is the token valid? Are you using the right token type for this endpoint? |
| 401 | Wrong token scope | Using a company token on a partner endpoint (or vice versa). |
| 409 | Token not active | Your credential is paused or deactivated — contact Oitchau. |
| 400 | Missing identifier | The externalCompanyId is missing from the path or query. |
ID Strategy
Oitchau uses two parallel identifier systems. Understanding both is essential before you start syncing data.
| Identifier | Who sets it | Description |
|---|---|---|
uuid |
Oitchau | Auto-generated UUID assigned to every entity. Returned in API responses. Use it to identify records in Oitchau unambiguously. |
externalId / externalCompanyId |
You | Your own system's identifier, stored by Oitchau and returned in webhooks. Use it to reconcile records between systems. |
uuid alongside your externalId. Most webhook payloads return both, so you can always match records on either side.Data Model
Key relationships to understand before building your integration:
- A Company (
externalCompanyId) contains one or more Legal Entities. - A Legal Entity is always tied to one country. On creation, Oitchau automatically assigns: the public holiday calendar, the statutory absence type catalog, and a default pay policy pre-filled with local statutory defaults.
- An Employee belongs to exactly one Legal Entity. When a legal entity is assigned or changed on an employee, their holiday calendar is automatically updated to match.
- A Pay Policy is scoped to exactly one Legal Entity and cannot be shared across entities.
- A Payroll Group is scoped to exactly one Legal Entity. Employees can only be assigned to payroll groups within their own entity.
- Locations and Teams are tied to a Legal Entity. Cost centers and departments can span entities.
Accepted locale values
en, es, he, pt-BR, pt-PT
Country-Specific Fields
Oitchau enforces country-specific validation on employee records. The available fields depend on the Legal Entity's country.
Tax ID (required on employee create/update)
All countries use a single field: taxId. The expected format and validation rules vary by country:
| Country | Local Name | Format |
|---|---|---|
| Brazil | CPF | 11 digits (checksum validated) |
| Italy | Codice Fiscale | 16-char alphanumeric |
| USA | SSN | 9 digits |
| UK | NI Number | 2 letters + 6 digits + 1 letter |
| Mexico | RFC | Alphanumeric |
taxId field. Invalid formats return a 400 error with a field-level message.Webhooks
Oitchau uses an event-driven delivery architecture built on Kafka and Change Data Capture (CDC). When data changes, events flow through the following pipeline before reaching your endpoint:
Oitchau DB → Kafka → External API listener → Webhook dispatcher → Your endpoint
- Delivery guarantees: respond with 2xx to acknowledge receipt. Failed deliveries are automatically retried with exponential backoff.
- Idempotency: every payload includes a
sendEventUuid. If you receive the same UUID twice, process it only once.
Configure your webhook endpoint by providing your URL and the list of event types you want to subscribe to. Contact your Oitchau integration contact to configure delivery.
Roles & Permissions
Oitchau uses a role-based access control model. Permissions can be scoped to a single legal entity, multiple entities, or the full company.
| Role | Platform Label | Access Level |
|---|---|---|
employer |
Owner | Full access — company settings, all legal entities, all employees, all payroll data. |
supervisor |
Supervisor / HR | Team-scoped access — attendance, requests, limited reports. |
employee |
Basic member | Personal access only — own punches, own requests. |
1. Managing Companies
Base path: v1/external-api/public/company
1.1 Create a Company
Use your partner token.
POST v1/external-api/public/company
Authorization: Bearer <partner-token>
Content-Type: application/json
{
"externalCompanyId": "acme-001",
"name": "Acme Ltda",
"taxPayerId": "12.345.678/0001-90",
"locale": "pt-BR",
"registeredAddress": {
"country": "BR",
"formatted": "Av. Paulista 1000, São Paulo, SP",
"city": "São Paulo",
"state": "SP",
"street": "Av. Paulista",
"streetNumber": "1000",
"zip": "01310-100"
},
"owner": {
"email": "owner@acme.com",
"fullName": "Ana Owner",
"externalId": "acme-user-1",
"taxPayerId": "123.456.789-00"
}
}
| Field | Required | Notes |
|---|---|---|
externalCompanyId | ✅ | Your unique ID for this company. Immutable. |
name | ✅ | Company display name. |
owner.email, owner.fullName, owner.externalId | ✅ | Initial owner/admin user. |
owner.taxPayerId | — | Owner's personal tax ID. |
taxPayerId | — | Company CNPJ / VAT / tax ID. |
locale | — | One of en, es, he, pt-BR, pt-PT. |
registeredAddress.country, .formatted | — | Required only if registeredAddress is sent. |
Response — save the token
token immediately — there is no endpoint to retrieve it again.{
"uuid": "96e01bb3-5a08-417e-9ac2-48fdf073eb9f",
"externalId": "acme-001",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"
}
1.2 Update a Company
PUT v1/external-api/public/company/acme-001 Authorization: Bearer <company-token> Content-Type: application/json { "name": "Acme Brasil Ltda", "locale": "pt-BR" }
1.3 Get a Company
GET v1/external-api/public/company?externalCompanyId=acme-001
Authorization: Bearer <company-token>
{
"id": 101,
"uuid": "96e01bb3-5a08-417e-9ac2-48fdf073eb9f",
"externalId": "acme-001",
"name": "Acme Ltda",
"active": true,
"locale": "pt-BR",
"tabletCode": "ugv4hk",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-20T14:45:00.000Z"
}
The tabletCode is a short code returned by this endpoint. Use it to pair a physical tablet device (kiosk) with the company.
1.4 Deactivate a Company
Use your partner token. Deactivates the company and invalidates its company token.
PUT v1/external-api/public/company/acme-001/deactivate
Authorization: Bearer <partner-token>
2. Managing Legal Entities
Base path: v1/external-api/public/company/{externalCompanyId}/legal-entities — use the company token.
A legal entity is a country-specific operating unit within a company. On creation, Oitchau automatically assigns the country's public holiday calendar, default absence types, and pay policy defaults.
country is immutable after creation and cannot be changed.2.1 Create a Legal Entity
POST v1/external-api/public/company/acme-001/legal-entities
Authorization: Bearer <company-token>
Content-Type: application/json
{
"name": "Acme Italy S.r.l.",
"externalId": "acme-le-it",
"country": "IT",
"registrationNumber": "MI-12345",
"taxIdentificationNumber": "IT12345678901",
"address": {
"formatted": "Via Roma 1, 20100 Milano, MI",
"country": "IT",
"city": "Milano",
"state": "MI",
"street": "Via Roma",
"streetNumber": "1",
"zip": "20100"
}
}
| Field | Required | Notes |
|---|---|---|
name | ✅ | |
country | ✅ | ISO 3166-1 alpha-2 (e.g. BR, IT, US). Immutable after creation. |
externalId | ✅ | Your own identifier. Must be unique within the company. Can be used in place of legalEntityId (UUID) when assigning employees. |
address.formatted, address.country | — | Required only if address is sent. |
registrationNumber | — | Chamber of commerce / registration number. |
taxIdentificationNumber | — | Validated against country-specific format (e.g. CNPJ for BR, Partita IVA for IT). |
Response 201 Created
{
"legalEntityId": "96e01bb3-5a08-417e-9ac2-48fdf073eb9f",
"externalId": "acme-le-it",
"name": "Acme Italy S.r.l.",
"country": "IT",
"registrationNumber": "MI-12345",
"taxIdentificationNumber": "IT12345678901",
"active": true,
"createdAt": "2025-03-01T10:00:00.000Z"
}
legalEntityId is a UUID generated by Oitchau. Store it alongside your own externalId — either can be used when creating employees.
2.2 Update a Legal Entity
PUT v1/external-api/public/company/acme-001/legal-entities/{legalEntityId} Authorization: Bearer <company-token> Content-Type: application/json { "name": "Acme Italy S.p.A.", "taxIdentificationNumber": "IT98765432101" }
2.3 List Legal Entities
GET v1/external-api/public/company/acme-001/legal-entities
Authorization: Bearer <company-token>
{
"items": [
{
"legalEntityId": "96e01bb3-5a08-417e-9ac2-48fdf073eb9f",
"externalId": "acme-le-it",
"name": "Acme Italy S.r.l.",
"country": "IT",
"active": true,
"createdAt": "2025-03-01T10:00:00.000Z"
}
]
}
2.4 Deactivate a Legal Entity
PUT v1/external-api/public/company/acme-001/legal-entities/{legalEntityId}/deactivate
Authorization: Bearer <company-token>
3. Managing Employees
Base path: v1/external-api/public/company/{externalCompanyId}/employee — use the company token.
3.1 Create an Employee
POST v1/external-api/public/company/acme-001/employee
Authorization: Bearer <company-token>
Content-Type: application/json
{
"name": "Marco Rossi",
"externalId": "acme-emp-42",
"email": "marco@acme.com",
"phoneNumber": "+393331234567",
"matricula": "0042",
"position": "Operator",
"isSupervisor": false,
"supervisorExternalId": "acme-emp-1",
"legalEntityExternalId": "acme-le-it",
"taxId": "RSSMRC80A01H501Z"
}
| Field | Required | Notes |
|---|---|---|
name, externalId | ✅ | externalId must be unique within the company. |
legalEntityId | one of ✅ | UUID returned when creating the legal entity. |
legalEntityExternalId | one of ✅ | The externalId you set when creating the legal entity. Determines the employee's country, holiday calendar, and which tax ID fields apply. |
email, phoneNumber, matricula, position | — | Optional employee details. |
isSupervisor | — | Marks the user as a supervisor. |
supervisorExternalId | — | The externalId of this employee's supervisor. |
3.2 Update an Employee
Send only the fields you want to change, identified by externalId:
PUT v1/external-api/public/company/acme-001/employee Authorization: Bearer <company-token> Content-Type: application/json { "externalId": "acme-emp-42", "position": "Senior Operator" }
3.3 Look Up an Employee
GET v1/external-api/public/company/acme-001/employee?externalId=acme-emp-42
Authorization: Bearer <company-token>
3.4 Deactivate an Employee
PUT v1/external-api/public/company/acme-001/employee/acme-emp-42/deactivate
Authorization: Bearer <company-token>
4. Single Sign-On (SSO)
SSO lets you log a user directly into the Oitchau web admin from your own interface without requiring them to enter a separate password.
GET v1/external-api/public/company/acme-001/employee/acme-emp-42/auth-url
Authorization: Bearer <company-token>
{ "url": "https://your-company.day.io/?ot_token=WU4XXXXXXXXXXX&page=punches" }
- Redirect the user's browser to the returned
urlto complete login. - The
ot_tokencan be used once only — generate the URL right before you redirect. - Optional query param:
page— open a specific page after login (e.g.punches).
SSO Flow
Your UI Your Backend Oitchau API
┌────────┐ ┌────────────┐ ┌──────────┐
│ │ Open │ │ │ │
│ │──────────▶│ │ │ │
│ │ Day.io │ │ GET …/auth-url │ │
│ │ │ │─────────────────▶│ │
│ │ │ │ │ │
│ │ │ │◀─────────────────│ │
│ │ │ { url: https://…?ot_token=…}│ │
│ │◀──────────│ │ │ │
│ │ redirect │ │ │ │
│ │──────────────────────────────────────────▶│ │
│ │ GET url?ot_token=… │ │
│ │◀──────────────────────────────────────────│ │
│ │ logged in (session) │ │
└────────┘ └────────────┘ └──────────┘
5. Events
Oitchau uses an event-driven delivery architecture built on Kafka and Change Data Capture (CDC). When data changes, events flow through the following pipeline before reaching your endpoint:
Oitchau DB → Kafka → External API listener → Webhook dispatcher → Your endpoint
- Delivery guarantees: respond with a 2xx status to acknowledge receipt. Failed deliveries are automatically retried with exponential backoff.
- Idempotency: every payload includes a
sendEventUuid. If you receive the same UUID twice, process it only once.
Available Event Types
6. Quick Start (end-to-end)
# Oitchau provides: <PARTNER_TOKEN> and the base URL ($PUB) # 1. Create a company → returns its company token curl -X POST "$PUB/v1/external-api/public/company" \ -H "Authorization: Bearer <PARTNER_TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "externalCompanyId": "acme-001", "name": "Acme", "locale": "en", "owner": { "email": "owner@acme.com", "fullName": "Ana Owner", "externalId": "acme-user-1" } }' # → { "uuid": "96e0…", "externalId": "acme-001", "token": "<COMPANY_TOKEN>" } # 2. Create a legal entity → returns its legalEntityId (UUID) curl -X POST "$PUB/v1/external-api/public/company/acme-001/legal-entities" \ -H "Authorization: Bearer <COMPANY_TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Italy S.r.l.", "externalId": "acme-le-it", "country": "IT", "registrationNumber": "MI-12345", "taxIdentificationNumber": "IT12345678901" }' # → { "legalEntityId": "96e01bb3-5a08-417e-9ac2-48fdf073eb9f", "externalId": "acme-le-it", … } # 3. Create an employee — reference the legal entity by externalId or UUID curl -X POST "$PUB/v1/external-api/public/company/acme-001/employee" \ -H "Authorization: Bearer <COMPANY_TOKEN>" \ -H "Content-Type: application/json" \ -d '{ "name": "Marco Rossi", "externalId": "acme-emp-42", "email": "marco@acme.com", "legalEntityExternalId": "acme-le-it", "taxId": "RSSMRC80A01H501Z" }' # 4. Generate an SSO link for the employee curl "$PUB/v1/external-api/public/company/acme-001/employee/acme-emp-42/auth-url" \ -H "Authorization: Bearer <COMPANY_TOKEN>" # → { "url": "https://…?ot_token=…&page=punches" }
7. Reference
Endpoint Summary
| Endpoint | Method | Token | Purpose |
|---|---|---|---|
…/company |
POST | partner | Create a company (returns company token). |
…/company/{id} |
PUT | company | Update a company. |
…/company?externalCompanyId= |
GET | company | Get a company. |
…/company/{id}/deactivate |
PUT | partner | Deactivate a company. |
…/company/{id}/legal-entities |
POST | company | Create a legal entity. |
…/company/{id}/legal-entities |
GET | company | List legal entities. |
…/company/{id}/legal-entities/{leId} |
PUT | company | Update a legal entity. |
…/company/{id}/legal-entities/{leId}/deactivate |
PUT | company | Deactivate a legal entity. |
…/company/{id}/employee |
POST PUT GET | company | Create, update, or look up an employee. |
…/company/{id}/employee/{empId}/deactivate |
PUT | company | Deactivate an employee. |
…/company/{id}/employee/{empId}/auth-url |
GET | company | Generate an SSO login URL. |
White-Label Customization
The Oitchau UI can be white-labeled per partner — colors, logo, and product name. This is configured by the Oitchau team on your behalf; no API calls are required on your side.
https://app.swaggerhub.com/apis/Day.io/ExternalAPI ↗