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
- 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).
- 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. - 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
| Product | Endpoints | Scopes |
|---|---|---|
| Areas | GET /areas, GET /areas/{id}, POST /areas | areas:read, areas:write |
| Employees | GET /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 |
| Vacations | GET /vacations, POST /vacations, PATCH /vacations/{id}/approve, PATCH /vacations/{id}/reject, GET /employees/{id}/vacation-balance | vacations:read, vacations:write |
| Time entries | GET /time-entries, POST /time-entries | time:read, time:write |
Plus webhooks to learn about changes without polling.
Typical ERP integration (e.g. Siesa)
- Initial load: import your employees with
POST /employees/import, using the ERP employee code asexternal_id. - Hires and changes: when the ERP creates or updates an employee, call
POST /employeesorPATCH /employees/{id}(look up the xYago id withGET /employees?external_id=...). See idempotency. - Terminations:
POST /employees/{id}/deactivate. - Payroll: read hours with
GET /time-entriesand vacations withGET /vacations, or subscribe totime_entry.createdandvacation.approved.
Going live
- In the panel, Live environment: enable the same products, set the rate limit and, recommended, the IP allowlist of your servers.
- Create an
xy_live_...credential with the minimum scopes. - Register your webhooks in the Live environment and store their signing secret.
- 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.