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.

🔑
Before you start, the Oitchau team will provide you with:
  • A partner token — your API credential
  • The base URL for each environment (staging and production)
ℹ️
Accessing the API in production requires a partner setup process completed by the Oitchau team. Contact your integration contact to begin.

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.

ChannelDescription
Mobile webMobile-optimized browser experience. No app install required.
KioskPhysical punch terminal (POS/tablet) for in-person clock-in/out.
External APIProgrammatic 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
💡
Single-entity companies: if your company has only one legal entity, the hierarchy is transparent — you interact with a single company as before. The multi-entity behavior described in this guide applies only when a second legal entity is added.

Core Concepts

ConceptDescription
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.

bash — end-to-end quickstart
# 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:

http
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.

⚠️
Store the company token immediately when creating a company. There is no endpoint to retrieve it again after creation.

Token Types

TokenIssued byScopeUsed 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

HTTPMeaningWhat 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.

IdentifierWho sets itDescription
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.
💡
Always store Oitchau's 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

text
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:

CountryLocal NameFormat
BrazilCPF11 digits (checksum validated)
ItalyCodice Fiscale16-char alphanumeric
USASSN9 digits
UKNI Number2 letters + 6 digits + 1 letter
MexicoRFCAlphanumeric
ℹ️
Regardless of the country, this value must always be provided in the 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.

RolePlatform LabelAccess 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.

http — request
POST v1/external-api/public/company
Authorization: Bearer <partner-token>
Content-Type: application/json
json — request body
{
  "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"
  }
}
FieldRequiredNotes
externalCompanyIdYour unique ID for this company. Immutable.
nameCompany display name.
owner.email, owner.fullName, owner.externalIdInitial owner/admin user.
owner.taxPayerIdOwner's personal tax ID.
taxPayerIdCompany CNPJ / VAT / tax ID.
localeOne of en, es, he, pt-BR, pt-PT.
registeredAddress.country, .formattedRequired only if registeredAddress is sent.

Response — save the token

⚠️
Save the token immediately — there is no endpoint to retrieve it again.
json — response 201
{
  "uuid": "96e01bb3-5a08-417e-9ac2-48fdf073eb9f",
  "externalId": "acme-001",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…"
}

1.2 Update a Company

http
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

http
GET v1/external-api/public/company?externalCompanyId=acme-001
Authorization: Bearer <company-token>
json — response
{
  "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.

http
PUT v1/external-api/public/company/acme-001/deactivate
Authorization: Bearer <partner-token>


3. Managing Employees

Base path: v1/external-api/public/company/{externalCompanyId}/employee — use the company token.

3.1 Create an Employee

http
POST v1/external-api/public/company/acme-001/employee
Authorization: Bearer <company-token>
Content-Type: application/json
json — request body
{
  "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"
}
FieldRequiredNotes
name, externalIdexternalId must be unique within the company.
legalEntityIdone of UUID returned when creating the legal entity.
legalEntityExternalIdone 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, positionOptional employee details.
isSupervisorMarks the user as a supervisor.
supervisorExternalIdThe externalId of this employee's supervisor.

3.2 Update an Employee

Send only the fields you want to change, identified by externalId:

http
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

http
GET v1/external-api/public/company/acme-001/employee?externalId=acme-emp-42
Authorization: Bearer <company-token>

3.4 Deactivate an Employee

http
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.

http — generate SSO URL
GET v1/external-api/public/company/acme-001/employee/acme-emp-42/auth-url
Authorization: Bearer <company-token>
json — response
{ "url": "https://your-company.day.io/?ot_token=WU4XXXXXXXXXXX&page=punches" }
  • Redirect the user's browser to the returned url to complete login.
  • The ot_token can 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

company:created A company is created.
company:updateAllFields A company is updated.
legalEntity:created A legal entity is created.
legalEntity:updated A legal entity is updated.
legalEntity:deactivated A legal entity is deactivated.
userProfile:created An employee is created.
userProfile:updateAllFields An employee is updated.
payrollGroup:userProfile:assigned An employee is assigned to a payroll group.
schedule:userProfile:assigned An employee is assigned to a schedule.
businessRulesGroup:userProfile:assigned An employee is assigned to a business-rules group.
punches:report A punches report is produced.
userProfile:missingDayScores Missing-day scores are produced for an employee.

6. Quick Start (end-to-end)

bash — complete integration flow
# 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

EndpointMethodTokenPurpose
…/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.