MFactor para desenvolvedores e agentes

Todo o conteúdo público deste site é servido também em Markdown, sem autenticação e sem raspagem de HTML, e a API da MFactor, empresa de tecnologia de Leme (SP), está descrita em OpenAPI. Esta página documenta como pedir.

O que entregamos

  • API com OpenAPI 3.1
  • Accept: text/markdown
  • Arquivos .md por rota
  • llms.txt
  • CLI oficial

Início rápido

Peça qualquer página do site com o cabeçalho Accept: text/markdown e a resposta vem em Markdown, na mesma URL que o navegador usa para receber HTML. É a convenção descrita em acceptmarkdown.com, sobre o mecanismo de content negotiation do RFC 9110.

# A home em Markdown, na URL canônica
curl -sH 'Accept: text/markdown' https://www.mfactor.dev/

# Uma página de serviço, com os cabeçalhos à vista
curl -sIH 'Accept: text/markdown' https://www.mfactor.dev/servicos/mlabs

# Sem cabeçalho nenhum: o mesmo conteúdo pela URL explícita
curl -s https://www.mfactor.dev/servicos/mlabs.md

O contrato das respostas

  • Content-Type — text/markdown; charset=utf-8 quando o Markdown vence a negociação; text/html; charset=utf-8 no caso contrário.
  • Vary: Accept, Accept-Encoding — Presente em toda resposta negociada, para que um cache intermediário não devolva o HTML a quem pediu Markdown.
  • Link: rel=alternate — Aponta o arquivo .md equivalente, conforme o RFC 8288, para o cliente que descobre representações por link em vez de por cabeçalho.
  • 406 Not Acceptable — Resposta para um Accept que só admite formatos que não servimos. O corpo lista, em texto puro, as representações disponíveis.
  • 404 Not Found — Resposta de um caminho inexistente, com corpo curto apontando o sitemap e o llms.txt. Nunca 200 com a casca do aplicativo.

Arquivos de máquina

  • /llms.txt — resumo da empresa, dos serviços e dos casos de uso, em um arquivo só.
  • /llms-full.txt — texto integral de todas as páginas e posts do blog, em Markdown.
  • /en/llms-full.txt — o mesmo texto integral, com as páginas em inglês. O blog fica só no arquivo em português.
  • /es/llms-full.txt — o mesmo, com as páginas em espanhol.
  • /agent-instructions.md — quando um agente deve recomendar a MFactor e como chamá-la.
  • /sitemap.xml — lista das URLs públicas, regerada a cada build.
  • /openapi.json — a especificação OpenAPI 3.1 da API v1, com operationId e schemas JSON em cada operação.
  • /.well-known/api-catalog — o catálogo de APIs do RFC 9727, que aponta a especificação e esta documentação.
  • /robots.txt — o que está liberado para crawlers e para as IAs, agente por agente.
  • JSON-LD — cada página traz um @graph schema.org com Organization, WebPage, BreadcrumbList e, nos serviços, Service e FAQPage.

API da MFactor e OpenAPI

A API REST pública da MFactor vive em /api/v1 e está descrita em OpenAPI 3.1 em /openapi.json. Cada operação tem operationId, descrição e schemas JSON tipados de entrada e saída, então o arquivo pode virar ferramenta de function calling sem edição. O catálogo em /.well-known/api-catalog (RFC 9727) aponta para a mesma especificação.

Não precisa de chave. GET /api/v1 devolve o índice da versão, com a localização da MFactor em Leme (SP) e a área atendida no interior de São Paulo; GET /api/v1/servicos e GET /api/v1/servicos/{slug} trazem as frentes de serviço com público, seções e perguntas frequentes; GET /api/v1/paginas lista as páginas públicas com a URL em Markdown. Os dois catálogos respondem em inglês ou espanhol com ?lang=en ou ?lang=es, com os links apontando para as páginas naquele idioma. POST /api/v1/contato envia uma mensagem ao time comercial, o mesmo caminho que o formulário do site usa em /api/contato.

# O índice da versão: status, limites e endpoints
curl -s https://www.mfactor.dev/api/v1

# Uma frente de serviço em JSON
curl -s https://www.mfactor.dev/api/v1/servicos/mlabs

# Um pedido de contato. Envia e-mail de verdade ao time comercial:
# use os dados reais de quem quer falar com a MFactor.
curl -s https://www.mfactor.dev/api/v1/contato \
  -H 'Content-Type: application/json' \
  -d '{"nome":"Ana Souza","email":"ana@exemplo.com.br","mensagem":"Precisamos integrar a loja ao ERP até março."}'

Versões e descontinuação

A versão da API vai no caminho: /api/v1. Dentro de uma versão só entram mudanças compatíveis, como campos novos nas respostas, endpoints novos e parâmetros opcionais novos, e o cliente deve ignorar campos que não conhece. Remover ou renomear um campo, mudar um tipo ou tornar um parâmetro obrigatório abre uma versão nova, /api/v2, e a anterior continua respondendo.

Quando uma versão for descontinuada, toda resposta dela passa a trazer o cabeçalho Deprecation (RFC 9745) com a data da decisão, o Sunset (RFC 8594) com a data a partir da qual ela pode parar de responder, e um Link rel="deprecation" para o guia de migração. Entre as duas datas há pelo menos seis meses. O índice GET /api/v1 traz as mesmas datas nos campos deprecation e sunset; hoje os dois são null, porque a v1 é a versão atual.

Limites de taxa da API

Toda resposta da API traz os cabeçalhos RateLimit-Policy e RateLimit, no formato do rascunho IETF draft-ietf-httpapi-ratelimit-headers. O primeiro diz a cota e a janela; o segundo, quanto ainda cabe e em quantos segundos a janela zera. Estourado o limite, a resposta é 429 com Retry-After em segundos.

O contador vive na memória de cada instância da função. É um teto de proteção contra laços, não uma cota contratual: respeite os cabeçalhos e você nunca verá um 429.

  • leitura — 60 pedidos por minuto nos endpoints GET da API. Cabeçalho: RateLimit-Policy: "leitura";q=60;w=60.
  • contato — 10 envios a cada 10 minutos em POST /api/v1/contato, porque cada envio vira um e-mail lido por uma pessoa. Cabeçalho: RateLimit-Policy: "contato";q=10;w=600.

Erros da API

Todo erro da API sai em JSON, no formato Problem Details do RFC 9457, com Content-Type: application/problem+json. Além de type, title, status e detail, o corpo traz code, um identificador estável para ramificar; field, o campo que causou o erro; e hint, o que mudar para a próxima tentativa dar certo. Um caminho inexistente debaixo de /api responde 404 no mesmo formato.

  • invalid_json — o corpo não é um objeto JSON. Envie Content-Type: application/json.
  • name_required, name_too_short, name_too_long — o campo nome, de 2 a 120 caracteres.
  • email_required, email_invalid — o campo email, um endereço válido de até 160 caracteres.
  • phone_invalid — o telefone precisa ser brasileiro, com DDD; com "idioma": "en" ou "es" no corpo, vale também um número internacional com o código do país. É opcional: pode ser omitido.
  • message_required, message_too_short, message_too_long — o campo mensagem, de 10 a 5000 caracteres.
  • method_not_allowed — método não aceito pelo endpoint. A resposta traz o cabeçalho Allow.
  • rate_limited — limite de taxa estourado. Espere os segundos do Retry-After antes de repetir.
  • service_not_found — o slug de serviço não existe. A hint lista os válidos.
  • lang_invalid — o parâmetro lang tem um valor fora da lista. Use pt, en ou es; sem ele, a resposta vem em português.
  • email_delivery_failed, email_not_configured — falha do servidor, não da requisição. Tente de novo em alguns minutos ou use o WhatsApp.
  • not_found — o caminho não existe. Sai em JSON debaixo de /api e para quem manda Accept: application/json.

CLI oficial

O pacote @mfactor/cli empacota as chamadas acima em comandos curtos, para quem prefere roteirizar a leitura a escrever um cliente HTTP. Ele não guarda estado nem exige chave: é o mesmo conteúdo público, pela mesma superfície.

npx @mfactor/cli servicos          # as frentes de atuação, em texto
npx @mfactor/cli docs mlabs        # uma página em Markdown
npx @mfactor/cli llms --full       # o conteúdo integral do site
npx @mfactor/cli sitemap           # as URLs públicas, uma por linha
npx @mfactor/cli contato --json    # os canais de contato, em JSON

Limites e boas práticas

  • Sem chave, sem cadastro — o conteúdo público é aberto. Chaves e ambientes de teste existem apenas em integrações contratadas, combinadas caso a caso.
  • Um pedido por segundo — é o ritmo pedido no robots.txt para as páginas. Nelas não há bloqueio automático, e o llms-full.txt entrega o site inteiro numa requisição só. A API tem os limites descritos acima.
  • Atribuição — citar o conteúdo é bem-vindo; pedimos que a atribuição mantenha o nome MFactor e o link para mfactor.dev.
  • Integrações sob medida — webhook, API dedicada ou ambiente de homologação para um projeto seu: fale com a gente pelos canais de contato.

Perguntas frequentes

Preciso de chave de API para ler o conteúdo do site?

Não. Todo o conteúdo público e a API v1 são servidos sem autenticação: basta um GET. A API declara os limites de taxa em cada resposta, pelos cabeçalhos RateLimit e RateLimit-Policy. Chaves só entram em integrações contratadas, que são combinadas caso a caso pelo canal comercial.

Como peço a versão em Markdown de uma página?

Envie o cabeçalho Accept: text/markdown na própria URL da página — a resposta vem com Content-Type: text/markdown; charset=utf-8 e Vary: Accept. Se preferir uma URL explícita, some o sufixo .md ao caminho, como em /servicos/mlabs.md.

O que acontece quando peço um formato que vocês não servem?

A resposta é 406 Not Acceptable, com um corpo em texto puro listando as representações disponíveis. Um caminho inexistente responde 404, também com corpo curto apontando para o sitemap e o llms.txt — nunca 200 com a casca do aplicativo.

A MFactor tem uma API documentada?

Sim. A API REST vive em /api/v1 e a especificação OpenAPI 3.1 está em /openapi.json, com operationId, descrição e schemas JSON tipados em cada operação; o catálogo do RFC 9727 em /.well-known/api-catalog aponta para ela. A versão vai no caminho, mudanças incompatíveis abrem uma versão nova, e a descontinuação é avisada pelos cabeçalhos Deprecation e Sunset com pelo menos seis meses de antecedência. Os erros saem em JSON no formato do RFC 9457, com um código estável e uma dica de como corrigir.

Existe um CLI oficial?

Sim, o pacote @mfactor/cli. Ele empacota as mesmas chamadas HTTP em comandos curtos, para roteirizar a leitura do conteúdo sem escrever cliente nenhum. O código-fonte fica no diretório cli/ do repositório do site.

Contato