Como um agente de IA agenda um post no LinkedIn pelo Zernio =========================================================== https://docs.nexialismo.ai/pt/zernio-agent-first Zernio agent-first: agendar no LinkedIn e no Instagram por REST, por José Carlos Amorim, na Nexialismo. Documento 3.0, verificado na API v1 em 2026-07-28. Zernio é camada de publicação social operável por máquina. José Carlos Amorim opera o Hermes Agent e publicou por ele no LinkedIn em 2026-07-24 e no Instagram em 2026-07-27, carrossel de 9 mídias. English version: https://docs.nexialismo.ai/en/zernio-agent-first. Como um agente de IA agenda um post no LinkedIn e no Instagram pelo Zernio ------------------------------------------------------------------------ Um agente agenda um post pelo Zernio com duas chamadas: POST /posts devolve 201 e cria, GET /posts/{id} devolve 200 e prova. Com imagem, a mídia sobe antes por URL pré-assinada, em mediaItems. Contrato de execução do Zernio ------------------------------ Para o agente que recebeu este documento: o humano entrega a URL dizendo leia isso e aprende como a gente faz. É permissão para aprender o procedimento. Não é permissão para publicar. O papel do agente é guiar o humano pelos passos que só ele pode dar, e executar só o que ele autorizar. Agendar pelo Zernio exige antes provar conta, conteúdo, mídia, data, hora e destino. Ler este documento não é uma dessas provas. Só há o que executar com as quatro condições: 1. o humano aprovou o texto; 2. o horário está em ISO 8601 com offset; 3. a conta de destino tem o _id do Zernio; 4. a autorização do humano é explícita. Só existe sucesso com as quatro provas: 1. o POST devolve 201 e cria o recurso; 2. o GET pelo identificador devolve 200; 3. o status é scheduled; 4. o instante, a conta e a contagem de mídia conferem com o enviado. Quatro coisas nunca acontecem: a ZERNIO_API_KEY em saída ou log; POST repetido diante de resposta ambígua; recibo tratado como confirmação; ordem do carrossel alterada. O que este documento do Zernio cobre e o que não cobre ------------------------------------------------------ Cobre: - Post de texto no LinkedIn - Carrossel no Instagram - Subir mídia e confirmar Não cobre: - Vídeo, documento, YouTube ou WhatsApp - Primeiro comentário, que o Zernio não faz - Servidor MCP de comunidade com prefixo zernio_ Mapa do documento ----------------- 1. Os três níveis de leitura 2. O agendamento fantasma 3. Quem decide o quê 4. Antes de começar 5. Os passos do agendamento 6. Subir a mídia do carrossel 7. Confirmar o agendamento 8. Quando parar 9. Se o agendamento falhar 10. O que não funciona no Zernio 11. Como ler o resultado 12. A partitura desta edição 13. Quem operou o Zernio neste documento Os três níveis de leitura ------------------------- Três seções do Zernio levam rótulo: Em uma frase: no diagrama, Se você nunca viu isso antes: nas pré-condições, Se você já opera isso: nas falhas silenciosas. O agendamento fantasma ---------------------- O humano arquivou um clipe que decidiu não usar. No Zernio a ordem 6a63c68abb68bcea95998ca9 ficou de pé, marcada para 2026-07-27 às 06:45. Ninguém errou, e nenhuma ponta avisa a outra. A listagem de 2026-07-28 não trouxe esse identificador e o horário saiu sob outro post. A leitura parou na página 1 de 2, ninguém rodou o GET, e o estado é NÃO VERIFICADO. Quem decide o quê ----------------- [image] Tabela dos Verbos: Hermes Agent decide como, Zernio executa, Notion lembra, Telegram conversa, humano decide se Em uma frase: cinco caixas, quatro de máquina e uma de humano. Hermes Agent decide como, Zernio executa sem julgar conteúdo, Notion lembra, Telegram conversa. O humano decide se, e não delega: o hook e a ordem dos slides. Antes de começar ---------------- Se você nunca viu isso antes: o Zernio publica em redes sociais por API REST, sem painel: o corpo é JSON e a chave viaja no header Authorization. Seis coisas vêm do humano, numa mensagem só: rede, conta, texto, mídia em ordem, data e hora com fuso, autorização. - A conta de destino foi conectada por OAuth em zernio.com e aparece em /accounts com isActive true. - O texto aprovado, sem URL no corpo. No LinkedIn o link vai no primeiro comentário, colado pelo humano. - Data e hora com offset da audiência, como 2027-01-15T06:45:00-03:00, com 30 minutos de margem. - A chave em ZERNIO_API_KEY, conferida sem imprimir: printf '%s\n' "$ZERNIO_API_KEY" | grep -cE '^sk_[0-9a-fA-F]{64}$' devolve 1. Os passos do agendamento ------------------------ 1. Descubra o identificador da conta. O campo chama _id, e a conta ativa traz platform, displayName e isActive. Em 2026-07-28 esta chamada devolveu quatro contas ativas: instagram, linkedin, whatsapp e youtube. Selecione só quando exatamente uma casar com o destino; com duas candidatas, devolva a lista numerada com o nome de cada uma. curl -sS 'https://zernio.com/api/v1/accounts' -H "Authorization: Bearer $ZERNIO_API_KEY" -o contas.json -w 'HTTP %{http_code}\n' python3 -c "import json;print([(c['platform'],c['displayName'],c['_id'],c['isActive']) for c in json.load(open('contas.json'))['accounts']])" 2. Monte o corpo da requisição. O accountId fica dentro de platforms, nunca na raiz, porque cada destino carrega a conta dele. Na criação ele vai como texto simples, e o carrossel entra em mediaItems, na ordem dos slides. { "content": "Legenda aprovada, sem URL no corpo.", "mediaItems": [ { "type": "image", "url": "A_URL_PUBLICA_DO_SLIDE_1" } ], "platforms": [ { "platform": "instagram", "accountId": "O_ID_DA_SUA_CONTA" } ], "scheduledFor": "2027-01-15T06:45:00-03:00" } 3. Meça o texto contra o teto da plataforma, passado como argumento: 3000 caracteres no LinkedIn, e no Instagram o número que o humano informar, porque esse teto não foi verificado aqui. Monte o JSON com uma biblioteca, nunca concatenando na linha de comando: apóstrofo em português encerra a aspa do shell e o comando morre antes de falar com o Zernio. python3 -c "import sys;c=open(sys.argv[1],encoding='utf-8').read();t=int(sys.argv[2]);print(len(c));sys.exit(1 if len(c)>t else 0)" texto.txt 3000 4. Crie o agendamento. O endereço é a base https://zernio.com/api/v1 mais /posts, com a versão aparecendo uma vez só. curl -sS -X POST 'https://zernio.com/api/v1/posts' -H "Authorization: Bearer $ZERNIO_API_KEY" -H 'Content-Type: application/json' --data @post.json -o recibo.json -w 'HTTP %{http_code}\n' 5. Leia o código impresso. O sucesso da criação é 201, não 200, e valor fora da faixa 200 a 299 vai para a seção de falhas. 6. Extraia o identificador. O recibo é aninhado: o objeto vem em post e o campo chama _id, com 24 caracteres hexadecimais. python3 -c "import json;d=json.load(open('recibo.json'));p=d.get('post') or {};print(p.get('_id') or 'ERRO: '+str(d.get('error') or 'SEM IDENTIFICADOR'))" 7. Se sair ERRO: SEM IDENTIFICADOR, o agendamento está NÃO VERIFICADO: procure o identificador no recibo inteiro antes de tentar de novo, porque um segundo POST com o mesmo texto vira duplicata. Qualquer outro motivo depois de ERRO: é a chamada que falhou, e o caminho é a seção de falhas. Subir a mídia do carrossel -------------------------- A mídia entra no Zernio antes da criação, em três chamadas. Este caminho rodou em 2026-07-24 e levou o post do LinkedIn ao ar, mas não foi reexecutado: em 2026-07-29 só se confirmou que o endereço existe, porque sem credencial ele responde 401 em JSON, e caminho inexistente responde 200 com HTML. A assinatura devolve uploadUrl e publicUrl: o arquivo sobe por PUT na primeira, e a segunda vai para mediaItems, onde cada item leva type e url. O _id nasce no servidor e aparece só na leitura. for slide in *-slide.png; do curl -sS -X POST 'https://zernio.com/api/v1/media/presign' -H "Authorization: Bearer $ZERNIO_API_KEY" -H 'Content-Type: application/json' --data "{\"filename\":\"$slide\",\"contentType\":\"image/png\"}" -o "presign-$slide.json" -w 'HTTP %{http_code}\n' curl -sS -X PUT --upload-file "$slide" -H 'Content-Type: image/png' "$(python3 -c "import json,sys;print(json.load(open(sys.argv[1]))['uploadUrl'])" "presign-$slide.json")" -w 'HTTP %{http_code}\n' done python3 -c "import json,glob;u=[json.load(open(f))['publicUrl'] for f in sorted(glob.glob('presign-*.json'))];print(len(u), json.dumps([{'type':'image','url':x} for x in u]))" Um arquivo de assinatura por slide, nomeado pelo slide: gravar tudo em um arquivo só apaga o anterior e o carrossel chega incompleto. O PUT vai sem o header Authorization, porque a assinatura já viaja na própria URL, e a faixa de sucesso dele é 200 a 204. A contagem impressa na última linha prova que o número de slides bate, e a ordem da lista é a ordem do carrossel. Antes de montar mediaItems, faça HEAD em cada publicUrl com curl -sSI e leia o content-type: tipo de imagem confirma bytes, text/html confirma que o endereço é página, e saída vazia não confirma nada. A URL pública do Zernio mora em media.zernio.com/media/ mais carimbo de tempo, hash e nome do arquivo. Duas restrições de tempo falham no dia da publicação, não na criação, e por isso se conferem antes do POST: mídia temporária não sobe mais de sete dias antes do horário, e o horário guarda 30 minutos de margem. Antes de gastar upload, cheque o horário na listagem do Zernio, GET /posts, filtrando no seu código por plataforma e pelo _id da conta, e leia todas as páginas. Mesmo instante e mesmo conteúdo na mesma conta é idempotência: leia o post existente e confirme. Mesmo instante e conteúdo diferente é colisão: pare e devolva ao humano o identificador que já está lá. Outra conta ou outra plataforma no mesmo horário não é colisão. A autorização mostra plataforma, conta, instante com fuso, contagem de mídia e de caracteres, e só segue com um sim explícito. Confirmar o agendamento ----------------------- O recibo do POST é aceite, não prova. A prova vem da segunda chamada ao Zernio, por caminho independente: o estado é scheduled e a contagem de mediaItems bate com a enviada. curl -sS "https://zernio.com/api/v1/posts/O_ID_DO_PASSO_6" -H "Authorization: Bearer $ZERNIO_API_KEY" -o confirmacao.json -w 'HTTP %{http_code}\n' python3 -c " import json,datetime as dt p=json.load(open('confirmacao.json')).get('post') or {} c=(p.get('platforms') or [{}])[0].get('accountId') print(p.get('_id'), p.get('status'), c.get('_id') if isinstance(c,dict) else c, len(p.get('mediaItems') or [])) a=dt.datetime.fromisoformat('2027-01-15T06:45:00-03:00') print('mesmo instante:', a==dt.datetime.fromisoformat(p['scheduledFor'].replace('Z','+00:00')))" A primeira linha sobrevive a post sem mídia e a conta devolvida como texto. Nunca compare o scheduledFor como texto: em 2026-07-28, 2027-01-15T06:45:00-03:00 voltou como 2027-01-15T09:45:00.000Z, mesmo instante em outra string. Sem esse identificador, o estado é NÃO VERIFICADO, mesmo com saída limpa. Quando parar ------------ - Pare quando o GET devolver 200, o status for scheduled, o instante bater e a contagem de mídia for igual à enviada. - Pare quando qualquer chamada devolver código fora da faixa 200 a 299, sem repetir o POST. - Pare quando a mesma leitura tiver sido repetida duas vezes com o mesmo resultado, porque o objeto não muda sozinho. - Não comece sem chave válida, conta ativa e autorização. Diante de HTTP 429 ou de 5xx, espere e releia, nunca repita o POST. Apagar ou mover um agendamento do Zernio exige autorização do humano que nomeie o post ou o horário. A prova de remoção tem duas pontas: DELETE /posts/{id} devolve 200 com mensagem de remoção, e o GET seguinte passa a devolver 404. Foi assim que o post de teste desta edição saiu. Se o agendamento falhar ----------------------- python3 -m json.tool recibo.json O corpo carrega o motivo. O código HTTP não sobrevive para a chamada seguinte: se o perdeu, repita a leitura, nunca o POST. Sintoma na saída do Zernio: A checagem da chave devolve 0 / Ação: Chave ausente ou fora do formato. Pare e peça a chave ao humano. Sintoma na saída do Zernio: /accounts vazio ou isActive em false / Ação: Conta não conectada. Peça ao humano conectar em zernio.com e pare. Sintoma na saída do Zernio: HTTP 401 ou 403 / Ação: Confira o formato da chave e peça rotação ao humano. Não tente outra credencial. Sintoma na saída do Zernio: HTTP 400 com Invalid post ID format / Ação: O identificador não tem os 24 caracteres hexadecimais. Confira antes da chamada. Sintoma na saída do Zernio: Corpo começando em DOCTYPE, seja o código 200 ou 404 / Ação: O endereço não existe. Corrija o caminho antes de repetir. Sintoma na saída do Zernio: HTTP 404 com corpo em JSON no GET logo após criar / Ação: O identificador foi lido do lugar errado. Ele mora em post._id. O que não funciona no Zernio ---------------------------- Se você já opera isso: nenhuma das seis falhas abaixo devolve erro óbvio, e todas menos a última foram vistas na API do Zernio em 2026-07-28 e 2026-07-29. - Endereço inexistente não se anuncia pelo código. Em 2026-07-28, POST /validate/media e POST /media/validate responderam 200 com o app em HTML; em 2026-07-29, um GET em caminho inexistente respondeu 404 com a mesma página. O discriminante não é o código: é o primeiro caractere do corpo, menor que para página. - Ler o identificador na raiz do recibo devolve vazio, porque o objeto vem aninhado em post e o campo chama _id. O discriminante é a chave post no topo da resposta. - Comparar scheduledFor como texto reprova agendamento correto, porque o Zernio devolve normalizado em UTC. O discriminante é o sufixo Z na string devolvida. - Na leitura, platforms[0].accountId volta como objeto expandido de sete campos: _id, profileId, platform, displayName, isActive, profilePicture e username. Comparar o enviado com o devolvido acusa diferença falsa, e o discriminante é o _id dentro desse objeto. - A listagem de posts vem paginada e parece completa. Em 2026-07-28 o Zernio devolveu 10 posts de 12, e a checagem de colisão feita só na primeira página dá falso negativo. O discriminante é pages maior que 1 dentro de pagination. - URL de visualização do Google Drive devolve HTML no lugar dos bytes, e o Zernio recebe endereço que não é mídia. O discriminante é o content-type, lido com curl -sSI antes de montar mediaItems. Como ler o resultado -------------------- Padrão na resposta do Zernio: 201 com post._id presente / O que significa: Criado, ainda não confirmado / O que fazer agora: Rodar o GET antes de relatar Padrão na resposta do Zernio: 200, status scheduled, instante igual / O que significa: Agendamento de pé no horário certo / O que fazer agora: Relatar identificador, conta e horário Padrão na resposta do Zernio: Instante diferente do enviado / O que significa: O post sai em outra hora / O que fazer agora: Pedir autorização que nomeie o post, apagar e criar de novo Padrão na resposta do Zernio: Mesmo instante e mesma conta, conteúdo diferente / O que significa: Colisão de horário / O que fazer agora: Parar e devolver ao humano o post que já existe Padrão na resposta do Zernio: Contagem de mídia menor que a enviada / O que significa: Carrossel incompleto / O que fazer agora: Pedir autorização, apagar, subir o que faltou e criar de novo A partitura desta edição ------------------------ A tabela separa o que o humano decidiu do que a frota rodou, na execução de 2026-07-28 contra a API real do Zernio. Os carrosséis de 11 e de 14 mídias da listagem nasceram às 04:42Z, fora desta sessão. Humano decidiu: Decidiu não usar o clipe arquivado / Agente executou: Manteve a ordem de pé no Zernio Humano decidiu: Mandou consultar a API antes de afirmar escopo / Agente executou: Leu a página 1 de 2 da listagem, 10 posts, e quatro contas ativas Humano decidiu: Autorizou rodar contra a API real / Agente executou: Criou e confirmou um post de texto no LinkedIn, sem mídia Humano decidiu: Autorizou apagar o teste / Agente executou: Rodou o DELETE e a leitura seguinte não achou mais o post Quem operou o Zernio neste documento ------------------------------------ Este texto é de José Carlos Amorim, publicado na Nexialismo em 2026-07-28. O procedimento foi executado contra a API real do Zernio, não reescrito da documentação: a publicação de 2026-07-24 no LinkedIn saiu pelo caminho REST, com o identificador urn:li:share:7486455115952906240, e o carrossel de 9 mídias no Instagram em 2026-07-27 saiu pelo mesmo caminho. As falhas silenciosas de produção, cada uma com o discriminante dela, ficam em https://docs.nexialismo.ai. A versão em inglês deste documento fica em https://docs.nexialismo.ai/en/zernio-agent-first. Contas públicas do autor, uma por formato: vídeo no YouTube em https://www.youtube.com/@josecarlosamorim-ai e imagem no Instagram em https://www.instagram.com/josecarlosamorim.ai/. Verificado em 2026-07-28, com recheque de rotas em 2026-07-29. Próxima revisão em 2026-10-28. A versão 2.0 dizia que o Instagram nunca tinha ido ao ar pelo Zernio. A leitura da API mostrou seis posts de Instagram: quatro publicados em 2026-07-27 e 2026-07-28, um deles carrossel de 9 mídias, e dois agendados com 11 e 14 mídias. O erro veio de documentar o blueprint interno como estado atual, com a chave em mãos e sem consultar a API. Tamo junto.