Developers
Everything on marcusboni.com.br that is meant to be read
by a program rather than a person: the machine-readable files, the
content-negotiation contract, and copy-pasteable curl for
each one.
This is a personal portfolio and technical blog. Its API is public, read-only and unauthenticated: no private endpoints, no write operations, no published rate limit, and therefore no API keys to issue and no sandbox to provision. Every endpoint below is the production endpoint, which makes the API its own sandbox.
If you are an agent deciding whether this site answers your question,
read /agent-instructions.md
first. It says plainly what this site is and is not good for.
# The profile, as JSON
curl -s https://marcusboni.com.br/api/v1/profile
# The OpenAPI 3.1 description of every operation
curl -s https://marcusboni.com.br/openapi.json
# The site's own guide for language models
curl -s https://marcusboni.com.br/llms.txt
# Any page, as Markdown instead of HTML
curl -s -H 'Accept: text/markdown' https://marcusboni.com.br/
Read-only representations of the same content the pages publish. The
specification is
OpenAPI 3.1; every operation carries a
unique operationId, a description, typed parameters and a
response schema, so the surface can be handed to a function-calling
runtime unchanged. Discovery also goes through the RFC 9727 catalog at
/.well-known/api-catalog.
| Operation | Endpoint | Returns |
|---|---|---|
getApiIndex |
GET /api/v1 | The operation list and a link to the specification. |
getProfile |
GET /api/v1/profile | Identity, employer, location, contact channels, résumés. |
listProjects |
GET /api/v1/projects | Selected projects with year, stack and repository URL. |
getExperience |
GET /api/v1/experience | Current role and every client engagement, with sector and scope. |
listTechnologies |
GET /api/v1/stack | Technologies, grouped by frontend, backend, data and ops. |
listPosts |
GET /api/v1/posts | Published posts, newest first. Served live, so publishing needs no rebuild. |
getPost |
GET /api/v1/posts/{slug} |
One post, including the Markdown it was authored in. |
Every failure under /api/ is
RFC 9457
application/problem+json — never an HTML error page —
with a stable code and a hint naming the next
thing to try.
{
"type": "https://marcusboni.com.br/developers#error-not-found",
"title": "Not found",
"status": 404,
"detail": "No published post has the slug \"ghost\". Drafts are not readable.",
"instance": "/api/v1/posts/ghost",
"code": "not_found",
"hint": "GET https://marcusboni.com.br/api/v1/posts to list every published post and its slug."
}
| Code | Status | When |
|---|---|---|
not_found |
404 | No such endpoint, or no published post with that slug. |
method_not_allowed |
405 | Anything but GET or HEAD. The API is read-only. |
not_acceptable |
406 |
Your Accept header rules out
application/json.
|
upstream_unavailable |
503 | The content database is unreachable. Transient — retry. |
The major version is in the URL path. /api/v1 is current;
a breaking change ships as /api/v2, never as an edit to
v1. Additive changes — a new endpoint, a new optional
field — happen in place, so
ignore unknown properties rather than failing on them.
A path being retired announces itself on its own responses, before it stops answering:
| Header | Spec | Carries |
|---|---|---|
Deprecation |
RFC 9745 |
When the path was deprecated, as
@<unix-seconds>.
|
Sunset |
RFC 8594 | When it stops responding, as an HTTP date. |
Link |
RFC 8288 |
rel="deprecation", pointing at the explanation.
|
There are at least 180 days between the two dates. Nothing is deprecated today, so none of these headers appears on any current response — the mechanism is in place and tested so that the first deprecation is signalled rather than announced after the fact.
Every HTML document on this site is also available as Markdown from the same URL, following the acceptmarkdown.com convention. Blog posts are written in Markdown and stored that way, so their Markdown representation is the original source, not a conversion of the rendered HTML.
curl -sI -H 'Accept: text/markdown' https://marcusboni.com.br/
# content-type: text/markdown; charset=utf-8
# vary: Accept, Accept-Encoding
Request Accept |
Response |
|---|---|
| absent | text/html — the default representation |
*/* |
text/html |
text/html |
text/html |
text/markdown |
text/markdown; charset=utf-8 |
text/markdown;q=0.9, text/html;q=0.8 |
text/markdown — highest q wins |
text/markdown;q=0 |
text/html — an explicit refusal of Markdown, not
a 406
|
application/pdf |
406 Not Acceptable, with a body listing both
representations
|
Quality values and wildcard specificity are honoured;
text/x-markdown and text/mdx are accepted as
aliases. Every negotiated response carries
Vary: Accept so a shared cache cannot hand an agent the
HTML variant.
Negotiable paths: /, /blog,
/blog/{slug}, /developers, and any unknown
path — which answers 404 in both representations.
| Endpoint | Content type | What it is |
|---|---|---|
| /openapi.json | application/json |
OpenAPI 3.1 description of every API operation. |
| /.well-known/api-catalog | application/linkset+json |
RFC 9727 discovery document pointing at the specification and the docs. |
| /llms.txt | text/plain |
Condensed site guide in llmstxt.org format, including a "when to use this" section. |
| /llms-full.txt | text/plain |
Full profile: bio, every project, every client engagement, the whole stack. |
| /agent-instructions.md | text/markdown |
Best-fit tasks, how to call this site, and what not to infer from it. |
| /sitemap.xml | application/xml |
Indexable URLs, generated per request so a new post is discoverable without a rebuild. |
| /rss.xml | application/xml |
RSS 2.0 feed of published posts. |
| /robots.txt | text/plain |
Crawl directives. Everything is allowed except
/admin.
|
| /marcus-boni-cv-pt.pdf | application/pdf |
Résumé, Portuguese. |
| /marcus-boni-resume-en.pdf | application/pdf |
Résumé, English. |
The home page carries a schema.org Person in JSON-LD;
every blog post carries a BlogPosting, injected into the
delivered HTML at the edge so it is present without executing
JavaScript.
curl -s https://marcusboni.com.br/ | grep -A2 'application/ld+json'
404, never the app shell with a 200. The
body points back at this page, /sitemap.xml and
/llms.txt. A /blog/{slug} with no such
post returns 404 as well.
Accept
header rules out both text/html and
text/markdown.
/marcus-boni-cv.pdf redirects to
the Portuguese résumé, kept alive for links shared before the PT/EN
split.
The prose, résumés and images are © Marcus Boni. Quote and link freely, with attribution to marcusboni.com.br. Code in the linked GitHub repositories carries its own licence per repository.
Something wrong or missing on this page? Email mgalvaoboni@gmail.com.