Kevin Canlas API documentation

This site exposes small, public, read-only resources rather than an account or developer dashboard. No API key, signup, OAuth flow, or authentication header is required for the documented GET routes. The data can be temporarily unavailable when a documented public upstream source is unavailable.

  • API catalog — linkset for the actual public API endpoints.
  • Sitemap — published HTML routes, excluding API responses and drafts.

API discovery

GET /api

The API index describes the two public data routes, their documentation, the OpenAPI specification, and the authentication policy. It returns JSON with authentication: "none" and is useful when a client needs to discover the service before selecting an endpoint. It is cached with Cache-Control: public, max-age=3600.

curl -i https://www.kevincanlas.com/api

The index is a discovery document, not a replacement for the endpoint schemas below or the OpenAPI specification.

Versioning and deprecation policy

Use /api/v1/mon-price and /api/v1/github-contributions for the explicit version 1 contract. The existing /api/mon-price and /api/github-contributions paths remain version 1 aliases and return the same payloads directly, without redirects. Existing portfolio behavior is unchanged.

Version 1 preserves the documented field names, types, units, and meanings. An incompatible contract requires a new major-version path, such as /api/v2/; the unversioned aliases will not silently switch versions. Current timestamps and public upstream data remain variable by design.

No version or alias is currently deprecated, and no removal date is scheduled. If a route is deprecated later, this page will document the migration and affected URLs, and its responses will include the RFC 9745 Deprecation header as a Structured Field date. A scheduled removal will also use the RFC 8594 Sunset header as an HTTP date, not earlier than the deprecation date. These headers are absent while no deprecation or removal is scheduled.

Public endpoints

Function-call inputs

Both data operations take zero arguments: no path parameters, query parameters, or request body. The OpenAPI operations explicitly declare an empty parameters array. When adapting a GET operation to a function tool, use the operationId as its name, its description as guidance, and the empty-object input schema below. Execute the documented GET URL without a body; do not invent arguments just to create a non-empty schema.

{ "type": "object", "properties": {}, "required": [], "additionalProperties": false }

GET /api/mon-price

Returns the current MON-USD market preview and the seven-day hourly history used by the portfolio. It accepts no parameters and requires no authentication. The response is read-only market data from Coinbase Exchange; it is not trading advice.

The JSON response contains product ("MON-USD"), currency ("USD"), source ("Coinbase"), windowSeconds (604800), points (chronological { time, value } entries), value, changePercent, low, high, and asOf (the source timestamp). time values are Unix seconds; asOf is an ISO 8601 timestamp.

curl -i https://www.kevincanlas.com/api/v1/mon-price

Caching: successful responses send Cache-Control: private, no-store. The server may reuse candle history in memory for up to five minutes, while the current ticker is fetched without a framework or upstream cache. A caller should treat values and timestamps as changing data.

GET /api/github-contributions

Returns the public contribution calendar for the fixed GitHub account kvncnls over a rolling 365-day window ending on the current date in America/Toronto. It accepts no parameters and requires no authentication. The route reports the public calendar it can read; it does not promise completeness if GitHub changes, limits, or withholds that source.

The JSON response contains username, totalContributions, startDate, endDate, days, timeZone, and nextRefreshAt. Each days entry contains an ISO date, a non-negative count, and GitHub’s contribution intensity level from 0 through 4.

curl -i https://www.kevincanlas.com/api/v1/github-contributions

Caching: successful responses send Cache-Control: public, max-age=0, s-maxage=<seconds-until-next-Toronto-midnight>, stale-while-revalidate=300. The server keeps one rolling-year response in memory until the next Toronto midnight. Clients should read the returned nextRefreshAt when they need to understand the refresh boundary.

Rate limits

The site supports an optional shared, per-client fixed-window quota for GET and HEAD requests to the two data endpoints, including their version 1 aliases. All four URLs share the same bucket, so switching aliases does not reset a client's allowance. The site does not advertise an allowance unless a configured shared store has actually accounted for the request.

When enforcement is active, responses include RateLimit-Policy and RateLimit using the current IETF RateLimit draft, which is not yet a published RFC. For example, a configured allowance of 100 requests per 60 seconds would use RateLimit-Policy: "public-api";q=100;w=60 and RateLimit: "public-api";r=99;t=60 after the first request. These numbers illustrate the format; they are not a promised quota. Read the actual response headers for the configured allowance, remaining requests, and seconds until reset.

An exhausted quota returns 429 problem JSON with code: "rate_limit_exceeded" and an integer-seconds Retry-After header. Wait at least that long before retrying. Quota-bearing responses are not shared-cacheable. If the quota service is unconfigured, cannot identify a trusted client, or is unavailable, reads remain available without quota headers; missing headers do not guarantee unlimited upstream capacity. The quota does not apply to HTML pages or discovery documents.

Errors

API errors use application/problem+json. The response has stable type, title, status, detail, code, and resolution fields; an error field can remain for compatibility with older callers. The type URLs below are documentation fragments, so clients can use them as stable identifiers and people can open the relevant explanation.

Upstream unavailable

HTTP status: 502. Code: upstream_unavailable. Type: `https://www.kevincanlas.com/developers#upstream-unavailable`. The public Coinbase or GitHub source did not provide usable data. Retry the request later; the route does not turn an upstream failure into a fabricated success payload.

API route not found

HTTP status: 404. Code: api_route_not_found. Type: `https://www.kevincanlas.com/developers#api-route-not-found`. No documented public API route matches the requested /api/... path. Check the API catalog or OpenAPI specification.

Method not allowed

HTTP status: 405. Code: method_not_allowed. Type: `https://www.kevincanlas.com/developers#method-not-allowed`. The route is read-only. Use GET to read data or HEAD to inspect the response headers; unsupported write methods return a problem response with an Allow header.

Rate limit exceeded

HTTP status: 429. Code: rate_limit_exceeded. Type: `https://www.kevincanlas.com/developers#rate-limit-exceeded`. The configured shared request allowance is exhausted. Respect Retry-After; sending requests to a version alias does not bypass the allowance. This response is possible only when shared quota enforcement is configured and operational.

curl -i https://www.kevincanlas.com/api/does-not-exist
curl -i -X POST https://www.kevincanlas.com/api/mon-price

CLI

The repository CLI entry point is a zero-dependency, read-only Node script for the same public resources. The deployed site publishes the exact source at `/cli.mjs`, so you can download it, inspect it, and run it without installing an npm package. This is a repository-contained tool; no npm publication is claimed.

curl -fsSL -o kevincanlas.mjs https://www.kevincanlas.com/cli.mjs
sed -n '1,80p' kevincanlas.mjs
node kevincanlas.mjs --help
node kevincanlas.mjs profile --json

From a repository checkout, run the entry point directly. The commands below cover the profile, published writings, skills, OpenAPI document, and API catalog. Add --json for machine-readable output. Add --base-url http://localhost:3000 when reading a local site instead of the deployed origin.

node packages/cli/bin/kevincanlas.mjs profile
node packages/cli/bin/kevincanlas.mjs writings --json
node packages/cli/bin/kevincanlas.mjs skills --json
node packages/cli/bin/kevincanlas.mjs api
node packages/cli/bin/kevincanlas.mjs catalog --json
node packages/cli/bin/kevincanlas.mjs api --base-url http://localhost:3000
node packages/cli/bin/kevincanlas.mjs catalog --base-url http://localhost:3000 --json

Discovery and Markdown

The OpenAPI specification is the contract for the two data endpoints. The API catalog points to those endpoints and this documentation. For content-oriented clients, read llms.txt, llms-full.txt, or the Markdown alternate at developers.md. The sitemap lists published HTML pages, not JSON responses or drafts.