Public API

Build powerful integrations

Access leave data, create requests, and sync your HR systems with the OrOut REST API.

Quick Start

1

Get your API key

Navigate to Settings → Integrations in your OrOut dashboard and generate an API key. Keep it secure!

2

Make your first request

Include your API key in the X-Api-Key header:

# List all users in your organization
curl -X GET "https://api.orout.co/public/v1/users" \
  -H "X-Api-Key: orro_live_your_api_key_here"
3

Explore the API

Use our interactive API reference to explore endpoints, test requests, and generate code samples.

Open API Reference

Available Endpoints

Users

List and retrieve user profiles in your organization.

GET /public/v1/users GET /public/v1/users/{id}

Leave Types

Retrieve available leave types configured for your organization.

GET /public/v1/leave-types GET /public/v1/leave-types/{id}

Allowances

Query user leave allowances and balances.

GET /public/v1/allowances

Leave Requests

Full CRUD operations for managing leave requests.

GET /public/v1/leave-requests GET /public/v1/leave-requests/{id} POST /public/v1/leave-requests PATCH /public/v1/leave-requests/{id} DELETE /public/v1/leave-requests/{id}

Documents

Access documents attached to leave requests (read-only).

GET /public/v1/leave-requests/{id}/documents GET /public/v1/leave-requests/{id}/documents/{docId}/download-url

Overtime / TOIL

Full CRUD operations for overtime submissions and TOIL balance queries.

GET /public/v1/overtime GET /public/v1/overtime/{id} GET /public/v1/overtime/balance POST /public/v1/overtime PATCH /public/v1/overtime/{id} DELETE /public/v1/overtime/{id}

Coverage

Check team coverage rules before submitting leave requests.

POST /public/v1/coverage/check

Hours Worked

Shift Workers

Submit worked hours from external rostering systems. Automatically accrues leave for shift workers.

POST /public/v1/hours-worked POST /public/v1/hours-worked/bulk GET /public/v1/users/{externalUserId}/hours-allowance GET /public/v1/users/{externalUserId}/hours-allowances

Webhooks

Real-time

Subscribe to real-time events for leave requests, allowance changes, and more.

GET /public/v1/webhooks GET /public/v1/webhooks/{id} POST /public/v1/webhooks PUT /public/v1/webhooks/{id} DELETE /public/v1/webhooks/{id}

Code Examples

Create a leave request

const response = await fetch('https://api.orout.co/public/v1/leave-requests', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'orro_live_your_api_key_here'
  },
  body: JSON.stringify({
    userId: '550e8400-e29b-41d4-a716-446655440000',
    leaveTypeId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
    startDate: '2025-01-15',
    endDate: '2025-01-17',
    notes: 'Family holiday'
  })
});

const leaveRequest = await response.json();
console.log(leaveRequest.id); // New leave request ID

List leave requests with filters

const params = new URLSearchParams({
  status: 'Approved',
  startDateFrom: '2025-01-01',
  startDateTo: '2025-12-31',
  pageSize: '50'
});

const response = await fetch(
  `https://api.orout.co/public/v1/leave-requests?${params}`,
  {
    headers: {
      'X-Api-Key': 'orro_live_your_api_key_here'
    }
  }
);

const { items, totalCount, hasNextPage } = await response.json();

Check coverage before submitting leave

const response = await fetch('https://api.orout.co/public/v1/coverage/check', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'orro_live_your_api_key_here'
  },
  body: JSON.stringify({
    userId: '550e8400-e29b-41d4-a716-446655440000',
    startDate: '2026-02-10',
    endDate: '2026-02-14',
    includeDailyBreakdown: true
  })
});

const result = await response.json();
if (result.hasViolation) {
  console.warn(result.message); // "Team coverage would drop below 60%"
}

Create an overtime submission

const response = await fetch('https://api.orout.co/public/v1/overtime', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'orro_live_your_api_key_here'
  },
  body: JSON.stringify({
    userId: '550e8400-e29b-41d4-a716-446655440000',
    date: '2026-01-18',
    hoursWorked: 4.5,
    description: 'Weekend deployment support'
  })
});

const submission = await response.json();
console.log(submission.id); // New overtime submission ID
console.log(`TOIL accrued: ${submission.toilHoursAccrued} hours`);

Get TOIL balance for a user

const userId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
  `https://api.orout.co/public/v1/overtime/balance?userId=${userId}`,
  {
    headers: {
      'X-Api-Key': 'orro_live_your_api_key_here'
    }
  }
);

const balance = await response.json();
console.log(`Available: ${balance.totalHoursAvailable} hours`);
console.log(`Expiring soon: ${balance.hoursExpiringSoon} hours`);

List and download leave request documents

const leaveRequestId = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';

// List documents
const response = await fetch(
  `https://api.orout.co/public/v1/leave-requests/${leaveRequestId}/documents`,
  {
    headers: { 'X-Api-Key': 'orro_live_your_api_key_here' }
  }
);
const documents = await response.json();

// Get download URL for a specific document
const docId = documents[0].id;
const urlResponse = await fetch(
  `https://api.orout.co/public/v1/leave-requests/${leaveRequestId}/documents/${docId}/download-url`,
  {
    headers: { 'X-Api-Key': 'orro_live_your_api_key_here' }
  }
);
const { url } = await urlResponse.json();
// Use url to download - valid for 15 minutes

Submit hours worked from rostering system

// Single submission
const response = await fetch('https://api.orout.co/public/v1/hours-worked', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'orro_live_your_api_key_here'
  },
  body: JSON.stringify({
    externalUserId: 'EMP-12345',  // Your system's employee ID
    date: '2026-01-15',
    hoursWorked: 8.5,
    leaveTypeId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
  })
});

const result = await response.json();
console.log(`Accrued: ${result.hoursAccrued} hours`);
console.log(`New balance: ${result.newBalance} hours`);

Bulk submit hours (end of week/month)

const response = await fetch('https://api.orout.co/public/v1/hours-worked/bulk', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'orro_live_your_api_key_here'
  },
  body: JSON.stringify({
    submissions: [
      { externalUserId: 'EMP-001', date: '2026-01-15', hoursWorked: 10 },
      { externalUserId: 'EMP-001', date: '2026-01-16', hoursWorked: 8 },
      { externalUserId: 'EMP-002', date: '2026-01-15', hoursWorked: 12 }
    ]
  })
});

const result = await response.json();
console.log(`Processed: ${result.processedCount}/${result.totalCount}`);

Subscribe to leave request events

const response = await fetch('https://api.orout.co/public/v1/webhooks', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Api-Key': 'orro_live_your_api_key_here'
  },
  body: JSON.stringify({
    url: 'https://your-app.com/webhooks/orout',
    eventTypes: [
      'leave_request.approved',
      'leave_request.rejected',
      'leave_request.cancelled'
    ],
    description: 'Sync leave to rostering system'
  })
});

const webhook = await response.json();
console.log(`Webhook ID: ${webhook.id}`);
console.log(`Secret: ${webhook.signingSecret}`); // Store securely!

Verify webhook signature (Node.js)

import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler:
app.post('/webhooks/orout', (req, res) => {
  const signature = req.headers['x-orout-signature'];
  const payload = JSON.stringify(req.body);

  if (!verifyWebhookSignature(payload, signature, process.env.OROUT_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook event
  const { eventType, data } = req.body;
  console.log(`Received: ${eventType}`, data);

  res.status(200).send('OK');
});

Rate Limiting

Request Limits

API requests are limited to 1,000 requests per hour per organization. Exceeding this limit will result in a 429 Too Many Requests response.

Rate Limit Headers

Each response includes headers to help you track your usage:

Header Description
X-RateLimit-Limit Maximum requests allowed per hour
X-RateLimit-Remaining Requests remaining in current window
Retry-After Seconds to wait before retrying (only on 429)

Authentication

API Key Format

API keys follow the format:

orro_live_xxxxxxxxxxxxxxxxxxxxxxxx

Security Best Practices

  • Never expose keys in client-side code
  • Use environment variables
  • Regenerate if compromised

Ready to integrate?

Get your API key and start building today.