feriados.io ← Inicio
apienglishbusiness-dayslatamcalendars

Custom Business Calendars via API: Company-Specific Non-Working Days

How to manage company-specific non-working days — plant shutdowns, collective vacations, trade fairs — via API and apply them to any business day calculation in LATAM.

4 de abril de 2026

Public holidays in Chile, Colombia, or Mexico are well-documented and updated by someone else. Your company’s own non-working days are not. Annual plant maintenance, industry trade fairs, collective vacation periods, end-of-year shutdowns — these need to live somewhere, and in most companies that somewhere is a hardcoded array, an environment variable, or a spreadsheet that HR updates once a year and nobody else remembers to check.

The result is predictable: a cron job that fires during a plant shutdown, a delivery date that lands on collective vacations, an SLA deadline calculated without accounting for a company-wide closure.

The standard approach and why it breaks

Most teams end up with something like this:

// The classic approach
const COMPANY_CLOSURES = [
  "2026-07-15", // Annual maintenance
  "2026-12-26", // Year-end closure
  "2026-12-27",
  "2026-12-28",
];

function isWorkingDay(date, country) {
  if (COMPANY_CLOSURES.includes(date)) return false;
  // ... official holiday logic
}

The problem is not the logic — it’s the coupling. These dates live in the codebase, which means:

An environment variable or internal database doesn’t solve the coordination problem — it just moves it.

A cleaner approach: custom calendars via API

The idea: define a calendar with a name and a slug, add your company’s non-working dates to it, then use ?calendar=slug as an overlay parameter on any business day calculation. Official country holidays still apply — your calendar adds on top.

Create the calendar

curl -X POST https://api.feriados.io/v1/calendars \
  -H "Authorization: Bearer frd_your_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Plant North", "slug": "plant-north"}'
{
  "success": true,
  "data": {
    "id": "01HZ...",
    "name": "Plant North",
    "slug": "plant-north",
    "created_at": "2026-04-04T12:00:00.000Z"
  }
}

Add non-working dates

curl -X POST https://api.feriados.io/v1/calendars/plant-north/dates \
  -H "Authorization: Bearer frd_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "dates": [
      { "date": "2026-07-15", "name": "Annual maintenance" },
      { "date": "2026-12-26", "name": "Year-end closure" },
      { "date": "2026-12-27", "name": "Year-end closure" },
      { "date": "2026-12-28", "name": "Year-end closure" }
    ]
  }'

Up to 100 dates per request. Duplicates are silently ignored, so running the same script twice is safe.

Use the calendar in calculations

Once the calendar is set up, any business day endpoint accepts ?calendar=slug:

# Is July 15th a working day at Plant North?
curl "https://api.feriados.io/v1/CL/is-business-day?date=2026-07-15&calendar=plant-north" \
  -H "Authorization: Bearer frd_your_key"
{
  "success": true,
  "data": {
    "date": "2026-07-15",
    "is_business_day": false,
    "day_of_week": "Wednesday",
    "region": null
  },
  "meta": { "country": "CL", "calendar": "plant-north", "total": 1 }
}

Wednesday, July 15 has no official Chilean holiday — but the API returns false because it’s registered as a plant closure. Without ?calendar, it would return true.

Practical examples

Cron jobs that skip company shutdowns

const API = "https://api.feriados.io/v1";
const HEADERS = { Authorization: `Bearer ${process.env.FERIADOS_API_KEY}` };

async function isWorkingDayToday(country, calendar) {
  const today = new Date().toISOString().slice(0, 10);
  const url = `${API}/${country}/is-business-day?date=${today}&calendar=${calendar}`;
  const { data } = await fetch(url, { headers: HEADERS }).then(r => r.json());
  return data.is_business_day;
}

// Skip payroll processing during plant shutdowns
if (await isWorkingDayToday("CL", "plant-north")) {
  await processPayroll();
} else {
  console.log("Plant closed — skipping payroll run");
}

Delivery dates that avoid company closures

async function estimatedDelivery(country, calendar, businessDays = 3) {
  const today = new Date().toISOString().slice(0, 10);
  const url = `${API}/${country}/business-days/add?date=${today}&days=${businessDays}&calendar=${calendar}`;
  const { data } = await fetch(url, { headers: HEADERS }).then(r => r.json());
  return data.result_date;
}

// Order placed July 14 — 3 business days delivery, skipping July 15 maintenance
const delivery = await estimatedDelivery("CL", "plant-north", 3);
// → "2026-07-21" instead of "2026-07-17"

SLA deadlines that account for operational closures

async function slaDeadline(country, calendar, openedAt, slaDays) {
  const url = `${API}/${country}/business-days/add?date=${openedAt}&days=${slaDays}&calendar=${calendar}`;
  const { data } = await fetch(url, { headers: HEADERS }).then(r => r.json());
  return data.result_date;
}

// 5-business-day SLA opened July 13, respecting plant closure on July 15
const deadline = await slaDeadline("CL", "plant-north", "2026-07-13", 5);
// → "2026-07-22" instead of "2026-07-20"

Multiple operations, multiple calendars

If your company operates in multiple countries or has plants with different schedules, use one calendar per context:

const CALENDARS = {
  CL: "plant-santiago",
  CO: "plant-bogota",
  PE: "plant-lima",
};

async function calculateDeadline(country, date, days) {
  const cal = CALENDARS[country];
  const params = cal ? `&calendar=${cal}` : "";
  const url = `${API}/${country}/business-days/add?date=${date}&days=${days}${params}`;
  const { data } = await fetch(url, { headers: HEADERS }).then(r => r.json());
  return data.result_date;
}

Each plant has its own closure schedule. The calculation logic stays the same — only the calendar slug changes.

Keeping calendars up to date

At the start of each year, or whenever closures are confirmed, an upsert script is enough. Duplicates are ignored, so running it multiple times is safe:

curl -X POST https://api.feriados.io/v1/calendars/plant-north/dates \
  -H "Authorization: Bearer frd_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "dates": [
      { "date": "2027-07-14", "name": "Annual maintenance 2027" },
      { "date": "2027-12-26", "name": "Year-end closure 2027" },
      { "date": "2027-12-27", "name": "Year-end closure 2027" }
    ]
  }'

If a date changes, delete the old one and add the corrected date:

curl -X DELETE https://api.feriados.io/v1/calendars/plant-north/dates/2027-07-14 \
  -H "Authorization: Bearer frd_your_key"

No deploys, no environment variable updates, no cross-team coordination.

Plan limits

PlanCalendarsFuture dates per calendar
Free110
Starter3Unlimited
Team10Unlimited
BusinessUnlimitedUnlimited

The ?calendar=slug overlay works on all five business day endpoints: is-business-day, business-days/add, business-days/subtract, business-days/between, and last-business-day.


Custom calendars are available from the Starter plan. The Free plan includes 1 calendar with up to 10 future dates to test the feature. See plans → · Get your free API key →


See also: Custom Calendars documentation → · SLA business days in LATAM → · Business Days API guide →

Integra feriados.io en tu proyecto

API key gratis en 30 segundos. Sin tarjeta. 11 países de Latinoamérica, siempre actualizada con los feriados oficiales.

← Ver todos los artículos