Quick start
- 1
Sign up free and create an API key in the dashboard.
- 2
Call any endpoint with the x-api-key header.
cURL
curl -H "x-api-key: ga_live_..." "https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check?date=2026-08-17"
Python
import requests
response = requests.get(
"https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check",
params={"date": "2026-08-17"},
headers={"x-api-key": "ga_live_..."},
timeout=30,
)
body = response.json()
print(body["data"] if body["ok"] else body["error"])
JavaScript
const params = new URLSearchParams({"date": "2026-08-17"});
const response = await fetch(`https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check?${params}`, {
headers: { "x-api-key": "ga_live_..." },
});
const body = await response.json();
console.log(body.ok ? body.data : body.error);
PHP
<?php
$ch = curl_init('https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check?' . http_build_query(['date' => '2026-08-17']));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['x-api-key: ga_live_...'],
CURLOPT_TIMEOUT => 30,
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($body['ok'] ? $body['data'] : $body['error']);
Go
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
params := url.Values{}
params.Set("date", "2026-08-17")
req, _ := http.NewRequest("GET", "https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check?"+params.Encode(), nil)
req.Header.Set("x-api-key", "ga_live_...")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var body map[string]any
json.NewDecoder(res.Body).Decode(&body)
fmt.Println(body["data"])
}
Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check?date=2026-08-17"))
.header("x-api-key", "ga_live_...")
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
Ruby
require "net/http"
require "json"
uri = URI("https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check")
uri.query = URI.encode_www_form({"date" => "2026-08-17"})
request = Net::HTTP::Get.new(uri)
request["x-api-key"] = "ga_live_..."
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
body = JSON.parse(response.body)
puts body["ok"] ? body["data"] : body["error"]
C#
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "ga_live_...");
var json = await client.GetStringAsync("https://kajidata.artonlabs.com/v1/indonesia:hari-libur/check?date=2026-08-17");
Console.WriteLine(json);
URL pattern: GET https://kajidata.artonlabs.com/v1/{category}:{api}/{endpoint}
Authentication
The key can also be sent as Authorization: Bearer … or the api_key query parameter (avoid the latter in production because URLs end up in logs). Add Accept-Language: id for Indonesian error messages.
Response format
Success
{
"ok": true,
"project": "indonesia:hari-libur",
"endpoint": "check",
"data": {
"date": "2026-08-17",
"is_holiday": true,
"name": "...",
"is_weekend": false
},
"meta": {
"request_id": "9f2c1a7b3e5d4c21",
"timestamp": "2026-11-01T05:05:18+00:00",
"latency_ms": 300,
"cached": false,
"stale": false,
"cost": 1,
"quota_remaining": 999,
"source": "Nager.Date",
"fetched_at": "2026-11-01T05:05:18+00:00"
}
}
Error
{
"ok": false,
"error": {
"code": "invalid_params",
"message": "...",
"details": [
{
"loc": [
"date"
],
"msg": "..."
}
]
},
"meta": {
"request_id": "...",
"timestamp": "..."
}
}
| Field | Meaning |
|---|---|
| meta.cached | true: served from cache, not billed |
| meta.stale | true: the source failed and this is the last good copy |
| meta.cost | quota used by this request |
| meta.source | the source that actually answered |
| meta.fetched_at | when the data was fetched from the source |
Error codes & billing
Only 200 responses fetched directly from the source use quota. Cache hits and stale copies are free.
| Code | HTTP | Billed? | Meaning |
|---|---|---|---|
| missing_api_key | 401 | no | The x-api-key header is missing |
| invalid_api_key | 401 | no | The key is wrong or has been revoked |
| plan_required | 403 | no | The API needs a higher plan |
| not_found | 404 | no | Endpoint or data (e.g. an area code) does not exist |
| invalid_params | 422 | no | details lists the invalid fields |
| rate_limited | 429 | no | Too many requests per second; see Retry-After |
| quota_exceeded | 429 | no | This month's quota is used up |
| upstream_error | 502 | no | Every source failed and no saved copy exists yet |
| upstream_timeout | 504 | no | The source took too long to respond |
| unavailable | 503 | no | The gateway is temporarily unavailable; retry later |
Response headers
- X-Request-Id
- Include it when contacting support.
- X-Cache
- HIT, MISS or STALE.
- X-Request-Cost
- Quota used by this request.
- X-Quota-Remaining
- Quota left this month.
- X-Latency-Ms
- Time spent in the gateway.
- Retry-After
- Seconds to wait after a rate_limited error.
OpenAPI, SDKs and AI agents
Use a generator such as openapi-generator to build a client in any language. For AI agents, see the MCP server and llms.txt.