← Back to blog
APIs .NET C# Backend Polly Integration

Free Public APIs Every Backend Developer Should Know

· 12 min read

Integrating external APIs is routine work in backend development. The challenge is finding out which ones exist, what they actually offer for free, and how to integrate them reliably. This article is a commented catalog — with real limitations and production tips.


🇧🇷 Addresses and Locations

ViaCEP

URL: https://viacep.com.br/ws/{cep}/json/
Auth: None
Limit: Undocumented
Countries: 🇧🇷 Brazil

Returns street, neighborhood, city and state from a Brazilian postal code. Also supports reverse lookup by street name + municipality + state.

Strengths: zero configuration, consistent response, widely adopted.
Limitations: no public SLA and no declared rate limit — aggressive caching is mandatory.

BrasilAPI

URL: https://brasilapi.com.br/api/
Auth: None
Limit: Undocumented
Countries: 🇧🇷 Brazil

A hub of Brazilian public data. One dependency, many useful endpoints:

  • GET /cep/v2/{cep} — postal code via multiple sources, more robust than ViaCEP
  • GET /banks/v1 — bank list with ISPB and COMPE codes
  • GET /cnpj/v1/{cnpj} — full company registration data
  • GET /ddd/v1/{ddd} — state and cities by area code
  • GET /feriados/v1/{year} — national holidays by year
  • GET /taxas/v1 — SELIC, CDI, savings rate and other financial indices
  • GET /ibge/municipios/v1/{uf} — municipalities by state

Strengths: unified API for official government data, open source, well maintained by the community.
Limitations: uptime depends on third-party sources — a circuit breaker is mandatory in production.

IBGE — Localities

URL: https://servicodados.ibge.gov.br/api/v1/localidades/
Auth: None
Limit: Undocumented
Countries: 🇧🇷 Brazil

Official geographic data: states, municipalities, mesoregions, microregions and districts. Ideal for validating addresses, populating dropdowns or generating regional reports.

Most used endpoints: /estados, /estados/{uf}/municipios, /municipios/{ibgeCode}.


💰 Financial Data

AwesomeAPI — Exchange Rates

URL: https://economia.awesomeapi.com.br/last/{pairs}
Auth: None
Limit: Undocumented
Countries: 🌍 Global

Real-time exchange rates for currencies (USD-BRL, EUR-BRL, GBP-BRL), cryptocurrencies (BTC-BRL, ETH-BRL) and Brazilian stocks (PETR4, VALE3). Offers history via /daily/{pair}/{days}.

Strengths: zero configuration, covers hundreds of pairs, updates every few minutes.
Limitations: no declared SLA — do not use as a sole source in critical payment systems. A 5–10 min cache is the minimum.

BrasilAPI — Rates and Indices

URL: https://brasilapi.com.br/api/taxas/v1
Auth: None
Limit: Undocumented
Countries: 🇧🇷 Brazil

Returns SELIC, CDI, CDB, savings rate and other financial indicators. Useful for investment simulators, monetary correction calculations and financial dashboards.

BACEN — PTAX

URL: https://olinda.bcb.gov.br/olinda/servico/PTAX/versao/v1/odata/
Auth: None
Limit: Undocumented
Countries: 🇧🇷 Brazil

Official exchange rates from the Brazilian Central Bank. PTAX is the reference rate used in financial contracts, settlements and monetary adjustments — more authoritative than commercial sources for legal or contractual purposes.

Most used endpoints:

  • GET /CotacaoDolarDia(dataCotacao=@d)?@d='MM-DD-YYYY' — USD rate for a given day (buy and sell)
  • GET /CotacaoMoedaDia(moeda=@m,dataCotacao=@d)?@m='EUR'&@d='MM-DD-YYYY' — other currencies

Strengths: official government source, free, no authentication required.
Limitations: data is only available on Brazilian banking business days; the API uses OData, which can be verbose for simple use cases.


₿ Cryptocurrencies

CoinGecko

URL: https://api.coingecko.com/api/v3/
Auth: None (demo) / Free API key
Limit: 30 req/min
Countries: 🌍 Global

The largest free cryptocurrency market data API: real-time prices, OHLCV history, market cap, volume and metadata for 10,000+ tokens. Does not cover on-chain data (wallet balances, transactions or block exploration) — use Etherscan or Blockchain.com for that.

Most used endpoints:

  • GET /simple/price?ids=bitcoin,ethereum&vs_currencies=usd,brl — current price for multiple tokens
  • GET /coins/{id}/market_chart?vs_currency=usd&days=30 — price history
  • GET /coins/markets?vs_currency=usd&order=market_cap_desc — ranking by market cap

Strengths: comprehensive market coverage, no registration required for basic use, excellent documentation.
Limitations: 30 req/min without an API key — caching is mandatory. For higher production volumes, consider the paid plan.

Etherscan

URL: https://api.etherscan.io/v2/api?chainid=1
Auth: Free API key
Limit: 5 req/sec / 100,000 req/day
Countries: 🌍 Global (Multi-chain EVM)

The largest Ethereum network explorer. Query wallet balances, transaction history, ERC-20/ERC-721 token transfers, verified contracts and block data — all via REST API. The chainid parameter lets you use the same API key across multiple networks: Ethereum (1), Polygon (137), BNB Chain (56) and dozens of other compatible EVM networks.

Most used endpoints:

  • GET ?chainid=1&module=account&action=balance&address={address} — ETH balance of a wallet
  • GET ?chainid=1&module=account&action=tokentx&address={address} — ERC-20 token transfers
  • GET ?chainid=1&module=block&action=getblocknobytime&timestamp={ts} — block closest to a timestamp

Strengths: extensive documentation, real-time on-chain data, free for basic use, a single API key covers multiple EVM networks.
Limitations: requires registration to obtain an API key; free plan limits may be insufficient for batch queries.

Blockchain.com — Simple API

URL: https://blockchain.info/
Auth: None
Limit: Undocumented
Countries: 🌍 Global (Bitcoin)

Public API for Bitcoin on-chain data. No API key, no registration — direct access to wallet balances and transaction history.

Most used endpoints:

  • GET /balance?active={address} — BTC balance of one or more wallets
  • GET /rawaddr/{address} — full transaction history for an address
  • GET /latestblock — most recent confirmed block

Strengths: zero configuration, Bitcoin data with no external provider dependency.
Limitations: Bitcoin only; no documented limit but susceptible to throttling at high volumes — caching is mandatory.


🏢 CNPJ and Companies

BrasilAPI — CNPJ

URL: https://brasilapi.com.br/api/cnpj/v1/{cnpj}
Auth: None
Limit: Undocumented
Countries: 🇧🇷 Brazil

Full company data from the Brazilian Revenue Service (Receita Federal): company name, trade name, CNAE codes, registration status, size, address and partner list.

Strengths: official data without requiring a digital certificate or special agreement.
Limitations: data reflects the last sync with Receita Federal — there may be a few hours lag.


🌤 Weather

Open-Meteo

URL: https://api.open-meteo.com/v1/forecast
Auth: None
Limit: 10,000 req/day
Countries: 🌍 Global

Open-source weather forecasts powered by multiple climate models (ECMWF, GFS, DWD). Covers hourly and daily forecasts as well as historical data back to 1940.

Strengths: no auth required, global coverage, excellent documentation, 80+ years of historical data.
Limitations: 10k req/day — a minimum 15-minute cache is mandatory.


🌐 IP Geolocation

ipapi.co

URL: https://ipapi.co/{ip}/json/
Auth: None
Limit: 1,000 req/day
Countries: 🌍 Global

Returns city, country, region, timezone, lat/lon, organization (ASN) and local currency. Omitting {ip} automatically uses the caller’s IP — useful for detecting a user’s country without login.

Strengths: rich data (ASN, currency, timezone), free HTTPS.
Limitations: 1k req/day is low for high-traffic production — per-session or per-IP caching is essential.

ip-api.com

URL: http://ip-api.com/json/{ip}
Auth: None
Limit: 45 req/min
Countries: 🌍 Global

Warning: the free plan is HTTP only — do not use in contexts where HTTPS is required. The paid plan enables HTTPS and raises the limit.


🌍 Geocoding and Geographic Data

Nominatim — OpenStreetMap

URL: https://nominatim.openstreetmap.org/
Auth: None
Limit: 1 req/sec (hard maximum by OpenStreetMap Foundation usage policy)
Countries: 🌍 Global

Geocoding and reverse geocoding powered by OpenStreetMap data. Converts addresses to coordinates and vice versa — free and with no registration.

Most used endpoints:

  • GET /search?q={address}&format=json — address → coordinates
  • GET /reverse?lat={lat}&lon={lon}&format=json — coordinates → full address

Strengths: free, no auth, global coverage, open-source data.
Limitations: the 1 req/s limit is hard and applies to the entire application (sum of all users). Not suitable for batch geocoding — for higher volumes, consider self-hosting Photon or using Geoapify.

CountriesNow

URL: https://countriesnow.space/api/v0.1/
Auth: None
Limit: Undocumented
Countries: 🌍 Global (222 countries)

Structured data for 222 countries and territories: name, capital, ISO code, dialing code, timezone, population, currency, language and flags (SVG). Free API, no registration, actively maintained.

Most used endpoints:

  • GET /countries — full list with ISO2, ISO3 and cities (227 countries)
  • GET /countries/flag/images — list with flag URLs (SVG)
  • GET /countries/currency — list with currency and ISO code per country
  • POST /countries/capital — capital of a specific country (body: {"country":"Brazil"})

Strengths: no auth, global coverage, includes flags and demographic data, clean JSON.
Limitations: no native pagination — returns complete lists; keep a local cache (TTL 24h+) to avoid repeating the call on every request.


🔒 Security

Have I Been Pwned

URL: https://api.pwnedpasswords.com/range/{prefix}
Auth: None (passwords) / paid API key (emails)
Limit: Undocumented (returns 429 on abuse)
Countries: 🌍 Global

Checks whether a password has appeared in known data breaches using k-anonymity: you send only the first 5 characters of the SHA-1 hash. The server returns all hashes with that prefix and comparison happens locally — the full password never travels over the network.

Strengths: privacy by design, database with billions of leaked passwords, completely free for passwords.
Limitations: checking compromised email addresses requires a paid API key ($3.50/month).

VirusTotal

URL: https://www.virustotal.com/api/v3/
Auth: Free API key
Limit: 4 req/min / 500 req/day
Countries: 🌍 Global

Analyzes URLs, files, domains and IPs against 70+ antivirus engines. Useful for validating user-submitted links or scanning uploaded files before processing them.

Hudson Rock — Cavalier

URL: https://cavalier.hudsonrock.com/api/json/v2/osint-tools/
Auth: None
Limit: Undocumented
Countries: 🌍 Global

Cybercrime intelligence focused on infostealer malware. Unlike HIBP — which indexes data from breaches and public dumps — Cavalier covers credentials stolen directly from victims’ devices by malware such as RedLine, Raccoon and Vidar.

Public endpoints:

  • GET /search-by-email?email={email} — checks if an email appears in infostealer logs
  • GET /search-by-domain?domain={domain} — identifies compromised employees and systems for a domain

Strengths: covers a distinct attack vector from HIBP; no authentication required.
Limitations: large generic domains (e.g., google.com) may return 400; rate limit undocumented.


📅 Public Holidays

Nager.Date

URL: https://date.nager.at/api/v3/PublicHolidays/{year}/{country}
Auth: None
Limit: Undocumented
Countries: 🌍 100+ countries

National and regional public holidays in 100+ countries. Essential for business day calculations, SLAs and scheduling. Supports BR, US, DE, PT, ES and dozens of other ISO 3166-1 codes.


🧪 Dev and Prototyping

JSONPlaceholder

URL: https://jsonplaceholder.typicode.com/
Auth: None
Limit: No declared limit
Countries: 🌍 Global

Fully functional fake API: posts, users, todos, photos, albums, comments. Supports all HTTP verbs — PUT/PATCH/DELETE simulate without persisting. Ideal for testing HttpClient pipelines or generating sample data in demos without spinning up infrastructure.

PokeAPI

URL: https://pokeapi.co/api/v2/
Auth: None
Limit: 100 req/min
Countries: 🌍 Global

Complete Pokémon universe catalog. Has one of the best REST API documentations available — great for practicing pagination with limit/offset, caching and relationships in RESTful APIs.


⚙️ Integrating Reliably

The production pattern is always the same: typed HttpClient or Refit for the HTTP client, Polly for resilience and TTL-based cache to reduce latency and respect rate limits. Only the endpoint changes.

Typed HttpClient

IHttpClientFactory fixes two classic pitfalls of new HttpClient(): socket exhaustionHttpClient must be reused across requests, never instantiated per call — and stale DNS — without the factory, the resolved DNS stays locked in the socket indefinitely. The typed client wraps HttpClient in a domain-specific service class; you inject the class, not HttpClient directly.

When to use: projects with few external endpoints, or when you want full control over serialization and error handling without adding external dependencies.

// The HttpClient is injected already configured by IHttpClientFactory
public class ViaCepClient(HttpClient httpClient)
{
    public Task<ViaCepResponse?> GetAddressAsync(string postalCode)
    {
        // Strip non-digit characters before building the URL
        var digits = new string(postalCode.Where(char.IsDigit).ToArray());
        return httpClient.GetFromJsonAsync<ViaCepResponse>($"/ws/{digits}/json/");
    }
}

// Program.cs — registers the typed client with a centralized base URL
builder.Services.AddHttpClient<ViaCepClient>(client =>
    client.BaseAddress = new Uri("https://viacep.com.br"));

Refit

Refit generates the HTTP client implementation from an annotated interface. You describe the API contract as an interface — Refit creates the concrete class at runtime via source generators. The interface also acts as living documentation of the contract.

When to use instead of typed HttpClient: when the API has many endpoints or you want to eliminate serialization and URL-building boilerplate. Downsides: it’s an external dependency and less flexible for very custom scenarios (large response streaming, complex multipart uploads).

// dotnet add package Refit.HttpClientFactory

// The interface declares endpoints — Refit generates the implementation at runtime
public interface IViaCepApi
{
    [Get("/ws/{cep}/json/")]
    Task<ViaCepResponse> GetAddressAsync(string cep);
}

// Program.cs — Refit and Polly chain into the same HttpClient pipeline
builder.Services.AddRefitClient<IViaCepApi>()
    .ConfigureHttpClient(client =>
        client.BaseAddress = new Uri("https://viacep.com.br"));

Refit and Polly integrate in the same chain: AddRefitClient<T>().ConfigureHttpClient(...).AddResilienceHandler(...).

Cache

Cache stores external call responses locally for a set period (TTL — Time to Live), avoiding repeated requests. Beyond reducing latency, it protects against rate limits and shields your application from momentary instability in the external dependency.

IMemoryCache — stores data in the process’s own memory. Simple, no additional latency. Critical limitation: not shared between instances. In horizontally scaled environments (multiple pods/containers), each instance holds its own isolated cache — inconsistencies are inevitable and the caching benefit is partially lost.

IDistributedCache with Redis — external cache shared across all instances. Mandatory when the application scales horizontally. Adds network latency (~1ms on LAN), but guarantees consistency and allows the cache to survive pod restarts.

// Program.cs
builder.Services.AddMemoryCache();

// In the service:
public async Task<ExchangeRate?> GetRateAsync(string pair)
{
    var cacheKey = $"rate:{pair.ToUpper()}";

    // Return immediately if the value is already cached
    if (_cache.TryGetValue(cacheKey, out ExchangeRate? cached))
        return cached;

    var result = await _api.GetRateAsync(pair);

    if (result is not null)
        _cache.Set(cacheKey, result, new MemoryCacheEntryOptions
        {
            // Hard ceiling — expires regardless of access frequency
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
            // Resets the TTL on each read — only expires if unused
            SlidingExpiration = TimeSpan.FromMinutes(2),
        });

    return result;
}

Resilience with Polly

Polly is the resilience library for .NET. It implements stability patterns — retry, circuit breaker, timeout and bulkhead — that protect your application when external dependencies fail or slow down. In .NET 8+, Polly v8 is integrated directly via Microsoft.Extensions.Http.Resilience, with no need for manual pipeline setup.

Retry automatically retries transient failures (network timeouts, momentary 503s). Circuit Breaker stops trying when the dependency is clearly unavailable — it prevents a slow API from bringing down your whole application and gives the external service time to recover. Strategy order is critical: from inside out, each layer wraps the previous one.

builder.Services.AddHttpClient<ViaCepClient>(client =>
        client.BaseAddress = new Uri("https://viacep.com.br"))
    .AddResilienceHandler("viacep-pipeline", pipeline =>
    {
        // Timeout applied individually to each attempt
        pipeline.AddTimeout(TimeSpan.FromSeconds(4));

        pipeline.AddRetry(new HttpRetryStrategyOptions
        {
            // Maximum number of retries after the initial failure
            MaxRetryAttempts = 3,
            // Base delay before the first retry
            Delay = TimeSpan.FromMilliseconds(500),
            // Exponential: each retry doubles the previous delay (500ms → 1s → 2s)
            BackoffType = DelayBackoffType.Exponential,
            // Random variation on the delay to prevent simultaneous retry storms
            UseJitter = true,
            // Trigger retry on network exceptions or 5xx responses
            ShouldHandle = args => ValueTask.FromResult(
                args.Outcome.Exception is not null ||
                args.Outcome.Result?.StatusCode >= HttpStatusCode.InternalServerError),
        });

        pipeline.AddCircuitBreaker(new HttpCircuitBreakerStrategyOptions
        {
            // Time window used to calculate the failure rate
            SamplingDuration = TimeSpan.FromSeconds(30),
            // Minimum requests in the window before evaluating the circuit
            MinimumThroughput = 5,
            // Open the circuit if 50% or more of requests fail
            FailureRatio = 0.5,
            // How long the circuit stays open before attempting recovery
            BreakDuration = TimeSpan.FromSeconds(15),
        });
    });

Strategy order matters: timeout → retry → circuit breaker, from inside out.

Official References