xYago APIv1

Getting started

The xYago API connects your ERP, payroll or any other system with xYago: sync areas, employees, vacations and time entries, and receive a signed webhook whenever something changes.

The API reference (endpoint summaries and descriptions) is written in Spanish, the language of most xYago customers. Field names, error codes and event names are English and stable; this English guide covers every concept you need.

Base URL (production and sandbox):

https://api.xyago.com/v1

Everything is UTF-8 JSON, timestamps are ISO 8601 UTC (2026-03-02T14:05:00Z) and phone numbers use E.164 (+573005550123). See the API reference, or download the OpenAPI spec or the Postman collection.

Your first request in 5 minutes

  1. Enable the API in the sandbox. A company administrator opens the xYago admin panel → API Developer, selects the Test environment and enables the products you need (e.g. Areas and Employees).
  2. Create a sandbox API key. In Credentials → New credential: give it a name (e.g. "Siesa test") and select the scopes you need (areas:read, employees:read...). The full key (xy_test_...) is shown only once: store it in your secrets manager.
  3. Make the first call. The sandbox returns fixed example data, so you can experiment safely.

curl

export XYAGO_API_KEY="xy_test_EXAMPLE_replace-with-your-sandbox-key"

curl "https://api.xyago.com/v1/areas?limit=1" \
  -H "Authorization: Bearer $XYAGO_API_KEY"

Python

import os

import requests  # pip install requests

response = requests.get(
    "https://api.xyago.com/v1/areas",
    params={"limit": 1},
    headers={"Authorization": f"Bearer {os.environ['XYAGO_API_KEY']}"},
    timeout=30,
)
response.raise_for_status()
print(response.json())

JavaScript

// Node.js 18+ (native fetch). Save as first-call.mjs
const response = await fetch("https://api.xyago.com/v1/areas?limit=1", {
  headers: { Authorization: `Bearer ${process.env.XYAGO_API_KEY}` },
});
const data = await response.json();
if (!response.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data);

C#

using System.Net.Http.Headers;

using var http = new HttpClient { BaseAddress = new Uri("https://api.xyago.com/v1/") };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("XYAGO_API_KEY"));

var response = await http.GetAsync("areas?limit=1");
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");

Response (200 OK):

{
  "results": [
    {
      "id": "51f510d8-6482-5355-b5c3-5f511c06d851",
      "public_id": "AR-0002",
      "name": "Administracion",
      "parent_id": null,
      "status": "active",
      "minimum_employees": 1,
      "maximum_employees": 4,
      "skills": [],
      "created_at": "2026-01-17T09:00:00Z",
      "updated_at": "2026-01-17T09:00:00Z"
    }
  ],
  "next_cursor": "eyJ0IjogIjIwMjYtMDEtMTdUMDk6MDA6MDAiLCAiaWQiOiAiNTFmNTEwZDgtNjQ4Mi01MzU1LWI1YzMtNWY1MTFjMDZkODUxIn0"
}

A 401 invalid_api_key means the header is wrong; 403 api_disabled means the product is not enabled in the panel's Test environment. See the error table.

What you can do

ProductEndpointsScopes
AreasGET /areas, GET /areas/{id}, POST /areasareas:read, areas:write
EmployeesGET /employees, GET /employees/{id}, POST /employees, PATCH /employees/{id}, POST /employees/{id}/deactivate, POST /employees/import, GET /employees/import/{job_id}employees:read, employees:write
VacationsGET /vacations, POST /vacations, PATCH /vacations/{id}/approve, PATCH /vacations/{id}/reject, GET /employees/{id}/vacation-balancevacations:read, vacations:write
Time entriesGET /time-entries, POST /time-entriestime:read, time:write

Plus webhooks to learn about changes without polling.

Typical ERP integration (e.g. Siesa)

  1. Initial load: import your employees with POST /employees/import, using the ERP employee code as external_id.
  2. Hires and changes: when the ERP creates or updates an employee, call POST /employees or PATCH /employees/{id} (look up the xYago id with GET /employees?external_id=...). See idempotency.
  3. Terminations: POST /employees/{id}/deactivate.
  4. Payroll: read hours with GET /time-entries and vacations with GET /vacations, or subscribe to time_entry.created and vacation.approved.

Going live

  1. In the panel, Live environment: enable the same products, set the rate limit and, recommended, the IP allowlist of your servers.
  2. Create an xy_live_... credential with the minimum scopes.
  3. Register your webhooks in the Live environment and store their signing secret.
  4. Only the API key changes: the base URL is the same.

Never put an API key in source code, a mobile app or a browser: the API is designed for server-to-server calls.