Documentação da API do MDShare
MDShare publica, compartilha e revisa documentos Markdown. Cada documento recebe um ID único de 8 caracteres e uma URL curta para compartilhamento.
Visão Geral #
O MDShare foi projetado para ser usado por:
- LLMs (Large Language Models) - Para compartilhar outputs longos via links curtos
- Desenvolvedores - Para compartilhar documentação, notas e snippets de código
- Ferramentas de automação - Para gerar relatórios e documentos compartilháveis
Características Principais
- IDs únicos de 8 caracteres hexadecimais (ex:
8f14e45f) - Sistema de revisões com histórico completo
- Suporte a imagens embarcadas
- Visualizador web com tema claro/escuro
- Syntax highlighting para blocos de código
- GitHub Flavored Markdown (GFM)
- Documentos não expiram
Meus documentos #
O painel de documentos mostra os arquivos que pertencem à sua conta e os que compartilharam com você. A mesma listagem está disponível em GET /api/docs. Use uma sessão ou um token de agente com proprietário definido. O token lista os documentos do proprietário e os compartilhados com ele, desde que tenha escopo de leitura, comentário, publicação ou administração. O escopo delete sozinho não abre a listagem.
GET /api/docs?scope=shared&q=proposta&visibility=private&page=1&limit=20
Você pode combinar scope=mine|shared, visibility=private|link, password=yes|no, pending=yes|no, owner=email e q. A busca procura título, ID, e-mail e nome do proprietário. A página tem até 100 documentos.
A resposta traz docs, total, page, limit, pages, counts e owners. Cada documento informa proprietário, criador, papel concedido, visibilidade, senha, datas, revisão e tópicos pendentes. Para um agente, o papel concedido e os escopos do token são verificados juntos em cada ação. openComments conta comentários principais abertos; respostas não criam outra pendência. Em documentos antigos, o criador pode estar sem registro.
Sugestões de texto #
Use POST /api/{id}/comments com kind: "suggestion" para propor uma substituição. Envie body e anchor como em um comentário, além dos campos abaixo:
{
"kind": "suggestion",
"body": "Atualizar prazo após a vistoria.",
"anchor": { "quote": "30 dias", "start": 125, "end": 132 },
"original": "30 dias",
"proposed": "45 dias",
"sourceStart": 120,
"sourceEnd": 127,
"baseRevision": 2,
"hash": "sha256_do_markdown_original_em_hexadecimal"
}
sourceStart e sourceEnd apontam para o Markdown fonte, enquanto a âncora identifica o trecho renderizado. O hash SHA-256 e a revisão impedem uma sugestão sobre texto que já mudou. A resposta de comentários inclui kind, original e proposed para comparar as versões.
Presença e alterações #
GET /api/{id}/activity?revision=2 lista quem está lendo a revisão e devolve version, que muda com os comentários. Para aparecer na lista, envie POST /api/{id}/activity com {"clientId":"cliente_12345678","revision":2} periodicamente. A presença expira após 35 segundos. Use "leave":true para sair. Uma seleção opcional usa quote, start, end, prefix e suffix. Apenas pessoas que podem ler o documento usam essa rota.
Transcrição de voz #
Quem pode comentar pode enviar uma gravação em multipart/form-data para POST /api/{id}/transcribe, no campo audio. A resposta traz o texto transcrito. Depois, envie esse texto para /comments. A API aceita apenas WAV PCM mono, 16 kHz e 16 bits, com até dois minutos. O limite padrão é 8 MiB por gravação e 20 transcrições por dia por identidade. Acessos por senha compartilham a cota do IP. Sem serviço configurado, a resposta é 503.
Atualização segura #
Leia o documento antes de editar. GET /api/{id} informa a revisão e devolve um ETag como "rev-3". Envie baseRevision: 3 no JSON de PUT /api/update ou o mesmo valor no cabeçalho If-Match. Essa precondição é obrigatória: sem ela, a API responde 428. Se outra pessoa publicou uma revisão antes, a API responde 409 e informa a revisão atual. Leia a versão nova e concilie as alterações antes de tentar novamente.
Se a rede falhar durante a publicação, repita a chamada com a mesma Idempotency-Key e o mesmo conteúdo. A API devolve o resultado anterior sem criar outra revisão. Uma chave repetida com conteúdo diferente recebe 409.
curl -X PUT https://mdshare-a2m.pages.dev/api/update \
-H 'Content-Type: application/json' \
-H 'If-Match: "rev-3"' \
-H 'Idempotency-Key: proposta-2026-revisao-4' \
-d '{"id":"8f14e45f","markdown":"# Proposta atualizada"}'
Primeiros passos #
Publique um documento
curl -X POST \
-H "Authorization: Bearer $MDSHARE_TOKEN" \
-H "Content-Type: text/markdown" \
-d '# Meu Primeiro Documento
Este é um teste do **MDShare**!' \
https://mdshare-a2m.pages.dev/api/upload
Resposta:
{
"success": true,
"id": "8f14e45f",
"url": "https://mdshare-a2m.pages.dev/view/8f14e45f",
"revision": 1
}
Autenticação #
publish ou um IP autorizado. Para ler um documento privado, é preciso ter acesso ao próprio documento.
Há dois caminhos para autenticar uma automação:
- Token de agente (recomendado) —
Authorization: Bearer mds_.... Funciona de qualquer IP, tem escopo (read,publish,comment,delete,admin) e pode ser revogado sozinho. É o caminho para agentes com egress variável, que não cabem numa lista de IPs. - Whitelist de IP — mantida para a rede da Fibersals; nada a enviar.
Quem administra cria e revoga tokens:
curl -X POST https://mdshare-a2m.pages.dev/api/tokens \
-H "Content-Type: application/json" \
-d '{"name":"Bot comercial","scopes":["publish"],"owner":"bot@fibersals.com.br"}'
curl -X DELETE https://mdshare-a2m.pages.dev/api/tokens/{id}
IPs Autorizados:
177.10.3.14131.72.81.212
Endpoints públicos (não requerem whitelist):
GET /view/{id}- Visualização de documentosGET /img/{id}/{file}- Acesso a imagensGET /eGET /docs/- Entrada do produto e documentaçãoGET /documents/- Painel de documentos; a lista exige loginPOST /api/auth- Troca a senha do documento por um token/api/{id}/comments- Comentários, autorizados conforme o acesso ao documento
Os comentários usam uma segunda camada de autorização, por documento: quem tem a senha comenta, mesmo de fora da whitelist. Veja Comentários.
URL Base #
https://mdshare-a2m.pages.dev
Todas as requisições à API devem usar HTTPS.
Upload de Markdown #
Cria um novo documento Markdown e retorna um ID único e URL para visualização.
Content-Types Suportados
| Content-Type | Descrição | Suporta Imagens |
|---|---|---|
multipart/form-data |
Upload de arquivo .md com imagens | Sim |
application/json |
JSON com markdown e imagens base64 | Sim (base64) |
text/markdown |
Markdown direto no body | Não |
text/plain |
Texto plano tratado como Markdown | Não |
Parâmetros (multipart/form-data)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
markdown |
File ou String | Sim | Conteúdo Markdown |
images[] |
File[] | Não | Array de imagens |
Parâmetros (application/json)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
markdown |
String | Sim | Conteúdo Markdown |
images |
Array | Não | Array de objetos {name, data} |
password |
String | Não | Senha para acesso pelo link; entregue a senha separadamente |
Exemplo 1: Multipart Form Data
curl -X POST \
-F "markdown=@documento.md" \
-F "images[]=@diagrama.png" \
-F "images[]=@screenshot.jpg" \
https://mdshare-a2m.pages.dev/api/upload
Exemplo 2: JSON
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"markdown": "# Título\n\nConteúdo do documento."
}' \
https://mdshare-a2m.pages.dev/api/upload
Exemplo 3: JSON com Imagens Base64
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"markdown": "# Com Imagem\n\n",
"images": [
{
"name": "logo.png",
"data": "data:image/png;base64,iVBORw0KGgo..."
}
]
}' \
https://mdshare-a2m.pages.dev/api/upload
Exemplo 4: Texto Direto
curl -X POST \
-H "Content-Type: text/markdown" \
-d '# Hello World
Este é um documento simples.' \
https://mdshare-a2m.pages.dev/api/upload
Resposta de Sucesso (200 OK)
{
"success": true,
"id": "8f14e45f",
"url": "https://mdshare-a2m.pages.dev/view/8f14e45f",
"revision": 1
}
Resposta de Erro (400 Bad Request)
{
"success": false,
"error": "No markdown content provided"
}
Atualizar Markdown #
Atualiza um documento existente. Cria uma nova revisão mantendo o histórico. Envie a revisão que serviu de base à edição em baseRevision ou no cabeçalho If-Match.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id |
String | Sim | ID do documento (8 caracteres hex) |
markdown |
String ou File | Sim | Novo conteúdo Markdown |
baseRevision |
Inteiro | Sim, se não enviar If-Match | Revisão lida antes de editar. Aceito em JSON e multipart; falta de precondição retorna 428 e revisão desatualizada retorna 409. |
images[] |
File[] ou Array | Não | Novas imagens a adicionar |
Exemplo: JSON
curl -X PUT \
-H "Content-Type: application/json" \
-d '{
"id": "8f14e45f",
"baseRevision": 1,
"markdown": "# Documento Atualizado\n\nEsta é a revisão 2."
}' \
https://mdshare-a2m.pages.dev/api/update
Exemplo: Multipart Form Data
curl -X PUT \
-F "id=8f14e45f" \
-F "baseRevision=1" \
-F "markdown=@documento_atualizado.md" \
-F "images[]=@nova_imagem.png" \
https://mdshare-a2m.pages.dev/api/update
Resposta de Sucesso
{
"success": true,
"id": "8f14e45f",
"url": "https://mdshare-a2m.pages.dev/view/8f14e45f",
"revision": 2
}
Resposta de Erro (404 Not Found)
{
"success": false,
"error": "Markdown not found with this ID"
}
Obter Markdown #
Retorna o conteúdo Markdown e metadados de um documento.
Parâmetros de URL
| Parâmetro | Descrição |
|---|---|
id |
ID do documento (8 caracteres hex) |
Query Parameters
| Parâmetro | Tipo | Descrição |
|---|---|---|
revision |
Integer | Número da revisão específica |
format |
String | raw para obter texto puro |
Exemplo: Obter documento atual
curl https://mdshare-a2m.pages.dev/api/8f14e45f
Exemplo: Obter revisão específica
curl "https://mdshare-a2m.pages.dev/api/8f14e45f?revision=1"
Exemplo: Obter markdown puro
curl "https://mdshare-a2m.pages.dev/api/8f14e45f?format=raw"
Resposta (JSON)
{
"success": true,
"id": "8f14e45f",
"created": "2025-01-30T12:00:00.000Z",
"updated": "2025-01-30T14:30:00.000Z",
"revision": 2,
"totalRevisions": 2,
"images": ["diagrama.png", "screenshot.jpg"],
"content": "# Título\n\nConteúdo do documento..."
}
Resposta (format=raw)
# Título
Conteúdo do documento...
Visualizar Documento #
Renderiza o documento Markdown em uma página HTML bonita e interativa.
Query Parameters
| Parâmetro | Tipo | Descrição |
|---|---|---|
revision |
Integer | Visualizar revisão específica |
Recursos do Visualizador
- Toggle de tema claro/escuro (salvo no localStorage)
- Dropdown para selecionar revisões
- Syntax highlighting automático para código
- Renderização de imagens embarcadas
- Suporte a GitHub Flavored Markdown
- Design responsivo para mobile
Exemplo de URL
https://mdshare-a2m.pages.dev/view/8f14e45f
https://mdshare-a2m.pages.dev/view/8f14e45f?revision=1
Acessar Imagens #
Retorna uma imagem associada a um documento.
Formatos Suportados
- PNG (
image/png) - JPEG (
image/jpeg) - GIF (
image/gif) - WebP (
image/webp) - SVG (
image/svg+xml) - ICO (
image/x-icon) - BMP (
image/bmp)
Exemplo
https://mdshare-a2m.pages.dev/img/8f14e45f/diagrama.png
Uso no Markdown


As imagens são automaticamente resolvidas para o caminho correto no visualizador.
Comentários #
Comentários ficam presos a um trecho do documento, não à posição numa página. Cada comentário guarda o texto citado, o contexto ao redor e a posição na revisão em que foi criado. Consulte revisões anteriores para ler comentários antigos.
viewer não permite comentar pelo login, mesmo em um documento protegido aberto por link; informar a senha gera uma autorização própria. Documentos abertos por link permitem leitura, mas a escrita exige permissão.
Obter um token com a senha
curl -X POST https://mdshare-a2m.pages.dev/api/auth \
-H "Content-Type: application/json" \
-d '{"id": "8f14e45f", "password": "minha-senha"}'
{
"success": true,
"token": "a1b2c3...",
"expiresIn": 86400
}
Envie o token em todas as chamadas de comentário: Authorization: Bearer <token>
Lista os comentários do documento, em ordem de criação.
Query Parameters
| Parâmetro | Tipo | Descrição |
|---|---|---|
status |
String | open ou resolved |
includeDeleted |
Boolean | Inclui os excluídos. Exige administrador |
Exemplo
curl https://mdshare-a2m.pages.dev/api/8f14e45f/comments \
-H "Authorization: Bearer $TOKEN"
Resposta
{
"success": true,
"docId": "8f14e45f",
"revision": 3,
"total": 1,
"comments": [
{
"id": "3f9a1c2b7d4e5061",
"docId": "8f14e45f",
"parentId": null,
"revision": 2,
"author": "Eng. Marina",
"body": "Isso já foi tratado na vistoria de 2025?",
"anchor": {
"quote": "infiltração na face sul",
"prefix": "O telhado apresenta ",
"suffix": ", com manchas visíveis",
"start": 61,
"end": 84
},
"status": "open",
"created": "2026-08-12T12:00:00.000Z",
"updated": null,
"deleted": null
}
]
}
Cria um comentário, ancorado num trecho ou geral.
Body (JSON)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
body |
String | Sim | Texto do comentário (até 5000 caracteres) |
images |
Array | Não | Imagens do comentário ou da sugestão: objetos com name e data em Base64 |
author |
String | Não | Nome de quem comenta. Padrão: Anônimo |
anchor |
Object | Não | Trecho comentado. Sem ele, o comentário é geral do documento |
parentId |
String | Não | Id do comentário respondido (threads de um nível) |
revision |
Integer | Não | Revisão em que o trecho foi lido. Padrão: a atual |
Objeto anchor
| Campo | Descrição |
|---|---|
quote |
O trecho exato comentado |
prefix / suffix |
Até 32 caracteres antes e depois — desempatam trechos repetidos |
start / end |
Offsets no texto plano renderizado |
Exemplo
curl -X POST https://mdshare-a2m.pages.dev/api/8f14e45f/comments \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"author": "Eng. Marina",
"body": "Isso já foi tratado na vistoria de 2025?",
"anchor": {
"quote": "infiltração na face sul",
"prefix": "O telhado apresenta ",
"suffix": ", com manchas visíveis",
"start": 61,
"end": 84
}
}'
Resposta 201 com o comentário criado em comment.
Mencionar pessoas
Digite @ e escolha alguém pelo nome ou email. A busca mostra usuários Fibersals registrados que podem ler o documento. Funciona em comentários, respostas, edição e justificativas de sugestões. Mencionar uma pessoa não concede acesso.
Pela API, consulte GET /api/{id}/mentions?q=nome e escreva @pessoa@fibersals.com.br em body. A senha anônima não permite buscar pessoas nem gerar emails. Emails sem o @ extra, código, imagens e o Markdown proposto da sugestão não geram avisos.
A resposta inclui mentions e notificationStatus: {state,total,sent}. Aviso pendente significa que ele aguarda envio. Enviado significa que o serviço de email o aceitou, sem garantir chegada à caixa de entrada. Uma falha de email não apaga o comentário salvo. Sem integração configurada, os avisos ficam pendentes.
Cada comentário aceita até dez destinatários e cada identidade pode gerar até 50 avisos por dia. Repetir o envio ou editar o comentário não repete um aviso já aceito para aquela pessoa. Remover a menção, excluir o comentário ou revogar o acesso cancela um envio pendente. O email abre a revisão e a conversa com a autorização normal do documento.
Colar imagens
Cole a imagem no campo de comentário, resposta, justificativa ou texto proposto da sugestão. Confira a prévia e remova o que não quiser enviar. O MDShare guarda as imagens quando você envia a anotação; se o envio falhar, o rascunho continua disponível.
Pela API, envie images: [{"name":"foto.png","data":"BASE64"}] e use  em body ou proposed. A resposta troca essa referência por uma URL local /img/{id}/{arquivo}. O trecho original da sugestão e seus offsets não mudam.
Cada anotação aceita até cinco imagens PNG, JPEG, GIF ou WebP, com até 8 MiB por imagem e 20 MiB no total. SVG não é aceito nesse fluxo. Cada arquivo precisa aparecer no corpo ou no texto proposto. Os limites de texto também valem após a troca das referências.
As imagens seguem as permissões atuais do documento. Elas permanecem disponíveis até excluir o documento, mesmo após excluir a anotação, para preservar sugestões já incorporadas ao Markdown e revisões anteriores. Comentários mostram imagens locais e mantêm o restante como texto.
Resolve, reabre ou edita o texto de um comentário.
curl -X PATCH https://mdshare-a2m.pages.dev/api/8f14e45f/comments/3f9a1c2b7d4e5061 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "resolved"}'
Exclui o comentário e suas respostas. Por padrão é exclusão lógica: some da
listagem e continua visível para auditoria com ?includeDeleted=true.
Query Parameters
| Parâmetro | Descrição |
|---|---|
hard |
true apaga a linha de vez. Exige administrador |
curl -X DELETE https://mdshare-a2m.pages.dev/api/8f14e45f/comments/3f9a1c2b7d4e5061 \
-H "Authorization: Bearer $TOKEN"
Excluir Documento e Revisão #
delete. Um token só com publish não apaga. Não há desfazer: o conteúdo sai
do KV, do R2 e do banco de comentários.
Apaga o documento inteiro: metadados, todas as revisões, as imagens e os
comentários. O confirm precisa repetir o id do documento.
curl -X DELETE "https://mdshare-a2m.pages.dev/api/8f14e45f?confirm=8f14e45f"
Resposta
{
"success": true,
"id": "8f14e45f",
"deleted": true,
"deletedObjects": 4,
"deletedComments": 2
}
Remove uma revisão antiga do histórico. A revisão atual e a última restante não podem ser apagadas — publique uma nova antes.
curl -X DELETE "https://mdshare-a2m.pages.dev/api/8f14e45f?revision=2"
Resposta
{
"success": true,
"id": "8f14e45f",
"deletedRevision": 2,
"revisions": [1, 3]
}
Integração com LLMs #
🤖 Instruções para LLMs
Se você é um LLM (Claude, GPT, etc.), use esta API para compartilhar outputs longos com o usuário através de links curtos e legíveis.
Quando Usar
- Outputs muito longos que não cabem bem no chat
- Documentação gerada que o usuário quer salvar
- Relatórios de análise que precisam ser compartilhados
- Código com muitos arquivos
- Qualquer conteúdo que se beneficia de formatação rica
Fluxo Recomendado
- Gere o conteúdo Markdown
- Faça POST para
/api/upload - Apresente o link
urlao usuário - Se precisar atualizar, use PUT para
/api/updatecom oide abaseRevisionlida antes da edição
Exemplo de Uso por LLM
# Passo 1: Gerar o Markdown
markdown_content = """
# Relatório de Análise
## Sumário Executivo
Esta análise examina os dados de vendas Q4 2024...
## Dados
| Métrica | Valor |
|---------|-------|
| Vendas | $1.2M |
| Crescimento | +15% |
## Conclusões
- Ponto 1
- Ponto 2
"""
# Passo 2: Enviar para MDShare
import requests
response = requests.post(
"https://mdshare-a2m.pages.dev/api/upload",
json={"markdown": markdown_content}
)
result = response.json()
# result = {"success": true, "id": "abc12345", "url": "https://...", "revision": 1}
# Passo 3: Apresentar ao usuário
print(f"Seu relatório está disponível em: {result['url']}")
Resposta Sugerida para o Usuário
Gerei o relatório completo de análise. Você pode visualizá-lo aqui:
📄 https://mdshare-a2m.pages.dev/view/abc12345
O documento inclui:
- Sumário executivo
- Tabelas de dados
- Conclusões e recomendações
O link é permanente e você pode compartilhá-lo com sua equipe.
Proteção por Senha #
Quem gerencia o documento pode alterar a senha no painel ou usar PUT /api/{id}/password com {"password":"nova senha"}. Para remover, use DELETE /api/{id}/password. A troca invalida o acesso feito com a senha anterior e não cria uma revisão do texto.
Envie a senha por um canal separado do link. Quem gerencia o documento pode trocá-la ou removê-la.
Criar Documento com Senha
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"markdown": "# Documento Confidencial\n\nConteúdo secreto aqui...",
"password": "minhasenha123"
}' \
https://mdshare-a2m.pages.dev/api/upload
Resposta
{
"success": true,
"id": "8f14e45f",
"url": "https://mdshare-a2m.pages.dev/view/8f14e45f",
"revision": 1,
"isPublic": true,
"message": "Documento protegido por senha. Compartilhe o link e a senha com quem deve acessá-lo."
}
isPublic é um campo legado: nesta resposta ele indica presença de senha, não acesso público. Consulte visibility e hasPassword no catálogo ou em GET /api/{id}/share para distinguir visibilidade e proteção.
Adicionar ou trocar senha
curl -X PUT https://mdshare-a2m.pages.dev/api/8f14e45f/password \
-H "Content-Type: application/json" \
-d '{"password":"novasenha456"}'
Remover senha
curl -X DELETE https://mdshare-a2m.pages.dev/api/8f14e45f/password
Como Funciona
- Ao acessar um documento protegido, o usuário vê uma tela de senha
- Após digitar a senha correta, um token de sessão é gerado (válido por 24h)
- O visualizador guarda o acesso em cookie até o token expirar ou a senha mudar
- A senha nova é armazenada com PBKDF2 e sal; senhas antigas em SHA-256 continuam aceitas até serem trocadas
Autenticação via API
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"id": "8f14e45f",
"password": "minhasenha123"
}' \
https://mdshare-a2m.pages.dev/api/auth
Resposta
{
"success": true,
"token": "abc123def456...",
"expiresIn": 86400
}
Envie o token da API no cabeçalho Authorization: Bearer <token>. No navegador, digite a senha na tela do documento.
Upload de Imagens #
Existem duas formas de incluir imagens em seus documentos:
Upload e atualização aceitam PNG, JPEG (.jpg ou .jpeg), GIF, WebP e SVG. Cada publicação pode enviar até 20 imagens, com no máximo 8 MiB por arquivo e 25 MiB no total. Os limites consideram os bytes da imagem, após decodificar Base64.
Use nomes sem pastas, barras, .. ou caracteres de controle. Cada imagem precisa ter um nome diferente, inclusive após a conversão de espaços e caracteres especiais para _. No multipart e nas URLs Base64, o MIME informado deve corresponder à extensão; MIME ausente ou application/octet-stream deixa a extensão definir o formato.
Dados Base64 inválidos, nomes repetidos, formatos não aceitos e mais de 20 imagens retornam 400. Arquivo acima de 8 MiB ou conjunto acima de 25 MiB retorna 413. Essas recusas não publicam conteúdo nem imagens.
1. Upload de Arquivos (Multipart Form Data)
curl -X POST \
-F "markdown=@documento.md" \
-F "images[]=@imagem1.png" \
-F "images[]=@imagem2.jpg" \
https://mdshare-a2m.pages.dev/api/upload
2. Base64 (JSON)
{
"markdown": "# Documento\n\n",
"images": [
{
"name": "logo.png",
"data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}
]
}
Referenciando Imagens no Markdown
Use caminhos relativos simples no seu Markdown:



O visualizador automaticamente resolve para:
https://mdshare-a2m.pages.dev/img/{id}/nome-do-arquivo.png
Sistema de Revisões #
Cada atualização de documento cria uma nova revisão. O histórico completo é mantido.
Como Funciona
- Upload inicial = Revisão 1
- Cada PUT/update = Nova revisão (+1)
- Todas as revisões são preservadas indefinidamente
- A URL
/view/{id}sempre mostra a versão mais recente
Acessar Revisões Específicas
# Via API
curl "https://mdshare-a2m.pages.dev/api/8f14e45f?revision=1"
# Via Visualizador
https://mdshare-a2m.pages.dev/view/8f14e45f?revision=1
Comparar revisões no desktop
No visualizador, clique em Comparar revisões. A versão antiga aparece à esquerda e a nova à direita, com Markdown renderizado e rolagem sincronizada. Os blocos removidos ficam em vermelho; os adicionados ficam em verde. Um bloco alterado mostra o original em vermelho e o resultado em verde.
A comparação começa com a revisão exibida e a anterior disponível. Você pode escolher outro par nos seletores. Quando não há revisão anterior, o botão fica desativado. A comparação usa as permissões atuais do documento e mantém o texto e os comentários intactos.
Metadados de Revisão
{
"revision": 3,
"totalRevisions": 3,
"created": "2025-01-30T12:00:00.000Z",
"updated": "2025-01-30T15:45:00.000Z"
}
Comentários Ancorados #
No visualizador, selecione um trecho do documento e clique em Comentar. O comentário aparece no painel lateral e o trecho fica destacado para todo mundo que abrir o link com a senha.
Como a âncora sobrevive a uma nova revisão
Ao abrir o documento, cada âncora é procurada nesta ordem:
- O offset guardado ainda aponta para o mesmo texto — usa direto.
- O texto existe em outro ponto — o contexto (prefixo e sufixo) escolhe a ocorrência certa.
- Só o espaçamento mudou — compara ignorando quebras de linha e espaços repetidos.
- O trecho sumiu — o comentário vira órfão: continua na lista, sem destaque, avisando que o trecho não existe nesta revisão.
Ou seja: editar o documento com PUT /api/update não perde comentários,
mesmo inserindo parágrafos antes do trecho comentado.
Estados
- Aberto — pendente. É o que o contador no cabeçalho mostra.
- Resolvido — tratado; o destaque vira um sublinhado discreto.
- Excluído — sai da listagem, permanece na auditoria do admin.
Ciclo de Revisão com LLM #
É para isto que os comentários existem: um LLM publica, um humano revisa e comenta o trecho exato, o LLM lê os comentários pela API e age em cima deles. O link é permanente, então o ciclo inteiro acontece na mesma URL.
Os seis passos
- Publicar —
POST /api/upload. Guardar oid. - Entregar — mandar
/view/{id}para quem revisa (com senha, se for externo). - Revisar — a pessoa seleciona o trecho e comenta no navegador.
- Ler —
GET /api/{id}?format=commentedtraz o markdown com cada comentário delimitado no trecho exato (ouGET /api/{id}/commentspara JSON). - Agir — corrigir o markdown e publicar com
PUT /api/update. - Fechar —
PATCH /api/{id}/comments/{commentId}com{"status":"resolved"}.
Repetir do passo 4 até não sobrar comentário aberto.
Exemplo do passo 4 ao 6
TOKEN=$(curl -s -X POST https://mdshare-a2m.pages.dev/api/auth \
-H "Content-Type: application/json" \
-d '{"id":"8f14e45f","password":"minha-senha"}' | jq -r .token)
# o que está pendente, e sobre qual trecho
curl -s "https://mdshare-a2m.pages.dev/api/8f14e45f/comments?status=open" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.comments[] | "[\(.id)] \(.author): \(.body)\n trecho: \(.anchor.quote // "(documento)")"'
# ... aplica as correções e publica a revisão nova ...
curl -X PATCH https://mdshare-a2m.pages.dev/api/8f14e45f/comments/3f9a1c2b7d4e5061 \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"status":"resolved"}'
Markdown comentado
Em vez de casar âncoras por conta própria, o agente pede o documento já anotado:
curl "https://mdshare-a2m.pages.dev/api/8f14e45f?format=commented&status=open"
O telhado apresenta **{{{c1}}}infiltração na face sul{{{/c1}}}**, com manchas.
{{{comments
c1 id=3f9a1c2b7d4e5061 status=open author="Eng. Marina" revision=2
Isso já foi tratado na vistoria de 2025?
}}}
Os delimitadores cercam exatamente o trecho comentado, e a legenda traz o
id que vai no PATCH para resolver. Ao publicar a
revisão corrigida, remova os delimitadores — eles são anotação, não conteúdo.
Comentário sem trecho aparece como scope=documento; trecho que
sumiu, como scope=nao-localizado; trecho repetido sem contexto
que o distinga, como scope=aproximado.
Duas regras que evitam retrabalho
- Resolva o que você aplicou. Quando a correção altera justamente o trecho comentado, a âncora não encontra mais aquele texto e o comentário passa a aparecer como órfão. É o comportamento correto — marque como resolvido no mesmo momento em que aplicar.
-
Olhe o campo
revision. O comentário pode ter sido escrito sobre uma versão anterior do documento.
Quem assina o comentário
Comentário feito por quem entrou com a conta Google da Fibersals traz
authorEmail preenchido — identidade verificada, sem digitar
nome. Comentário feito com a senha do documento traz só o nome digitado, e
authorEmail nulo. Um agente que precise saber de quem veio a
instrução deve olhar esse campo.
Tratamento de Erros #
Todas as respostas de erro seguem o mesmo formato:
{
"success": false,
"error": "Descrição do erro"
}
Códigos de Status HTTP
| Código | Descrição | Causa Comum |
|---|---|---|
200 |
OK | Requisição bem sucedida |
400 |
Bad Request | Dados inválidos ou faltando |
401 |
Unauthorized | Token inválido, revogado ou expirado |
403 |
Forbidden | A credencial não dá acesso à operação ou ao documento |
404 |
Not Found | Documento ou revisão não existe |
409 |
Conflict | Revisão alterada por outra publicação ou documento em alteração |
500 |
Internal Error | Erro no servidor |
Exemplos de Erros
# Publicação sem credencial autorizada
{
"success": false,
"error": "Authentication required to publish"
}
# Markdown vazio
{
"success": false,
"error": "No markdown content provided"
}
# ID inválido
{
"success": false,
"error": "Invalid ID format"
}
# Documento não encontrado
{
"success": false,
"error": "Markdown not found with this ID"
}
# Revisão não encontrada
{
"success": false,
"error": "Revision 5 not found. Available: 1-3"
}
Exemplos cURL #
Upload Básico
curl -X POST \
-H "Content-Type: text/markdown" \
-d '# Título
Conteúdo do documento.' \
https://mdshare-a2m.pages.dev/api/upload
Upload de Arquivo
curl -X POST \
-F "markdown=@meu-documento.md" \
https://mdshare-a2m.pages.dev/api/upload
Upload com Imagens
curl -X POST \
-F "markdown=@documento.md" \
-F "images[]=@img1.png" \
-F "images[]=@img2.jpg" \
https://mdshare-a2m.pages.dev/api/upload
Atualizar Documento
curl -X PUT \
-H "Content-Type: application/json" \
-d '{"id": "8f14e45f", "baseRevision": 1, "markdown": "# Atualizado\n\nNovo conteúdo."}' \
https://mdshare-a2m.pages.dev/api/update
Obter Documento
# JSON com metadados
curl https://mdshare-a2m.pages.dev/api/8f14e45f
# Markdown puro
curl "https://mdshare-a2m.pages.dev/api/8f14e45f?format=raw"
# Revisão específica
curl "https://mdshare-a2m.pages.dev/api/8f14e45f?revision=1"
One-liner: Upload de stdin
echo "# Quick Note" | curl -X POST -d @- https://mdshare-a2m.pages.dev/api/upload
Exemplos Python #
Instalação
pip install requests
Upload Simples
import requests
def upload_markdown(content: str) -> dict:
"""Upload markdown content and return response with URL."""
response = requests.post(
"https://mdshare-a2m.pages.dev/api/upload",
json={"markdown": content}
)
return response.json()
# Uso
result = upload_markdown("""
# Meu Documento
Este é um exemplo de documento Markdown.
## Seção 1
- Item 1
- Item 2
```python
print("Hello, World!")
```
""")
print(f"URL: {result['url']}")
print(f"ID: {result['id']}")
Upload com Imagens
import requests
import mimetypes
from pathlib import Path
def upload_with_images(markdown: str, images: list[str]) -> dict:
"""Upload markdown with image files."""
files = [('markdown', ('doc.md', markdown, 'text/markdown'))]
for img_path in images:
path = Path(img_path)
with open(path, 'rb') as f:
mime = mimetypes.guess_type(path.name)[0] or 'application/octet-stream'
files.append(('images[]', (path.name, f.read(), mime)))
response = requests.post(
"https://mdshare-a2m.pages.dev/api/upload",
files=files
)
return response.json()
# Uso
result = upload_with_images(
"# Com Imagens\n\n",
["diagrama.png"]
)
Atualizar Documento
import requests
def update_markdown(doc_id: str, content: str, base_revision: int) -> dict:
"""Update existing markdown document."""
response = requests.put(
"https://mdshare-a2m.pages.dev/api/update",
json={"id": doc_id, "markdown": content, "baseRevision": base_revision}
)
return response.json()
# Uso
# Use a revisão lida antes de editar o conteúdo.
result = update_markdown("8f14e45f", "# Atualizado\n\nNovo conteúdo.", base_revision=1)
Obter Documento
import requests
def get_markdown(doc_id: str, revision: int = None) -> dict:
"""Get markdown document by ID."""
url = f"https://mdshare-a2m.pages.dev/api/{doc_id}"
if revision:
url += f"?revision={revision}"
response = requests.get(url)
return response.json()
# Uso
doc = get_markdown("8f14e45f")
print(doc['content'])
Classe Helper Completa
import requests
from dataclasses import dataclass
from typing import Optional
@dataclass
class MDShareResult:
success: bool
id: str = ""
url: str = ""
revision: int = 0
error: str = ""
class MDShare:
BASE_URL = "https://mdshare-a2m.pages.dev"
@classmethod
def upload(cls, markdown: str) -> MDShareResult:
"""Upload new markdown document."""
resp = requests.post(
f"{cls.BASE_URL}/api/upload",
json={"markdown": markdown}
)
data = resp.json()
return MDShareResult(**data) if data.get('success') else MDShareResult(success=False, error=data.get('error', ''))
@classmethod
def update(cls, doc_id: str, markdown: str, base_revision: int) -> MDShareResult:
"""Update existing document."""
resp = requests.put(
f"{cls.BASE_URL}/api/update",
json={"id": doc_id, "markdown": markdown, "baseRevision": base_revision}
)
data = resp.json()
return MDShareResult(**data) if data.get('success') else MDShareResult(success=False, error=data.get('error', ''))
@classmethod
def get(cls, doc_id: str, revision: Optional[int] = None) -> dict:
"""Get document content and metadata."""
url = f"{cls.BASE_URL}/api/{doc_id}"
if revision:
url += f"?revision={revision}"
return requests.get(url).json()
@classmethod
def view_url(cls, doc_id: str) -> str:
"""Get viewer URL for document."""
return f"{cls.BASE_URL}/view/{doc_id}"
# Uso
result = MDShare.upload("# Hello\n\nWorld!")
print(f"Visualize em: {result.url}")
# Atualizar
MDShare.update(result.id, "# Updated\n\nNew content!")
# Obter conteúdo
doc = MDShare.get(result.id)
print(doc['content'])
Exemplos JavaScript #
Upload com Fetch
async function uploadMarkdown(content) {
const response = await fetch('https://mdshare-a2m.pages.dev/api/upload', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ markdown: content })
});
return response.json();
}
// Uso
const result = await uploadMarkdown(`# Meu Documento
Conteúdo aqui...
`);
console.log(`URL: ${result.url}`);
console.log(`ID: ${result.id}`);
Upload com Imagens (FormData)
async function uploadWithImages(markdownFile, imageFiles) {
const formData = new FormData();
formData.append('markdown', markdownFile);
for (const img of imageFiles) {
formData.append('images[]', img);
}
const response = await fetch('https://mdshare-a2m.pages.dev/api/upload', {
method: 'POST',
body: formData
});
return response.json();
}
// Uso com file inputs
const mdFile = document.getElementById('markdown-input').files[0];
const imgFiles = document.getElementById('images-input').files;
const result = await uploadWithImages(mdFile, imgFiles);
Atualizar Documento
async function updateMarkdown(id, content, baseRevision) {
const response = await fetch('https://mdshare-a2m.pages.dev/api/update', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, markdown: content, baseRevision })
});
return response.json();
}
// Uso
// Use a revisão lida antes de editar o conteúdo.
await updateMarkdown('8f14e45f', '# Atualizado\n\nNovo conteúdo.', 1);
Obter Documento
async function getMarkdown(id, revision = null) {
let url = `https://mdshare-a2m.pages.dev/api/${id}`;
if (revision) url += `?revision=${revision}`;
const response = await fetch(url);
return response.json();
}
// Uso
const doc = await getMarkdown('8f14e45f');
console.log(doc.content);
Classe Helper (ES6)
class MDShare {
static BASE_URL = 'https://mdshare-a2m.pages.dev';
static async upload(markdown) {
const res = await fetch(`${this.BASE_URL}/api/upload`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ markdown })
});
return res.json();
}
static async update(id, markdown, baseRevision) {
const res = await fetch(`${this.BASE_URL}/api/update`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, markdown, baseRevision })
});
return res.json();
}
static async get(id, revision = null) {
let url = `${this.BASE_URL}/api/${id}`;
if (revision) url += `?revision=${revision}`;
const res = await fetch(url);
return res.json();
}
static viewUrl(id) {
return `${this.BASE_URL}/view/${id}`;
}
}
// Uso
const { id, url } = await MDShare.upload('# Hello World');
console.log(`View: ${url}`);
Exemplos MCP Tools #
Usando WebFetch (se disponível)
# O LLM pode usar WebFetch para enviar markdown
# Exemplo conceitual de como um LLM usaria:
1. Preparar o conteúdo Markdown
2. Usar ferramenta de HTTP POST para:
URL: https://mdshare-a2m.pages.dev/api/upload
Body: {"markdown": "# Seu conteúdo aqui"}
Content-Type: application/json
3. Extrair 'url' da resposta JSON
4. Apresentar o link ao usuário
Fluxo de Trabalho LLM
# Quando o usuário pede um relatório/documento longo:
1. Gerar o conteúdo completo em Markdown
2. Fazer upload via POST /api/upload
3. Obter o link de resposta
4. Responder ao usuário:
"Aqui está seu relatório completo:
📄 https://mdshare-a2m.pages.dev/view/abc12345
O documento inclui todas as seções solicitadas
e está formatado para fácil leitura."
# Se precisar atualizar:
1. Usar PUT /api/update com o ID existente e a baseRevision lida antes de editar
2. Informar ao usuário que o documento foi atualizado
(o mesmo link continua funcionando)