# hecigo Developer Resources

Everything hecigo publishes for developers and for automated clients, in one
place. This page is the index; each entry below is a stable, predictable URL you
can bookmark or hard-code.

If you are an AI agent, start with
[hecigo.com/llms.txt](https://hecigo.com/llms.txt), which names what this site is
for and when to reach for us.

## Open-source n8n nodes by hecigo

hecigo maintains two n8n community nodes on npm. Both are MIT licensed, both are
used outside our own projects, and both take issues.

### n8n-nodes-zalo-platform

An n8n community node for the Zalo Bot Platform: send messages, photos and
stickers, and manage webhooks. Zalo is the dominant messaging platform in
Vietnam, and this node is what we use to reach it from an n8n workflow.

- npm: https://www.npmjs.com/package/n8n-nodes-zalo-platform
- Source and README: https://github.com/hecigo/n8n-nodes-zalo-platform
- Install in n8n: **Settings → Community Nodes → Install →** `n8n-nodes-zalo-platform`
- Install from a shell: `npm install n8n-nodes-zalo-platform`
- Licence: MIT
- What breaks in production, written up honestly:
  [Running a Zalo bot on n8n: what breaks between test mode and production](https://hecigo.com/blog/n8n-zalo-bot-node-what-breaks-in-production/)

### n8n-nodes-firecrawl-v2

An n8n community node covering the Firecrawl v2 API (scrape, crawl, map,
search, extract, and the batch operations) against both Firecrawl Cloud and a
self-hosted instance. Ten operations, six of which return web content and are
not interchangeable.

- npm: https://www.npmjs.com/package/n8n-nodes-firecrawl-v2
- Source and README: https://github.com/hecigo/n8n-nodes-firecrawl-v2
- Install in n8n: **Settings → Community Nodes → Install →** `n8n-nodes-firecrawl-v2`
- Install from a shell: `npm install n8n-nodes-firecrawl-v2`
- Licence: MIT
- Which operation to reach for:
  [Firecrawl on n8n: picking the right operation, and what async does to your workflow](https://hecigo.com/blog/n8n-firecrawl-node-choosing-the-right-operation/)

All hecigo source lives under the GitHub organisation
[github.com/hecigo](https://github.com/hecigo). Issues and pull requests on either
node are the fastest route to a case being covered.

## Machine-readable endpoints on hecigo.com

| Endpoint | Format | What it is |
| --- | --- | --- |
| [/llms.txt](https://hecigo.com/llms.txt) | Markdown, llmstxt.org | Site summary, when to use hecigo, and a link index |
| [/llms-full.txt](https://hecigo.com/llms-full.txt) | Markdown | Every public page and post concatenated, for a single fetch |
| [/agent-instructions.md](https://hecigo.com/agent-instructions.md) | Markdown | How an agent should call, cite, and hand off to hecigo |
| [/openapi.json](https://hecigo.com/openapi.json) | OpenAPI 3.1 | Every endpoint on this page, described formally |
| [/sitemap.xml](https://hecigo.com/sitemap.xml) | XML | Every indexable URL, with last-modified dates |
| [/robots.txt](https://hecigo.com/robots.txt) | Text | Crawl rules; no AI crawler is blocked |
| [/blog-index.json](https://hecigo.com/blog-index.json) | JSON | Blog metadata: slug, title, description, date, tags, language |

Everything above is public, unauthenticated, CORS-open, and free to fetch. There
is no rate limit beyond the CDN's own abuse protection. Please send a user agent
that identifies your client.

### The OpenAPI document

[/openapi.json](https://hecigo.com/openapi.json) describes this surface in
OpenAPI 3.1: every path above, the Accept negotiation on canonical page URLs,
the schema of `blog-index.json`, and the shape of the error bodies. It is
generated from the same manifest the negotiation runs on, so a retired post
cannot linger in it.

Read what it is carefully, because the word "API" invites the wrong assumption:
it documents a **read-only website surface**, not a hosted hecigo product. Every
operation is a GET. There is no API key, no OAuth flow, no write path, and no
multi-tenant hecigo service behind it. hecigo builds middleware inside client
infrastructure, and that middleware is the client's, not a platform we rent out.

## Markdown content negotiation

Every public page on hecigo.com is available as Markdown at the same URL. Send
`Accept: text/markdown` and you get clean prose instead of a page of layout
markup, per the convention documented at
[acceptmarkdown.com](https://acceptmarkdown.com/):

```bash
curl -s -H "Accept: text/markdown" https://hecigo.com/
curl -s -H "Accept: text/markdown" https://hecigo.com/blog/n8n-zalo-bot-node-what-breaks-in-production/
```

Responses carry `Content-Type: text/markdown; charset=utf-8` and
`Vary: Accept, Accept-Encoding`. Q-values are honoured, so a browser's
`Accept: text/html,...,*/*;q=0.8` still gets HTML.

Every page also ships a `.md` sibling if you would rather address it directly,
advertised on the HTML response as
`Link: </index.md>; rel="alternate"; type="text/markdown"`:

```bash
curl -s https://hecigo.com/index.md
curl -s https://hecigo.com/developers.md
```

A request for a path that does not exist returns a real **HTTP 404**, and a
request whose `Accept` header we genuinely cannot satisfy returns **406 Not
Acceptable** rather than silently handing back the wrong format. Both answer in
a format you can parse; see [Errors](#errors) below.

## Errors

Errors on this site default to JSON, shaped per RFC 9457. You do not have to ask
for it:

```bash
curl -s https://hecigo.com/no-such-page/
curl -s https://hecigo.com/blog/no-such-post.md
```

```json
{
  "type": "https://hecigo.com/developers/#http-404",
  "title": "Not Found",
  "status": 404,
  "detail": "There is no page at /no-such-page/ on hecigo.com.",
  "instance": "/no-such-page/",
  "code": "not_found",
  "resolution": "Fetch https://hecigo.com/llms.txt for the link index or https://hecigo.com/sitemap.xml for every URL. ...",
  "documentation_url": "https://hecigo.com/developers/#errors",
  "links": { "agentIndex": "https://hecigo.com/llms.txt", "...": "..." }
}
```

Branch on `code`, not on the prose in `title` or `detail`. There are two values:
`not_found` and `representation_not_available`.

### Why JSON is the default

Because of what the wire actually tells us. A browser names `text/html` outright
in its `Accept` header, so a person who mistypes a URL still gets the rendered
404 page. `curl`, `fetch`, and every HTTP client library send `*/*` or no
`Accept` header at all, and the catch-all wildcard is not a claim to read HTML.
That is the whole distinction:

| What you send | What a 404 gives you |
| --- | --- |
| Nothing, or `*/*` | JSON problem document |
| `Accept: application/json` | JSON problem document |
| `Accept: text/markdown` | The Markdown recovery map |
| `Accept: text/html`, which is what a browser sends | The rendered 404 page |

This used to be the other way round: JSON arrived only if you named it, and
everything else got prose. An agent with a default header had no way to guess
which header would have worked.

### The status code is chosen on evidence

#### HTTP 404

There is no such path. The body names the path it is answering about, so an
agent fetching several dead URLs can tell the responses apart, and `resolution`
points at `/llms.txt` and `/sitemap.xml`.

#### HTTP 406

The path exists, but no representation matches your `Accept` header. The
`available` member names the two formats it does have. Calling this a 404 would
say the page is not there; calling a genuine 404 a 406 would say a dead path is
real and worth retrying in another format. The 406 body is JSON in every case,
including when you asked for something we have never heard of.

### Every error carries links in its headers

Including the HTML 404 page, which is how a client that cannot parse the page
still finds its way to this document:

```
Link: <https://hecigo.com/openapi.json>; rel="service-desc"; type="application/vnd.oai.openapi+json",
      <https://hecigo.com/llms.txt>; rel="service-doc"; type="text/plain",
      <https://hecigo.com/developers/#errors>; rel="help"; type="text/html"
```

Error responses carry `Vary: Accept, Accept-Encoding` and `Cache-Control: no-store`,
since the format of the body is chosen from a request header.

One limit worth knowing: paths that carry a non-document extension, such as
`/og-image.png`, are not routed through negotiation at all, so their errors are
the CDN's own. The document extensions `.md`, `.txt`, `.json` and `.xml` are.

## What hecigo does not publish

Stated plainly so nobody wastes an afternoon looking:

- **No hosted product API.** `/openapi.json` describes this website's read-only
  surface, and nothing more. hecigo builds middleware inside client
  infrastructure; there is no multi-tenant hecigo service to call, no API key,
  and no OAuth flow.
- **No write endpoints.** Every documented operation is a GET.
- **No webhooks you can subscribe to.** The only webhook on this domain is the
  enquiry-form intake, which is ours, not yours.

The public, usable surface is the two n8n nodes and the endpoints above. When
there is more, this page is where it appears.

## Getting in touch about the code

- Bugs and feature requests on the nodes: open an issue on the relevant GitHub
  repository, with the payload that broke it.
- Everything else: hi@hecigo.com, or the form at
  [hecigo.com/contact](https://hecigo.com/contact/).
