Skip to content

Instantly share code, notes, and snippets.

@aborruso
Last active April 1, 2026 08:44
Show Gist options
  • Select an option

  • Save aborruso/8f4693916761b88cd0bd3c70559602a5 to your computer and use it in GitHub Desktop.

Select an option

Save aborruso/8f4693916761b88cd0bd3c70559602a5 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CAP Professional Open – Poste Italiane</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family: Arial, sans-serif; color: #333; background:#fff; }
/* TOP BAR */
.topbar { background:#f5f5f5; display:flex; justify-content:space-between; align-items:center; padding:6px 16px; font-size:11px; color:#555; border-bottom:1px solid #ddd; flex-wrap:wrap; gap:4px; }
.topbar a { color:#555; text-decoration:none; margin-left:10px; }
.topbar-left { display:flex; flex-wrap:wrap; gap:8px; }
.topbar-left span { cursor:pointer; }
.topbar-left span.active { color:#003399; font-weight:bold; border-bottom:2px solid #003399; }
/* NAVBAR */
.navbar { background:#003399; display:flex; align-items:center; padding:0 16px; height:52px; gap:16px; overflow-x:auto; }
.navbar::-webkit-scrollbar { display:none; }
.logo { background:#f5e100; padding:5px 10px; font-size:18px; font-weight:bold; color:#003399; white-space:nowrap; flex-shrink:0; }
.nav-item { color:#fff; font-size:11px; font-weight:bold; text-transform:uppercase; cursor:pointer; padding:16px 2px; white-space:nowrap; flex-shrink:0; }
.nav-right { margin-left:auto; color:#fff; font-size:16px; flex-shrink:0; }
/* SUBTABS */
.subtabs { display:flex; overflow-x:auto; padding:0 8px; border-bottom:2px solid #e0e0e0; background:#fff; }
.subtabs::-webkit-scrollbar { display:none; }
.subtab { padding:12px 10px; font-size:11px; cursor:pointer; color:#555; border-bottom:3px solid transparent; margin-bottom:-2px; white-space:nowrap; flex-shrink:0; }
.subtab.active { color:#003399; font-weight:bold; border-bottom:3px solid #003399; }
/* HERO */
.hero { padding:24px 16px; display:flex; flex-direction:column; gap:20px; }
@media(min-width:700px){
.hero { flex-direction:row; align-items:flex-start; gap:32px; padding:40px 24px; }
.hero-right { width:380px; flex-shrink:0; }
}
.hero-left h1 { font-size:30px; font-weight:300; color:#222; margin-bottom:12px; line-height:1.2; }
@media(min-width:700px){ .hero-left h1 { font-size:38px; } }
.hero-left p { font-size:14px; color:#555; line-height:1.5; }
.hero-right { background:#fff; border:1px solid #e0e0e0; border-radius:4px; padding:20px; box-shadow:0 2px 8px rgba(0,0,0,.07); }
.hero-right ul { list-style:none; }
.hero-right ul li { font-size:13px; color:#333; margin-bottom:12px; padding-left:22px; position:relative; line-height:1.5; }
.hero-right ul li::before { content:"✓"; color:#003399; font-weight:bold; position:absolute; left:0; }
.hero-right ul li.new-item::before { color:#e30613; }
.hero-right ul li a { color:#003399; }
.badge-open { display:inline-block; background:#e30613; color:#fff; font-size:10px; font-weight:bold; padding:2px 6px; border-radius:3px; margin-left:6px; vertical-align:middle; }
/* SECTION TABS */
.section-tabs { display:flex; overflow-x:auto; gap:16px; padding:16px 16px 0; border-top:1px solid #e0e0e0; }
.section-tabs::-webkit-scrollbar { display:none; }
.section-tab { font-size:11px; font-weight:bold; color:#003399; text-transform:uppercase; cursor:pointer; padding-bottom:8px; white-space:nowrap; letter-spacing:.5px; }
/* HERO IMG */
.hero-img { width:100%; height:160px; background:linear-gradient(135deg,#1a1a2e,#0f3460); display:flex; align-items:center; justify-content:center; overflow:hidden; }
@media(min-width:700px){ .hero-img { height:240px; } }
.hero-img-text { color:rgba(255,255,255,.2); font-family:monospace; font-size:10px; line-height:2; text-align:left; }
@media(min-width:700px){ .hero-img-text { font-size:12px; } }
/* LICENSE BANNER */
.license-banner { background:#f0f4ff; border-left:4px solid #003399; padding:14px 16px; margin:16px; border-radius:0 6px 6px 0; font-size:13px; line-height:1.6; }
.license-banner a { color:#003399; font-weight:bold; }
.license-banner code { background:#dde8ff; padding:1px 4px; border-radius:3px; font-size:11px; word-break:break-all; }
/* API SECTION */
.api-section { padding:24px 16px; }
@media(min-width:700px){ .api-section { padding:40px 24px; max-width:1100px; margin:0 auto; } }
.api-section h2 { font-size:22px; font-weight:300; color:#222; margin-bottom:6px; }
.api-section .subtitle { font-size:13px; color:#666; margin-bottom:24px; line-height:1.5; }
.endpoints { display:flex; flex-direction:column; gap:12px; }
.endpoint-card { border:1px solid #e0e0e0; border-radius:6px; overflow:hidden; }
.endpoint-header { display:flex; align-items:center; gap:10px; padding:12px 14px; background:#f8f8f8; cursor:pointer; flex-wrap:wrap; }
.method { font-size:10px; font-weight:bold; padding:3px 7px; border-radius:3px; font-family:monospace; flex-shrink:0; }
.method.get { background:#e8f5e9; color:#2e7d32; }
.method.post { background:#e3f2fd; color:#1565c0; }
.endpoint-path { font-family:monospace; font-size:12px; color:#333; font-weight:bold; }
.endpoint-desc { font-size:12px; color:#666; }
.chevron { margin-left:auto; color:#999; flex-shrink:0; }
.endpoint-body { padding:16px; background:#fff; border-top:1px solid #eee; display:none; }
.endpoint-body.open { display:block; }
.endpoint-body p { font-size:13px; color:#444; margin-bottom:12px; line-height:1.6; }
.param-table { width:100%; border-collapse:collapse; font-size:11px; margin-top:8px; overflow-x:auto; display:block; }
.param-table th { text-align:left; background:#f0f0f0; padding:6px 8px; font-weight:bold; white-space:nowrap; }
.param-table td { padding:6px 8px; border-top:1px solid #eee; vertical-align:top; }
.param-table td code { background:#f5f5f5; padding:1px 4px; border-radius:3px; }
.resp-example { background:#1e1e1e; color:#d4d4d4; border-radius:4px; padding:12px; font-family:monospace; font-size:10px; line-height:1.8; margin-top:10px; overflow-x:auto; white-space:pre; }
.key { color:#9cdcfe; }
.str { color:#ce9178; }
.num { color:#b5cea8; }
/* MEME OVERLAY */
#meme-overlay {
display:none; position:fixed; inset:0; background:rgba(0,0,0,.88);
z-index:9999; align-items:center; justify-content:center;
padding:16px;
}
#meme-overlay.show { display:flex; }
.meme-box {
background:#fff; border-radius:16px; padding:28px 24px;
max-width:480px; width:100%; text-align:center;
animation:popIn .4s cubic-bezier(.34,1.56,.64,1);
}
@keyframes popIn { from{transform:scale(.5);opacity:0} to{transform:scale(1);opacity:1} }
.meme-emoji { font-size:72px; display:block; margin-bottom:10px; }
.meme-box h2 { font-size:26px; color:#e30613; margin-bottom:10px; }
.meme-box p { font-size:14px; color:#444; line-height:1.7; margin-bottom:16px; }
.meme-caption { font-size:12px; color:#999; font-style:italic; }
.meme-btn { background:#003399; color:#fff; border:none; padding:12px 28px; border-radius:8px; font-size:15px; cursor:pointer; margin-top:16px; width:100%; }
footer { background:#003399; color:#fff; text-align:center; padding:20px 16px; font-size:11px; margin-top:32px; line-height:1.8; }
</style>
</head>
<body>
<div class="topbar">
<div class="topbar-left">
<span>PRIVATI</span>
<span class="active">BUSINESS ▾</span>
<span>PREMIUM</span>
<span>POSTE ITALIANE</span>
<span>TGPOSTE</span>
</div>
<div>
<a href="#">❓ ASSISTENZA</a>
<a href="#">👤 AREA PERSONALE</a>
</div>
</div>
<nav class="navbar">
<div class="logo">Poste<em style="font-style:normal;color:#555">italiane</em></div>
<span class="nav-item">SERVIZI FINANZIARI</span>
<span class="nav-item">CORRIERE ESPRESSO E PACCHI</span>
<span class="nav-item">SERVIZI POSTALI</span>
<span class="nav-item">SERVIZI ASSICURATIVI</span>
<span class="nav-item">SOLUZIONI DIGITALI</span>
<span class="nav-item">SERVIZI ONLINE</span>
<div class="nav-right">🔍</div>
</nav>
<div class="subtabs">
<div class="subtab active">CAP Professional</div>
<div class="subtab">CAP Street File</div>
<div class="subtab">CAP Zone</div>
<div class="subtab">CAP Delivery Points</div>
<div class="subtab">Points of Interest</div>
<div class="subtab" style="color:#e30613;font-weight:bold;">CAP Open API ✨</div>
</div>
<div class="hero">
<div class="hero-left">
<h1>CAP Professional <span class="badge-open">OPEN</span></h1>
<p>Dove trovare i CAP di tutti i comuni e località italiani — ora anche via API aperta, machine to machine, con dati in licenza libera.</p>
</div>
<div class="hero-right">
<ul>
<li>I CAP di tutte le località italiane ed i dati toponomastici delle strade delle 41 città divise in più zone CAP</li>
<li>Contiene oltre 90.000 strade</li>
<li>Contiene le denominazioni, standard e abbreviate, di comuni, frazioni e strade</li>
<li class="new-item">Accesso via <a href="#api-start" id="api-link"><strong>API REST</strong></a>, machine to machine, senza registrazione</li>
<li class="new-item">Dati in licenza <a href="https://creativecommons.org/licenses/by/4.0/deed.it" target="_blank"><strong>CC BY 4.0</strong></a> — riutilizzabili con attribuzione</li>
<li class="new-item">Aggiornamento mensile, formato JSON e CSV</li>
</ul>
</div>
</div>
<div class="section-tabs">
<span class="section-tab">DESCRIZIONE</span>
<span class="section-tab">SCOPRI DI PIÙ</span>
<span class="section-tab">LINK UTILI</span>
<span class="section-tab">ALTRI PRODOTTI</span>
<span class="section-tab" style="color:#e30613;">▶ ENDPOINT API</span>
</div>
<div class="hero-img">
<div class="hero-img-text">GET /api/cap/lookup?q=Palermo → 200 OK&#10;GET /api/cap/street?city=Roma → 200 OK&#10;GET /api/cap/comuni?regione=sicilia → 200 OK&#10;POST /api/cap/batch → 200 OK&#10;GET /api/cap/frazioni?comune=Milano → 200 OK</div>
</div>
<div class="license-banner" id="api-start">
📄 Dati rilasciati sotto <a href="https://creativecommons.org/licenses/by/4.0/deed.it" target="_blank">CC BY 4.0</a>. Obbligo di citare "Poste Italiane S.p.A." come fonte.<br>
Base URL: <code>https://api.cap.poste.it/v1</code>
</div>
<div class="api-section">
<h2>Endpoint disponibili</h2>
<p class="subtitle">Tocca un endpoint per vedere dettagli, parametri ed esempio di risposta.</p>
<div class="endpoints">
<div class="endpoint-card">
<div class="endpoint-header" onclick="toggle(this)">
<span class="method get">GET</span>
<span class="endpoint-path">/cap/lookup</span>
<span class="endpoint-desc">Ricerca CAP per comune</span>
<span class="chevron">▼</span>
</div>
<div class="endpoint-body">
<p>Restituisce i CAP associati a un comune o frazione. Supporta ricerca fuzzy sul nome.</p>
<table class="param-table"><tr><th>Param</th><th>Tipo</th><th>Req</th><th>Descrizione</th></tr>
<tr><td><code>q</code></td><td>string</td><td>✅</td><td>Nome comune o località</td></tr>
<tr><td><code>regione</code></td><td>string</td><td>❌</td><td>Filtra per regione</td></tr>
<tr><td><code>limit</code></td><td>int</td><td>❌</td><td>Max risultati (default 10)</td></tr>
</table>
<div class="resp-example"><span class="key">"results"</span>: [
{ <span class="key">"cap"</span>: <span class="str">"90121"</span>, <span class="key">"comune"</span>: <span class="str">"Palermo"</span>, <span class="key">"zona"</span>: <span class="str">"Centro"</span> },
{ <span class="key">"cap"</span>: <span class="str">"90128"</span>, <span class="key">"comune"</span>: <span class="str">"Palermo"</span>, <span class="key">"zona"</span>: <span class="str">"Uditore"</span> }
]</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header" onclick="toggle(this)">
<span class="method get">GET</span>
<span class="endpoint-path">/cap/street</span>
<span class="endpoint-desc">Toponomastica per via e città</span>
<span class="chevron">▼</span>
</div>
<div class="endpoint-body">
<p>Denominazione standard, abbreviata, CAP di zona e municipio per una strada specifica.</p>
<table class="param-table"><tr><th>Param</th><th>Tipo</th><th>Req</th><th>Descrizione</th></tr>
<tr><td><code>city</code></td><td>string</td><td>✅</td><td>Nome del comune</td></tr>
<tr><td><code>name</code></td><td>string</td><td>✅</td><td>Nome strada (anche parziale)</td></tr>
</table>
<div class="resp-example">{ <span class="key">"via_standard"</span>: <span class="str">"Via Nazionale"</span>,
<span class="key">"via_abbreviata"</span>: <span class="str">"V. Nazionale"</span>,
<span class="key">"cap"</span>: <span class="str">"00184"</span>, <span class="key">"municipio"</span>: <span class="str">"I"</span> }</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header" onclick="toggle(this)">
<span class="method get">GET</span>
<span class="endpoint-path">/cap/comuni</span>
<span class="endpoint-desc">Elenco comuni con CAP</span>
<span class="chevron">▼</span>
</div>
<div class="endpoint-body">
<p>Tutti i comuni italiani con CAP principale. Filtrabile per regione o provincia, esportabile in CSV.</p>
<table class="param-table"><tr><th>Param</th><th>Tipo</th><th>Req</th><th>Descrizione</th></tr>
<tr><td><code>regione</code></td><td>string</td><td>❌</td><td>Nome regione</td></tr>
<tr><td><code>provincia</code></td><td>string</td><td>❌</td><td>Sigla (es. <code>PA</code>)</td></tr>
<tr><td><code>format</code></td><td>string</td><td>❌</td><td><code>json</code> o <code>csv</code></td></tr>
</table>
<div class="resp-example">[
{ <span class="key">"istat"</span>: <span class="str">"082053"</span>, <span class="key">"comune"</span>: <span class="str">"Palermo"</span>, <span class="key">"cap"</span>: <span class="str">"90121"</span> },
{ <span class="key">"istat"</span>: <span class="str">"082067"</span>, <span class="key">"comune"</span>: <span class="str">"Termini Imerese"</span>, <span class="key">"cap"</span>: <span class="str">"90018"</span> }
]</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header" onclick="toggle(this)">
<span class="method post">POST</span>
<span class="endpoint-path">/cap/batch</span>
<span class="endpoint-desc">Risoluzione massiva indirizzi</span>
<span class="chevron">▼</span>
</div>
<div class="endpoint-body">
<p>Fino a 500 indirizzi in una chiamata. Ideale per normalizzazione di database CRM o mailing list.</p>
<table class="param-table"><tr><th>Campo</th><th>Tipo</th><th>Descrizione</th></tr>
<tr><td><code>addresses</code></td><td>array</td><td>Lista di <code>{ via, comune }</code></td></tr>
</table>
<div class="resp-example">{ <span class="key">"results"</span>: [
{ <span class="key">"input"</span>: <span class="str">"Via Roma 1, Milano"</span>,
<span class="key">"cap"</span>: <span class="str">"20122"</span>, <span class="key">"confidence"</span>: <span class="num">0.97</span> }
]}</div>
</div>
</div>
<div class="endpoint-card">
<div class="endpoint-header" onclick="toggle(this)">
<span class="method get">GET</span>
<span class="endpoint-path">/cap/frazioni</span>
<span class="endpoint-desc">Frazioni e località di un comune</span>
<span class="chevron">▼</span>
</div>
<div class="endpoint-body">
<p>Frazioni e località abitate con CAP e denominazioni abbreviate standardizzate.</p>
<table class="param-table"><tr><th>Param</th><th>Tipo</th><th>Req</th><th>Descrizione</th></tr>
<tr><td><code>comune</code></td><td>string</td><td>✅</td><td>Nome del comune</td></tr>
</table>
<div class="resp-example">[
{ <span class="key">"localita"</span>: <span class="str">"Sesto San Giovanni"</span>, <span class="key">"abbrev"</span>: <span class="str">"Sesto S.G."</span>, <span class="key">"cap"</span>: <span class="str">"20099"</span> }
]</div>
</div>
</div>
</div>
</div>
<!-- MEME OVERLAY -->
<div id="meme-overlay">
<div class="meme-box">
<span class="meme-emoji">🤡</span>
<h2>PESCE D'APRILE!</h2>
<p>Caro sviluppatore,<br>
questa API <strong>non esiste</strong>.<br>
I CAP di Poste Italiane sono ancora <em>blindati</em>, a pagamento, e con licenza proprietaria.<br><br>
<strong>La vera notizia è che dovrebbero essere aperti. 📢</strong></p>
<p class="meme-caption">"Ma la CC BY 4.0 era così bella…" — tutti gli sviluppatori italiani, ogni anno</p>
<button class="meme-btn" onclick="document.getElementById('meme-overlay').classList.remove('show')">😭 Lo so, lo so</button>
</div>
</div>
<footer>
© 2026 Poste Italiane S.p.A. – Sede Legale: Piazza Matteotti, 3 – 00144 Roma<br>
<span style="opacity:.5">Pagina dimostrativa. I dati CAP reali di Poste Italiane NON sono open data.</span>
</footer>
<script>
// Smooth scroll per il link API REST
document.getElementById('api-link').addEventListener('click', function(e){
e.preventDefault();
document.getElementById('api-start').scrollIntoView({behavior:'smooth'});
});
function toggle(header) {
const body = header.nextElementSibling;
body.classList.toggle('open');
header.querySelector('.chevron').textContent = body.classList.contains('open') ? '▲' : '▼';
}
// Trigger meme: scatta solo quando l'ultima endpoint card entra nel viewport
let memeShown = false;
const cards = document.querySelectorAll('.endpoint-card');
const lastCard = cards[cards.length - 1];
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !memeShown) {
memeShown = true; // blocca subito per evitare doppi trigger
setTimeout(() => {
document.getElementById('meme-overlay').classList.add('show');
}, 2000);
}
});
}, { threshold: 0.5 });
observer.observe(lastCard);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment