[{"data":1,"prerenderedAt":1504},["ShallowReactive",2],{"navigation":3,"blog-page":22,"blogs":33},[4],{"title":5,"path":6,"stem":7,"children":8,"page":21},"Blog","/blog","blog",[9,13,17],{"title":10,"path":11,"stem":12},"Desafios dos Programadores Iniciantes em Moçambique ao Criar Backends para APIs de Pagamentos M-Pesa","/blog/mpesa-api-starter","blog/mpesa-api-starter",{"title":14,"path":15,"stem":16},"Ofuzah - Bloqueie o Acesso à Internet de Qualquer Aplicação no Windows com Um Clique","/blog/ofuzah-internet-blocker","blog/ofuzah-internet-blocker",{"title":18,"path":19,"stem":20},"QR Code Scanner: Um Leitor de QR Codes e Códigos de Barras Grátis e Sem Anúncios","/blog/qrcode-scanner","blog/qrcode-scanner",false,{"id":23,"title":24,"body":25,"description":26,"extension":27,"links":28,"meta":29,"navigation":30,"path":6,"seo":31,"stem":7,"__hash__":32},"pages/blog.yml","Últimos artigos",{"title":24,"description":26},"Onde partilho ideias, aprendizados e reflexões sobre desenvolvimento web e o mundo da tecnologia.","yml",null,{},true,{"title":24,"description":26},"TcnBcuFTVsTH_ChXQmFIan-pk7pdo5e91M2f9zyTXCc",[34,592,988],{"id":35,"title":14,"author":36,"body":40,"date":584,"description":585,"extension":586,"image":587,"meta":588,"minRead":589,"navigation":30,"path":15,"seo":590,"stem":16,"__hash__":591},"blog/blog/ofuzah-internet-blocker.md",{"name":37,"avatar":38},"Albino T. Calbe",{"src":39,"alt":37},"/profile.png",{"type":41,"value":42,"toc":565},"minimark",[43,56,67,70,79,82,87,92,95,99,106,113,117,123,125,129,143,150,161,163,165,170,174,190,216,220,223,230,234,248,263,273,277,283,289,293,296,325,329,353,359,363,366,405,409,436,438,442,453,463,465,469,475,500,503,505,509,516,531,543,547,553,556],[44,45,46,47,51,52,55],"p",{},"Quem já usou o computador ligado ao ",[48,49,50],"strong",{},"hotspot do telemóvel"," conhece bem esta história, liga o computador para enviar um e-mail ou abrir uma página e, minutos depois, o pacote de ",[48,53,54],{},"dados móveis"," desapareceu. Não foi o navegador nem o e-mail. Foram aplicações a trabalhar em segundo plano: um programa a descarregar uma atualização, um launcher de jogos a atualizar um jogo, uma ferramenta qualquer a sincronizar ficheiros.",[44,57,58,59,62,63,66],{},"Foi exatamente essa dor que me levou a criar o ",[48,60,61],{},"Ofuzah",": um app para Windows que permite ",[48,64,65],{},"bloquear ou permitir o acesso à Internet de cada aplicação com um clique",".",[44,68,69],{},"Neste artigo, explico o problema, o que o Windows já oferece (e porque não chega) e como o Ofuzah resolve isto de forma simples.",[44,71,73,74],{"align":72},"center","\n  ",[75,76],"img",{"src":77,"alt":78},"https://raw.githubusercontent.com/teldio/ofuzah-releases/main/screenshots/pt-aplicacoes.png","Ofuzah — lista de aplicações com o interruptor de acesso à Internet",[80,81],"hr",{},[83,84,86],"h2",{"id":85},"o-problema-dados-móveis-a-desaparecer","O Problema: Dados Móveis a Desaparecer",[88,89,91],"h3",{"id":90},"_1-aplicações-que-atualizam-sozinhas","1. Aplicações que Atualizam Sozinhas",[44,93,94],{},"Muitos programas para Windows verificam e descarregam atualizações sempre que detetam ligação à Internet. Numa rede de casa isso passa despercebido. Num hotspot com um pacote de dados limitado, uma única atualização pode gastar centenas de megabytes sem pedir autorização.",[88,96,98],{"id":97},"_2-o-windows-não-tem-uma-forma-simples-de-resolver-isto","2. O Windows Não Tem uma Forma Simples de Resolver Isto",[44,100,101,102,105],{},"O Windows tem a opção de ",[48,103,104],{},"ligação com tráfego limitado",", que trava algumas transferências do próprio sistema. Mas muitas aplicações de terceiros simplesmente a ignoram.",[44,107,108,109,112],{},"A solução \"oficial\" é a ",[48,110,111],{},"Firewall do Windows Defender com Segurança Avançada",". Funciona, mas obriga a abrir uma consola técnica, percorrer um assistente com vários passos, escolher o programa, o tipo de regra, os perfis de rede… e repetir tudo para cada aplicação. Para desfazer, é preciso encontrar a regra certa no meio de centenas de outras.",[88,114,116],{"id":115},"_3-programas-de-terceiros-complicados-ou-pagos","3. Programas de Terceiros Complicados ou Pagos",[44,118,119,120,66],{},"As alternativas que encontrei eram firewalls completas, cheias de opções avançadas, pagas, com anúncios, ou que instalam controladores e serviços próprios. Eu só queria uma coisa: ",[48,121,122],{},"escolher que apps podem usar a Internet",[80,124],{},[83,126,128],{"id":127},"a-solução","A Solução",[44,130,131,132,134,135,138,139,142],{},"O ",[48,133,61],{}," mostra as aplicações instaladas no computador e, ao lado de cada uma, um interruptor: ",[48,136,137],{},"Permitido"," ou ",[48,140,141],{},"Bloqueado",". Um clique e a aplicação deixa de conseguir aceder à Internet. Outro clique e volta ao normal.",[44,144,145,146,149],{},"Por baixo, o Ofuzah usa a própria ",[48,147,148],{},"Windows Defender Firewall",", que já vem com o Windows. Não instala controladores, não cria serviços permanentes e não substitui a firewall do sistema. Apenas cria, de forma organizada, as regras que teria de criar à mão.",[44,151,152,153,156,157,160],{},"O app foi desenvolvido com ",[48,154,155],{},".NET"," e ",[48,158,159],{},"WPF",", com uma interface pensada para se parecer com uma aplicação nativa do Windows 11.",[80,162],{},[80,164],{},[166,167,169],"h1",{"id":168},"recursos-do-app","Recursos do App",[83,171,173],{"id":172},"_1-lista-de-aplicações-instaladas","1. Lista de Aplicações Instaladas",[44,175,176,177,180,181,184,185,189],{},"O Ofuzah procura automaticamente as aplicações no ",[48,178,179],{},"menu Iniciar",", nos ",[48,182,183],{},"programas instalados"," e nas pastas habituais como ",[186,187,188],"em",{},"Program Files",". Para cada uma mostra o ícone, o nome, o caminho, a editora e o estado atual.",[191,192,193,200,206],"ul",{},[194,195,196,199],"li",{},[48,197,198],{},"Pesquisa instantânea"," por nome ou caminho.",[194,201,202,205],{},[48,203,204],{},"Filtros:"," todas, permitidas, bloqueadas, adicionadas por si ou com estado desconhecido.",[194,207,208,211,212,66],{},[48,209,210],{},"Adicionar aplicação:"," se um programa não aparecer na lista, basta escolher o ficheiro ",[213,214,215],"code",{},".exe",[83,217,219],{"id":218},"_2-bloqueio-com-um-clique","2. Bloqueio com Um Clique",[44,221,222],{},"Ao desligar o interruptor, o Ofuzah cria uma regra de saída na Firewall que impede essa aplicação de iniciar ligações à Internet. Ao ligar de novo, remove a regra.",[44,224,225,226,229],{},"Antes de mostrar o novo estado, o Ofuzah ",[48,227,228],{},"volta a ler a Firewall para confirmar"," que a alteração foi mesmo aplicada. O que vê no ecrã corresponde ao que está realmente configurado.",[83,231,233],{"id":232},"_3-perfis-de-rede-bloquear-só-no-hotspot","3. Perfis de Rede: Bloquear Só no Hotspot",[44,235,236,237,240,241,138,244,247],{},"Esta é uma das funcionalidades de que mais gosto. O Windows classifica cada rede num de três perfis: ",[48,238,239],{},"Domínio",", ",[48,242,243],{},"Privado",[48,245,246],{},"Público",". No painel de detalhes de cada aplicação, pode escolher em que perfis o bloqueio se aplica.",[44,249,250,251,254,255,258,259,262],{},"Quando se liga ao hotspot do telemóvel, o Windows costuma tratá-lo como uma ",[48,252,253],{},"rede Pública",", enquanto a rede de casa fica normalmente como ",[48,256,257],{},"Privada",". Assim, pode bloquear uma aplicação ",[48,260,261],{},"apenas no perfil Público",": ela continua a atualizar-se à vontade em casa, mas fica sem Internet quando está a usar dados móveis.",[264,265,266],"blockquote",{},[44,267,268,269,272],{},"Dica: confirme como cada rede está classificada em ",[186,270,271],{},"Definições → Rede e Internet",". O perfil depende da escolha feita quando se ligou a essa rede pela primeira vez.",[83,274,276],{"id":275},"_4-painel-com-o-resumo-de-tudo","4. Painel com o Resumo de Tudo",[44,278,131,279,282],{},[48,280,281],{},"Painel"," mostra quantas aplicações foram detetadas, quantas estão bloqueadas, o estado da Firewall em cada perfil de rede e as últimas alterações feitas.",[44,284,73,285],{"align":72},[75,286],{"src":287,"alt":288},"https://raw.githubusercontent.com/teldio/ofuzah-releases/main/screenshots/pt-painel.png","Painel do Ofuzah com o resumo de aplicações e o estado da Firewall",[83,290,292],{"id":291},"_5-estado-real-e-avisos-honestos","5. Estado Real e Avisos Honestos",[44,294,295],{},"O Ofuzah não se limita a dizer \"bloqueado\" ou \"permitido\". Também avisa quando algo pode interferir:",[191,297,298,305,312,319],{},[194,299,300,301,304],{},"A Firewall está ",[48,302,303],{},"desativada"," num perfil de rede;",[194,306,307,308,311],{},"Existe uma ",[48,309,310],{},"regra de outro programa"," que já bloqueia ou permite a aplicação;",[194,313,314,315,318],{},"Uma ",[48,316,317],{},"política da empresa"," se sobrepõe às regras locais;",[194,320,321,322,66],{},"O executável foi ",[48,323,324],{},"removido ou mudou de pasta",[83,326,328],{"id":327},"_6-gestão-de-regras-e-histórico","6. Gestão de Regras e Histórico",[191,330,331,338,344],{},[194,332,333,334,337],{},"A página ",[48,335,336],{},"Regras de Firewall"," lista todas as regras criadas pelo Ofuzah, que pode remover uma a uma ou todas de uma vez.",[194,339,340,341],{},"As regras de outros programas aparecem apenas para consulta. ",[48,342,343],{},"O Ofuzah nunca as altera.",[194,345,131,346,349,350,66],{},[48,347,348],{},"Histórico"," regista cada operação (data, aplicação, resultado) e pode ser exportado para ",[48,351,352],{},"CSV",[44,354,73,355],{"align":72},[75,356],{"src":357,"alt":358},"https://raw.githubusercontent.com/teldio/ofuzah-releases/main/screenshots/pt-regras.png","Página de regras de Firewall do Ofuzah",[83,360,362],{"id":361},"_7-seguro-por-desenho","7. Seguro por Desenho",[44,364,365],{},"Mexer na Firewall exige privilégios de administrador. Por isso:",[191,367,368,374,385,391,398],{},[194,369,370,371,66],{},"A interface do Ofuzah funciona ",[48,372,373],{},"sem privilégios de administrador",[194,375,376,377,380,381,384],{},"Cada alteração passa por um ",[48,378,379],{},"assistente separado",", que só arranca depois de confirmar o pedido do ",[48,382,383],{},"Controlo de Conta de Utilizador (UAC)"," do Windows.",[194,386,387,388,66],{},"O Ofuzah ",[48,389,390],{},"nunca pede a sua palavra-passe",[194,392,393,394,397],{},"Só mexe nas ",[48,395,396],{},"suas próprias regras"," (todas do grupo «Ofuzah»).",[194,399,400,401,404],{},"Ao desinstalar, ",[48,402,403],{},"pergunta-lhe"," se quer remover as regras que criou.",[83,406,408],{"id":407},"_8-detalhes-que-fazem-diferença","8. Detalhes que Fazem Diferença",[191,410,411,417,423,429],{},[194,412,413,416],{},[48,414,415],{},"Tema claro e escuro",";",[194,418,419,422],{},[48,420,421],{},"Português e inglês",", com troca imediata nas configurações;",[194,424,425,428],{},[48,426,427],{},"Navegação por teclado"," e suporte para leitores de ecrã;",[194,430,431,432,435],{},"Opção para ",[48,433,434],{},"iniciar com o Windows"," (desligada por predefinição).",[80,437],{},[166,439,441],{"id":440},"uma-limitação-que-prefiro-explicar","Uma Limitação que Prefiro Explicar",[44,443,444,445,448,449,452],{},"O Ofuzah bloqueia ",[48,446,447],{},"executáveis individuais",". Algumas aplicações, sobretudo navegadores, jogos e programas com atualizadores, usam ",[48,450,451],{},"vários processos ou serviços"," para comunicar. Se bloquear apenas o executável principal, o atualizador pode continuar a funcionar.",[44,454,455,456,138,459,462],{},"Nesses casos, procure na lista os outros executáveis da mesma aplicação (por exemplo, os que têm ",[186,457,458],{},"update",[186,460,461],{},"helper"," no nome) e bloqueie-os também.",[80,464],{},[166,466,468],{"id":467},"grátis-sem-anúncios-e-privado","Grátis, Sem Anúncios e Privado",[44,470,131,471,474],{},[48,472,473],{},"Ofuzah é totalmente gratuito e não tem anúncios",". Não há versão \"Premium\" nem funcionalidades bloqueadas.",[191,476,477,482,488,494],{},[194,478,479],{},[48,480,481],{},"Não precisa de criar conta.",[194,483,484,487],{},[48,485,486],{},"Funciona offline."," Não envia dados para nenhum servidor e não tem telemetria.",[194,489,490,493],{},[48,491,492],{},"Não captura nem analisa o seu tráfego."," Apenas gere regras da Firewall.",[194,495,496,497,66],{},"O histórico e as definições ficam ",[48,498,499],{},"apenas no seu computador",[44,501,502],{},"Faria pouco sentido um app para poupar dados móveis andar ele próprio a gastá-los.",[80,504],{},[166,506,508],{"id":507},"onde-descarregar","Onde Descarregar",[44,510,511,512,515],{},"O Ofuzah está disponível para ",[48,513,514],{},"Windows 10 (versão 1809 ou posterior) e Windows 11, 64 bits",". Não é preciso instalar mais nada.",[191,517,518],{},[194,519,520,523,524],{},[48,521,522],{},"Windows:"," ",[525,526,530],"a",{"href":527,"rel":528},"https://github.com/teldio/ofuzah-releases/releases/latest",[529],"nofollow","Transferir no GitHub",[264,532,533],{},[44,534,535,538,539,542],{},[48,536,537],{},"Nota:"," o instalador ainda não está assinado digitalmente, por isso o Windows SmartScreen pode mostrar o aviso «O Windows protegeu o seu PC». Para continuar, clique em ",[48,540,541],{},"Mais informações → Executar mesmo assim",". Em cada versão publico o código SHA-256 do instalador para que possa confirmar que o ficheiro não foi alterado.",[166,544,546],{"id":545},"minha-conclusão","Minha Conclusão",[44,548,549,550,66],{},"O Ofuzah nasceu de um problema bem real, ver os dados móveis desaparecer por causa de aplicações que eu nem estava a usar. O Windows já tem tudo o que é preciso para resolver isto, mas escondido atrás de uma consola técnica. O Ofuzah só torna isso ",[48,551,552],{},"simples e prático",[44,554,555],{},"Se também trabalha muitas vezes com o hotspot do telemóvel, ou simplesmente quer decidir que programas podem falar com a Internet, experimente. E se tiver sugestões ou encontrar algum problema, deixe a sua opinião: é isso que me ajuda a melhorar o app.",[44,557,560,564],{"align":558,"style":559},"right","font-size: 12px;",[561,562,563],"i",{}," texto aprimorado por IA","🤖",{"title":566,"searchDepth":567,"depth":567,"links":568},"",2,[569,575,576,577,578,579,580,581,582,583],{"id":85,"depth":567,"text":86,"children":570},[571,573,574],{"id":90,"depth":572,"text":91},3,{"id":97,"depth":572,"text":98},{"id":115,"depth":572,"text":116},{"id":127,"depth":567,"text":128},{"id":172,"depth":567,"text":173},{"id":218,"depth":567,"text":219},{"id":232,"depth":567,"text":233},{"id":275,"depth":567,"text":276},{"id":291,"depth":567,"text":292},{"id":327,"depth":567,"text":328},{"id":361,"depth":567,"text":362},{"id":407,"depth":567,"text":408},"2026-10-16T00:00:00.000Z","Conheça o Ofuzah, um app grátis para Windows que permite bloquear ou permitir o acesso à Internet de cada aplicação, ideal para poupar dados móveis quando usa o hotspot do telemóvel.","md","/ofuzah.webp",{},7,{"title":14,"description":585},"k2uFH8NMjjwR9i1NLulrpVw4YnCp6oeJAXzGio6NoDI",{"id":593,"title":18,"author":594,"body":596,"date":981,"description":982,"extension":586,"image":983,"meta":984,"minRead":985,"navigation":30,"path":19,"seo":986,"stem":20,"__hash__":987},"blog/blog/qrcode-scanner.md",{"name":37,"avatar":595},{"src":39,"alt":37},{"type":41,"value":597,"toc":965},[598,609,620,623,625,629,633,636,640,643,647,650,654,657,659,663,671,687,689,691,693,697,700,714,717,721,728,742,748,752,759,779,786,790,801,819,823,826,845,852,856,866,870,890,892,894,901,904,922,925,927,929,948,950,953,958,961],[44,599,600,601,604,605,608],{},"Ler um ",[48,602,603],{},"QR Code"," devia ser a coisa mais simples do mundo: apontar a câmara, ver o conteúdo, seguir em frente. Mas quem já procurou um leitor na Play Store ou na App Store sabe que a realidade é outra. A maioria dos apps gratuitos está cheia de ",[48,606,607],{},"anúncios em ecrã inteiro",", banners que tapam a câmara, pedidos de subscrição e permissões que não fazem sentido nenhum para um simples leitor.",[44,610,611,612,615,616,619],{},"Foi por isso que criei o ",[48,613,614],{},"QR Code Scanner",": um leitor de QR Codes e códigos de barras ",[48,617,618],{},"100% grátis, sem anúncios"," e focado apenas em fazer bem o seu trabalho.",[44,621,622],{},"Neste artigo, apresento o app, os seus recursos e o porquê de ter decidido mantê-lo livre de publicidade.",[80,624],{},[83,626,628],{"id":627},"o-problema-dos-leitores-grátis","O Problema dos Leitores \"Grátis\"",[88,630,632],{"id":631},"_1-anúncios-em-todo-o-lado","1. Anúncios em Todo o Lado",[44,634,635],{},"Em muitos leitores, cada leitura vem acompanhada de um anúncio. Às vezes é preciso esperar alguns segundos, ou encontrar um \"X\" minúsculo, só para ver o conteúdo de um código que já foi lido.",[88,637,639],{"id":638},"_2-permissões-exageradas","2. Permissões Exageradas",[44,641,642],{},"Um leitor de QR Codes precisa da câmara. Não precisa da sua localização, dos seus contactos nem de acesso permanente à internet para lhe mostrar publicidade.",[88,644,646],{"id":645},"_3-dados-enviados-para-terceiros","3. Dados Enviados para Terceiros",[44,648,649],{},"Os códigos que lemos dizem muito sobre nós: os sites que visitamos, as redes Wi-Fi a que nos ligamos, os produtos que compramos. Em apps sustentados por publicidade, essa informação tem valor comercial.",[88,651,653],{"id":652},"_4-interfaces-confusas","4. Interfaces Confusas",[44,655,656],{},"Menus escondidos, botões de \"Premium\" em destaque e ecrãs carregados tornam uma tarefa de dois segundos numa experiência frustrante.",[80,658],{},[83,660,662],{"id":661},"a-solução-qr-code-scanner","A Solução: QR Code Scanner",[44,664,131,665,667,668],{},[48,666,614],{}," foi pensado para ser o oposto disso tudo. Abre direto na câmara, lê o código e mostra o resultado. ",[48,669,670],{},"Sem anúncios, sem conta, sem pagamentos.",[44,672,152,673,156,676,679,680,683,684,66],{},[48,674,675],{},"Expo",[48,677,678],{},"React Native",", por isso funciona de forma nativa tanto em ",[48,681,682],{},"Android"," como em ",[48,685,686],{},"iOS",[80,688],{},[80,690],{},[166,692,169],{"id":168},[83,694,696],{"id":695},"_1-dois-modos-de-leitura","1. Dois Modos de Leitura",[44,698,699],{},"No topo do ecrã, pode alternar entre dois modos, consoante o que pretende ler:",[191,701,702,708],{},[194,703,704,707],{},[48,705,706],{},"QR Code:"," lê QR Codes, Data Matrix, Aztec e PDF417.",[194,709,710,713],{},[48,711,712],{},"Código de Barras:"," lê EAN-13, EAN-8, UPC-A, UPC-E, Code 128, Code 39, Code 93, ITF-14 e Codabar, os formatos que encontramos em produtos de supermercado, livros, caixas e etiquetas.",[44,715,716],{},"Separar os modos torna a leitura mais rápida e evita que a câmara apanhe o código errado quando há vários por perto.",[83,718,720],{"id":719},"_2-leitura-a-partir-da-galeria","2. Leitura a Partir da Galeria",[44,722,723,724,727],{},"Recebeu um QR Code numa imagem pelo WhatsApp? Tirou um print de um código? Não precisa de outro telemóvel para o ler. Basta tocar em ",[48,725,726],{},"\"Da galeria\"",", escolher a foto, e o app procura o código na imagem.",[191,729,730,736],{},[194,731,732,733,735],{},"No ",[48,734,682],{},", lê todos os formatos suportados.",[194,737,732,738,741],{},[48,739,740],{},"iPhone",", lê QR Codes (limitação do próprio sistema iOS).",[44,743,744,745,66],{},"E tudo isto funciona ",[48,746,747],{},"offline",[83,749,751],{"id":750},"_3-resultado-claro-e-fácil-de-copiar","3. Resultado Claro e Fácil de Copiar",[44,753,754,755,758],{},"Quando um código é detetado, o resultado aparece numa ",[48,756,757],{},"folha inferior nativa"," com:",[191,760,761,770,773],{},[194,762,763,764,138,766,769],{},"O tipo de código lido (por exemplo, ",[186,765,603],{},[186,767,768],{},"EAN-13",");",[194,771,772],{},"O conteúdo completo, que pode ser selecionado;",[194,774,775,776,66],{},"Um botão para ",[48,777,778],{},"copiar para a área de transferência",[44,780,781,782,785],{},"O app ",[48,783,784],{},"não abre links automaticamente",". Mostra-lhe primeiro o conteúdo, para que possa decidir o que fazer com ele. É uma pequena proteção contra QR Codes maliciosos colados em locais públicos.",[83,787,789],{"id":788},"_4-histórico-de-leituras","4. Histórico de Leituras",[44,791,792,793,796,797,800],{},"Todas as leituras ficam guardadas num ",[48,794,795],{},"histórico local",", com as ",[48,798,799],{},"últimas 100 leituras"," organizadas por data (\"Hoje\", \"Ontem\", etc.).",[191,802,803,806,813],{},[194,804,805],{},"Se ler de novo um código que já está no histórico, ele passa para o topo da lista em vez de ficar duplicado.",[194,807,808,809,812],{},"Pode ",[48,810,811],{},"limpar o histórico"," a qualquer momento.",[194,814,815,816,66],{},"O histórico fica guardado ",[48,817,818],{},"apenas no seu dispositivo",[83,820,822],{"id":821},"_5-controlos-da-câmara","5. Controlos da Câmara",[44,824,825],{},"Para os códigos mais difíceis de ler:",[191,827,828,834,840],{},[194,829,830,833],{},[48,831,832],{},"Lanterna"," para ambientes com pouca luz;",[194,835,836,839],{},[48,837,838],{},"Zoom"," de 1x, 2x e 3x para códigos pequenos ou distantes;",[194,841,842,66],{},[48,843,844],{},"Troca entre câmara traseira e frontal",[44,846,847,848,851],{},"Também é possível ",[48,849,850],{},"pausar a leitura"," e retomá-la com um toque.",[83,853,855],{"id":854},"_6-português-e-inglês","6. Português e Inglês",[44,857,858,859,156,862,865],{},"O app usa automaticamente o idioma do seu telemóvel, mas pode trocar entre ",[48,860,861],{},"português",[48,863,864],{},"inglês"," diretamente no app, sem ir às definições do sistema.",[83,867,869],{"id":868},"_7-detalhes-que-fazem-diferença","7. Detalhes que Fazem Diferença",[191,871,872,878,884],{},[194,873,874,877],{},[48,875,876],{},"Vibração (feedback háptico)"," quando um código é detetado;",[194,879,880,883],{},[48,881,882],{},"Animações suaves"," que respeitam a opção \"reduzir movimento\" do sistema, para quem é sensível a animações;",[194,885,886,889],{},[48,887,888],{},"Tema escuro",", confortável para os olhos e para a bateria.",[80,891],{},[166,893,468],{"id":467},[44,895,896,897,900],{},"Este é o ponto mais importante: o ",[48,898,899],{},"QR Code Scanner é totalmente gratuito e não tem anúncios",". Não há versão \"Premium\", não há funcionalidades bloqueadas e não há publicidade escondida.",[44,902,903],{},"Além disso:",[191,905,906,910,916],{},[194,907,908],{},[48,909,481],{},[194,911,912,915],{},[48,913,914],{},"Não faz pedidos à internet."," O app não envia os seus dados para nenhum servidor.",[194,917,918,921],{},[48,919,920],{},"Só pede as permissões necessárias:"," a câmara, para ler códigos, e o acesso às fotos, apenas quando escolhe ler a partir da galeria.",[44,923,924],{},"Os códigos que lê são seus e ficam no seu telemóvel.",[80,926],{},[166,928,508],{"id":507},[191,930,931,940],{},[194,932,933,523,936],{},[48,934,935],{},"Android:",[525,937,939],{"href":938},"#","Google Play Store",[194,941,942,523,945],{},[48,943,944],{},"iOS:",[525,946,947],{"href":938},"App Store",[166,949,546],{"id":545},[44,951,952],{},"Nem todas as ferramentas precisam de ser um negócio. Um leitor de QR Codes é algo que usamos no dia a dia, em restaurantes, lojas, eventos ou para partilhar uma rede Wi-Fi, e merece ser simples, rápido e respeitar quem o usa.",[44,954,131,955,957],{},[48,956,614],{}," nasceu dessa ideia: fazer uma coisa e fazê-la bem, sem distrações e sem anúncios.",[44,959,960],{},"Se experimentar o app, deixe a sua opinião. O feedback de quem o usa é o que me ajuda a melhorá-lo.",[44,962,963,564],{"align":558,"style":559},[561,964,563],{},{"title":566,"searchDepth":567,"depth":567,"links":966},[967,973,974,975,976,977,978,979,980],{"id":627,"depth":567,"text":628,"children":968},[969,970,971,972],{"id":631,"depth":572,"text":632},{"id":638,"depth":572,"text":639},{"id":645,"depth":572,"text":646},{"id":652,"depth":572,"text":653},{"id":661,"depth":567,"text":662},{"id":695,"depth":567,"text":696},{"id":719,"depth":567,"text":720},{"id":750,"depth":567,"text":751},{"id":788,"depth":567,"text":789},{"id":821,"depth":567,"text":822},{"id":854,"depth":567,"text":855},{"id":868,"depth":567,"text":869},"2026-10-14T00:00:00.000Z","Conheça o QR Code Scanner, um app para Android e iOS que lê QR Codes e códigos de barras sem anúncios, sem conta e sem enviar os seus dados para lado nenhum.","/qrcode-scanner.webp",{},6,{"title":18,"description":982},"z4X2QeZwgl3wTKTA2Od1IbSRi1d9OizPn2mASgzxd30",{"id":989,"title":10,"author":990,"body":992,"date":1498,"description":1499,"extension":586,"image":1500,"meta":1501,"minRead":1307,"navigation":30,"path":11,"seo":1502,"stem":12,"__hash__":1503},"blog/blog/mpesa-api-starter.md",{"name":37,"avatar":991},{"src":39,"alt":37},{"type":41,"value":993,"toc":1484},[994,1005,1016,1018,1022,1026,1037,1046,1050,1064,1068,1087,1091,1105,1107,1111,1118,1132,1134,1136,1140,1144,1147,1180,1183,1187,1190,1203,1207,1219,1376,1380,1383,1398,1410,1413,1416,1420,1426,1429,1437,1455,1460,1467,1470,1473,1476,1480],[44,995,996,997,1000,1001,1004],{},"A integração com ",[48,998,999],{},"APIs de pagamento",", especialmente a do ",[48,1002,1003],{},"M-Pesa",", é uma das etapas mais desafiadoras para muitos programadores iniciantes em Moçambique. Embora a documentação do serviço ofereça uma visão geral, a implementação prática muitas vezes se transforma num verdadeiro teste de paciência — entre certificados SSL, chaves públicas e privadas, endpoints inconsistentes e autenticações complexas.",[44,1006,1007,1008,1011,1012,1015],{},"Neste artigo, partilho uma análise sincera sobre essas dificuldades e apresento uma ",[48,1009,1010],{},"solução prática",": um ",[48,1013,1014],{},"backend M-Pesa já pronto para uso",", que qualquer desenvolvedor pode clonar do GitHub e fazer deploy em minutos, utilizando apenas as suas próprias variáveis de ambiente obtidas no portal do desenvolvedor da M-Pesa.",[80,1017],{},[83,1019,1021],{"id":1020},"as-principais-dificuldades-dos-iniciantes","As Principais Dificuldades dos Iniciantes",[88,1023,1025],{"id":1024},"_1-documentação-incompleta-ou-confusa","1. Documentação Incompleta ou Confusa",[44,1027,1028,1029,1032,1033,1036],{},"Muitos desenvolvedores relatam que a ",[48,1030,1031],{},"documentação oficial da API M-Pesa"," (fornecida pela Vodacom Moçambique) é pouco detalhada, principalmente em relação a exemplos de código prático.",[1034,1035],"br",{},"\nIsso leva os iniciantes a cometer erros simples, como formatar mal as requisições ou usar endpoints incorretos.",[264,1038,1039],{},[44,1040,1041,1042,1045],{},"“Passei dias a tentar entender porque minha requisição devolvia ",[186,1043,1044],{},"403 Forbidden",", e o problema era apenas o cabeçalho mal formatado.” — Desenvolvedor júnior de Maputo",[88,1047,1049],{"id":1048},"_2-dificuldade-em-configurar-o-ssl","2. Dificuldade em Configurar o SSL",[44,1051,1052,1053,1056,1057,1059,1060,1063],{},"Embora o ambiente ",[48,1054,1055],{},"sandbox"," permita testes sem SSL, o ambiente de produção exige certificados válidos.",[1034,1058],{},"\nPara quem está a trabalhar localmente ou num ambiente gratuito, como o ",[48,1061,1062],{},"Vercel",", configurar HTTPS pode ser uma dor de cabeça.",[88,1065,1067],{"id":1066},"_3-autenticação-e-chaves-criptográficas","3. Autenticação e Chaves Criptográficas",[44,1069,1070,1071,1074,1075,240,1078,156,1081,66,1084,1086],{},"O M-Pesa utiliza ",[48,1072,1073],{},"autenticação baseada em chaves públicas e privadas",", o que exige que o programador entenda bem conceitos de ",[48,1076,1077],{},"criptografia RSA",[48,1079,1080],{},"assinaturas digitais",[48,1082,1083],{},"segurança de API",[1034,1085],{},"\nEsses temas são raramente abordados nos cursos iniciais de programação disponíveis em Moçambique, o que gera frustração.",[88,1088,1090],{"id":1089},"_4-ausência-de-exemplos-em-typescriptnodejs","4. Ausência de Exemplos em TypeScript/Node.js",[44,1092,1093,1094,1097,1098,1100,1101,1104],{},"Grande parte dos exemplos disponíveis online está em ",[48,1095,1096],{},"PHP ou Java",", linguagens mais antigas no ecossistema local.",[1034,1099],{},"\nEntretanto, o novo mercado — dominado por ",[48,1102,1103],{},"Node.js, React, Next.js e Vite"," — exige soluções modernas e fáceis de integrar ao frontend.",[80,1106],{},[83,1108,1110],{"id":1109},"a-solução-backend-m-pesa-pronto-para-deploy","A Solução: Backend M-Pesa Pronto para Deploy",[44,1112,1113,1114,1117],{},"Pensando nesses desafios, preparei um ",[48,1115,1116],{},"backend completo e funcional",", pronto para ser usado por qualquer desenvolvedor que queira integrar pagamentos via M-Pesa com rapidez e segurança.",[44,1119,1120,1121,1124,1125,1128,1129,1131],{},"Esse projeto foi criado com ",[48,1122,1123],{},"NextJS",", e pode ser ",[48,1126,1127],{},"implantado gratuitamente na Vercel"," com apenas alguns cliques.",[1034,1130],{},"\nO código está hospedado no GitHub, e basta clonar o repositório e definir as variáveis de ambiente.",[80,1133],{},[80,1135],{},[166,1137,1139],{"id":1138},"passos-para-criar-seu-próprio-backend","Passos para criar seu próprio backend",[83,1141,1143],{"id":1142},"_1-clonar-o-repositório","1. Clonar o Repositório",[44,1145,1146],{},"Acesse o repositório no GitHub e clone-o para o seu computador:",[1148,1149,1153],"pre",{"className":1150,"code":1151,"language":1152,"meta":566,"style":566},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","git clone https://github.com/calbedev/mpesa-api-starter.git\ncd mpesa-backend-ready\n","bash",[213,1154,1155,1171],{"__ignoreMap":566},[1156,1157,1160,1164,1168],"span",{"class":1158,"line":1159},"line",1,[1156,1161,1163],{"class":1162},"sBMFI","git",[1156,1165,1167],{"class":1166},"sfazB"," clone",[1156,1169,1170],{"class":1166}," https://github.com/calbedev/mpesa-api-starter.git\n",[1156,1172,1173,1177],{"class":1158,"line":567},[1156,1174,1176],{"class":1175},"s2Zo4","cd",[1156,1178,1179],{"class":1166}," mpesa-backend-ready\n",[44,1181,1182],{},"Se preferir, pode também fazer o fork e trabalhar na sua própria versão.",[83,1184,1186],{"id":1185},"_2-instalar-dependências","2. Instalar Dependências",[44,1188,1189],{},"No diretório do projeto, instale as dependências necessárias:",[1148,1191,1193],{"className":1150,"code":1192,"language":1152,"meta":566,"style":566},"pnpm install\n",[213,1194,1195],{"__ignoreMap":566},[1156,1196,1197,1200],{"class":1158,"line":1159},[1156,1198,1199],{"class":1162},"pnpm",[1156,1201,1202],{"class":1166}," install\n",[83,1204,1206],{"id":1205},"_3-definir-as-variáveis-de-ambiente","3. Definir as variáveis de ambiente",[44,1208,1209,1210,1213,1214,66],{},"Crie um ficheiro ",[213,1211,1212],{},".env"," e defina as seguintes variáveis, obtidas no ",[525,1215,1218],{"href":1216,"rel":1217},"https://developer.mpesa.vm.co.mz/",[529],"portal do desenvolvedor M-Pesa",[1148,1220,1222],{"className":1150,"code":1221,"language":1152,"meta":566,"style":566},"# M-Pesa API Configuration (OBRIGATÓRIO)\nMPESA_API_KEY=\"sua api key\"\nMPESA_PUBLIC_KEY= \"Sua public key\"\nMPESA_API_URL=api.sandbox.vm.co.mz \nMPESA_USE_SSL=false\n\n# API Security (OBRIGATÓRIO)\n# Defina uma chave secreta forte para proteger suas APIs\n# Esta chave será usada para autenticar requisições do frontend\nAPI_SECRET_KEY=\"defina uma chave secreta\"\n\n# Service Provider Configuration (OPCIONAL mas recomendado)\n# Necessário para operações B2B, B2C e Reversal\nMPESA_SERVICE_PROVIDER_CODE=171717\nMPESA_INITIATOR_IDENTIFIER=MPesa2018\nMPESA_SECURITY_CREDENTIAL=Mpesa2019\n",[213,1223,1224,1230,1249,1264,1278,1289,1294,1299,1305,1311,1326,1331,1337,1343,1354,1365],{"__ignoreMap":566},[1156,1225,1226],{"class":1158,"line":1159},[1156,1227,1229],{"class":1228},"sHwdD","# M-Pesa API Configuration (OBRIGATÓRIO)\n",[1156,1231,1232,1236,1240,1243,1246],{"class":1158,"line":567},[1156,1233,1235],{"class":1234},"sTEyZ","MPESA_API_KEY",[1156,1237,1239],{"class":1238},"sMK4o","=",[1156,1241,1242],{"class":1238},"\"",[1156,1244,1245],{"class":1166},"sua api key",[1156,1247,1248],{"class":1238},"\"\n",[1156,1250,1251,1254,1256,1259,1262],{"class":1158,"line":572},[1156,1252,1253],{"class":1234},"MPESA_PUBLIC_KEY",[1156,1255,1239],{"class":1238},[1156,1257,1258],{"class":1238}," \"",[1156,1260,1261],{"class":1166},"Sua public key",[1156,1263,1248],{"class":1238},[1156,1265,1267,1270,1272,1275],{"class":1158,"line":1266},4,[1156,1268,1269],{"class":1234},"MPESA_API_URL",[1156,1271,1239],{"class":1238},[1156,1273,1274],{"class":1166},"api.sandbox.vm.co.mz",[1156,1276,1277],{"class":1234}," \n",[1156,1279,1281,1284,1286],{"class":1158,"line":1280},5,[1156,1282,1283],{"class":1234},"MPESA_USE_SSL",[1156,1285,1239],{"class":1238},[1156,1287,1288],{"class":1166},"false\n",[1156,1290,1291],{"class":1158,"line":985},[1156,1292,1293],{"emptyLinePlaceholder":30},"\n",[1156,1295,1296],{"class":1158,"line":589},[1156,1297,1298],{"class":1228},"# API Security (OBRIGATÓRIO)\n",[1156,1300,1302],{"class":1158,"line":1301},8,[1156,1303,1304],{"class":1228},"# Defina uma chave secreta forte para proteger suas APIs\n",[1156,1306,1308],{"class":1158,"line":1307},9,[1156,1309,1310],{"class":1228},"# Esta chave será usada para autenticar requisições do frontend\n",[1156,1312,1314,1317,1319,1321,1324],{"class":1158,"line":1313},10,[1156,1315,1316],{"class":1234},"API_SECRET_KEY",[1156,1318,1239],{"class":1238},[1156,1320,1242],{"class":1238},[1156,1322,1323],{"class":1166},"defina uma chave secreta",[1156,1325,1248],{"class":1238},[1156,1327,1329],{"class":1158,"line":1328},11,[1156,1330,1293],{"emptyLinePlaceholder":30},[1156,1332,1334],{"class":1158,"line":1333},12,[1156,1335,1336],{"class":1228},"# Service Provider Configuration (OPCIONAL mas recomendado)\n",[1156,1338,1340],{"class":1158,"line":1339},13,[1156,1341,1342],{"class":1228},"# Necessário para operações B2B, B2C e Reversal\n",[1156,1344,1346,1349,1351],{"class":1158,"line":1345},14,[1156,1347,1348],{"class":1234},"MPESA_SERVICE_PROVIDER_CODE",[1156,1350,1239],{"class":1238},[1156,1352,1353],{"class":1166},"171717\n",[1156,1355,1357,1360,1362],{"class":1158,"line":1356},15,[1156,1358,1359],{"class":1234},"MPESA_INITIATOR_IDENTIFIER",[1156,1361,1239],{"class":1238},[1156,1363,1364],{"class":1166},"MPesa2018\n",[1156,1366,1368,1371,1373],{"class":1158,"line":1367},16,[1156,1369,1370],{"class":1234},"MPESA_SECURITY_CREDENTIAL",[1156,1372,1239],{"class":1238},[1156,1374,1375],{"class":1166},"Mpesa2019\n",[83,1377,1379],{"id":1378},"_4-testar-localmente","4. Testar localmente",[44,1381,1382],{},"Antes de fazer o deploy, teste o projeto no seu ambiente local:",[1148,1384,1386],{"className":1150,"code":1385,"language":1152,"meta":566,"style":566},"pnpm run dev\n",[213,1387,1388],{"__ignoreMap":566},[1156,1389,1390,1392,1395],{"class":1158,"line":1159},[1156,1391,1199],{"class":1162},[1156,1393,1394],{"class":1166}," run",[1156,1396,1397],{"class":1166}," dev\n",[44,1399,1400,1401,1405,1406],{},"Acesse ",[525,1402,1403],{"href":1403,"rel":1404},"http://localhost:3000",[529],", se tudo estiver configurado corretamente, o status da api estará ok, como na imagem abaixo:\n",[75,1407],{"alt":1408,"src":1409},"Status da API","/status.jpeg",[44,1411,1412],{},"Acesse as página de testes para fazer os testes de todas as funcionalidades com formulários intuitivos e visualização de respostas em tempo real.",[44,1414,1415],{},"Acesse a página da documentação para aprender como integrar as APIs no seu frontend com exemplos práticos e detalhados.",[83,1417,1419],{"id":1418},"_5-fazer-deploy-na-vercel","5. Fazer Deploy na Vercel",[1421,1422,1423],"ol",{},[194,1424,1425],{},"Crie uma conta em vercel.com",[44,1427,1428],{},"Clique em “Add New Project” → “Import Git Repository”.",[1421,1430,1431,1434],{"start":567},[194,1432,1433],{},"Escolha o repositório clonado no GitHub.",[194,1435,1436],{},"Configure as variáveis de ambiente na aba Environment Variables:",[191,1438,1439,1441,1443,1445,1447,1449,1451,1453],{},[194,1440,1235],{},[194,1442,1253],{},[194,1444,1269],{},[194,1446,1283],{},[194,1448,1316],{},[194,1450,1348],{},[194,1452,1359],{},[194,1454,1370],{},[1421,1456,1457],{"start":1280},[194,1458,1459],{},"Clique em Deploy.",[44,1461,1462,1463],{},"Em menos de 2 minutos, a Vercel compila e coloca o seu backend online com um domínio gratuito como:\n",[525,1464,1465],{"href":1465,"rel":1466},"https://mpesa-backend-ready.vercel.app",[529],[166,1468,1469],{"id":545},"Minha conclusão",[44,1471,1472],{},"Criar um backend M-Pesa do zero pode parecer uma tarefa impossível no início, mas com as ferramentas certas, torna-se um processo acessível e educativo.\nCom este projeto pronto para deploy, qualquer iniciante pode colocar a sua API no ar em minutos — aprendendo, testando e evoluindo com segurança.",[44,1474,1475],{},"O futuro do desenvolvimento em Moçambique depende de acesso, partilha de conhecimento e colaboração.\nE este é apenas o primeiro passo para transformar ideias locais em soluções digitais reais.",[44,1477,1478,564],{"align":558,"style":559},[561,1479,563],{},[1481,1482,1483],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}",{"title":566,"searchDepth":567,"depth":567,"links":1485},[1486,1492,1493,1494,1495,1496,1497],{"id":1020,"depth":567,"text":1021,"children":1487},[1488,1489,1490,1491],{"id":1024,"depth":572,"text":1025},{"id":1048,"depth":572,"text":1049},{"id":1066,"depth":572,"text":1067},{"id":1089,"depth":572,"text":1090},{"id":1109,"depth":567,"text":1110},{"id":1142,"depth":567,"text":1143},{"id":1185,"depth":567,"text":1186},{"id":1205,"depth":567,"text":1206},{"id":1378,"depth":567,"text":1379},{"id":1418,"depth":567,"text":1419},"2025-10-15T00:00:00.000Z","Um olhar realista sobre as dificuldades enfrentadas por desenvolvedores moçambicanos ao integrar a API do M-Pesa, e como um backend pronto para deploy na Vercel pode simplificar esse processo.","/mpesa-starter-api.png",{},{"title":10,"description":1499},"mwQRQMkpyUgT-r7pOSXrQ_kUoVJ9ft8SKtGtbf6vlZ4",1792227169675]