Como Integrar a API da B3 com TypeScript e JavaScript
Aprenda a buscar cotações de ações, ETFs e outros ativos da B3 usando TypeScript e JavaScript em aplicações modernas.
Por Que Integrar Dados da B3 em Sua Aplicação?
Aplicações financeiras, dashboards de investimentos e plataformas de análise precisam de dados confiáveis e atualizados do mercado brasileiro. A API da brapi.dev oferece acesso simples e direto a:
- Cotações em tempo real (plano pago) ou com delay de 15 min (gratuito)
- Dados de ações, ETFs, FIIs, BDRs e criptomoedas
- Informações fundamentalistas
- Histórico de preços
- Dividendos e proventos
Começando: Fetch Nativo (Browser e Node.js 18+)
O fetch é nativo em navegadores modernos e Node.js 18+, sem necessidade de bibliotecas extras.
Exemplo Básico
const fetchQuote = async (ticker: string) => {
const token = process.env.BRAPI_TOKEN;
const response = await fetch(
`https://brapi.dev/api/quote/${ticker}?token=${token}`
);
const data = await response.json();
return data;
};
// Uso
fetchQuote('PETR4').then(data => {
console.log(data.results[0]);
});
Com TypeScript e Tratamento de Erros
interface Quote {
symbol: string;
shortName: string;
regularMarketPrice: number;
regularMarketChange: number;
regularMarketChangePercent: number;
currency: string;
}
interface QuoteResponse {
results: Quote[];
requestedAt: string;
took: string;
}
async function getQuote(ticker: string): Promise<Quote | null> {
const token = process.env.BRAPI_TOKEN;
try {
const response = await fetch(
`https://brapi.dev/api/quote/${ticker}?token=${token}`
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data: QuoteResponse = await response.json();
return data.results[0] || null;
} catch (error) {
console.error('Erro ao buscar cotação:', error);
return null;
}
}
// Uso com tipos
const quote = await getQuote('PETR4');
if (quote) {
console.log(`${quote.symbol}: R$ ${quote.regularMarketPrice.toFixed(2)}`);
console.log(`Variação: ${quote.regularMarketChangePercent.toFixed(2)}%`);
}
Buscando Múltiplos Tickers
async function getMultipleQuotes(tickers: string[]): Promise<Quote[]> {
const token = process.env.BRAPI_TOKEN;
const tickersParam = tickers.join(',');
const response = await fetch(
`https://brapi.dev/api/quote/${tickersParam}?token=${token}`
);
const data: QuoteResponse = await response.json();
return data.results;
}
// Uso
const quotes = await getMultipleQuotes(['PETR4', 'VALE3', 'ITUB4']);
quotes.forEach(quote => {
console.log(`${quote.symbol}: R$ ${quote.regularMarketPrice}`);
});
Usando Axios para Mais Recursos
Axios oferece sintaxe mais simples, interceptors e melhor tratamento de erros.
Instalação
npm install axios
# ou
yarn add axios
# ou
bun add axios
Cliente Básico com Axios
import axios from 'axios';
const brapiClient = axios.create({
baseURL: 'https://brapi.dev/api',
params: {
token: process.env.BRAPI_TOKEN
}
});
// Buscar cotação
const { data } = await brapiClient.get(`/quote/PETR4`);
console.log(data.results[0]);
Classe Cliente Profissional
import axios, { AxiosInstance, AxiosError } from 'axios';
class BrapiClient {
private client: AxiosInstance;
constructor(token: string) {
this.client = axios.create({
baseURL: 'https://brapi.dev/api',
timeout: 10000,
params: { token }
});
}
async getQuote(ticker: string): Promise<Quote> {
try {
const { data } = await this.client.get<QuoteResponse>(`/quote/${ticker}`);
return data.results[0];
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(`API Error: ${error.response?.status} - ${error.message}`);
}
throw error;
}
}
async getMultipleQuotes(tickers: string[]): Promise<Quote[]> {
const tickersParam = tickers.join(',');
const { data } = await this.client.get<QuoteResponse>(`/quote/${tickersParam}`);
return data.results;
}
}
// Uso
const brapi = new BrapiClient(process.env.BRAPI_TOKEN!);
const quote = await brapi.getQuote('PETR4');
Integração com Next.js
Server Component (Recomendado)
// app/stock/[ticker]/page.tsx
interface PageProps {
params: { ticker: string };
}
async function getQuote(ticker: string) {
const token = process.env.BRAPI_TOKEN;
const res = await fetch(
`https://brapi.dev/api/quote/${ticker}?token=${token}`,
{ next: { revalidate: 60 } } // Cache por 60 segundos
);
if (!res.ok) throw new Error('Failed to fetch');
return res.json();
}
export default async function StockPage({ params }: PageProps) {
const data = await getQuote(params.ticker);
const quote = data.results[0];
return (
<div className="p-6">
<h1 className="text-2xl font-bold">{quote.shortName}</h1>
<p className="text-3xl font-bold mt-2">
R$ {quote.regularMarketPrice.toFixed(2)}
</p>
<p className={quote.regularMarketChangePercent > 0 ? 'text-green-600' : 'text-red-600'}>
{quote.regularMarketChangePercent.toFixed(2)}%
</p>
</div>
);
}
API Route
// app/api/quote/[ticker]/route.ts
import { NextResponse } from 'next/server';
export async function GET(
request: Request,
{ params }: { params: { ticker: string } }
) {
const token = process.env.BRAPI_TOKEN;
try {
const response = await fetch(
`https://brapi.dev/api/quote/${params.ticker}?token=${token}`
);
if (!response.ok) {
return NextResponse.json(
{ error: 'Failed to fetch quote' },
{ status: response.status }
);
}
const data = await response.json();
return NextResponse.json(data);
} catch (error) {
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
Client Component com SWR
'use client';
import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then(r => r.json());
export function StockQuote({ ticker }: { ticker: string }) {
const { data, error, isLoading } = useSWR(
`/api/quote/${ticker}`,
fetcher,
{ refreshInterval: 60000 } // Atualiza a cada 60s
);
if (error) return <div>Erro ao carregar</div>;
if (isLoading) return <div>Carregando...</div>;
const quote = data.results[0];
return (
<div className="p-4 border rounded">
<h3 className="font-bold">{quote.symbol}</h3>
<p className="text-2xl">R$ {quote.regularMarketPrice.toFixed(2)}</p>
</div>
);
}
Node.js com Cache
class BrapiService {
private cache = new Map<string, { data: Quote; timestamp: number }>();
private cacheDuration = 60000; // 60 segundos
constructor(private token: string) {}
async getQuote(ticker: string): Promise<Quote> {
const cached = this.cache.get(ticker);
const now = Date.now();
// Retorna do cache se ainda válido
if (cached && now - cached.timestamp < this.cacheDuration) {
return cached.data;
}
// Busca novo dado
const response = await fetch(
`https://brapi.dev/api/quote/${ticker}?token=${this.token}`
);
const data = await response.json();
const quote = data.results[0];
// Atualiza cache
this.cache.set(ticker, {
data: quote,
timestamp: now
});
return quote;
}
}
// Uso
const service = new BrapiService(process.env.BRAPI_TOKEN!);
const quote = await service.getQuote('PETR4');
Boas Práticas
1. Armazene o Token em Variáveis de Ambiente
# .env.local
BRAPI_TOKEN=seu_token_aqui
// Nunca faça isso
const token = 'meu_token_secreto'; // ❌ Inseguro!
// Faça isso
const token = process.env.BRAPI_TOKEN; // ✅ Seguro
2. Implemente Cache
// Next.js App Router
fetch(url, { next: { revalidate: 60 } })
// Next.js Pages Router
export async function getStaticProps() {
return {
props: { data },
revalidate: 60 // Revalida a cada 60s
}
}
3. Trate Erros Adequadamente
try {
const quote = await getQuote('PETR4');
} catch (error) {
if (error instanceof Error) {
console.error('Erro:', error.message);
}
}
4. Use TypeScript para Segurança de Tipos
// Define interfaces para os dados
interface Quote {
symbol: string;
regularMarketPrice: number;
// ... outros campos
}
// TypeScript vai alertar sobre erros
const price: number = quote.regularMarketPrice; // ✅
const invalid: string = quote.regularMarketPrice; // ❌ Erro de tipo
Exemplo Completo: Dashboard de Ações
// components/StockDashboard.tsx
'use client';
import { useEffect, useState } from 'react';
interface Quote {
symbol: string;
shortName: string;
regularMarketPrice: number;
regularMarketChangePercent: number;
}
export function StockDashboard() {
const [quotes, setQuotes] = useState<Quote[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function loadQuotes() {
const tickers = ['PETR4', 'VALE3', 'ITUB4', 'BBDC4'];
const response = await fetch(`/api/quotes?tickers=${tickers.join(',')}`);
const data = await response.json();
setQuotes(data.results);
setLoading(false);
}
loadQuotes();
const interval = setInterval(loadQuotes, 60000); // Atualiza a cada minuto
return () => clearInterval(interval);
}, []);
if (loading) return <div>Carregando...</div>;
return (
<div className="grid grid-cols-2 gap-4">
{quotes.map(quote => (
<div key={quote.symbol} className="p-4 border rounded">
<h3 className="font-bold">{quote.symbol}</h3>
<p className="text-sm text-gray-600">{quote.shortName}</p>
<p className="text-2xl font-bold mt-2">
R$ {quote.regularMarketPrice.toFixed(2)}
</p>
<p className={quote.regularMarketChangePercent > 0 ? 'text-green-600' : 'text-red-600'}>
{quote.regularMarketChangePercent > 0 ? '+' : ''}
{quote.regularMarketChangePercent.toFixed(2)}%
</p>
</div>
))}
</div>
);
}
Próximos Passos
- Veja exemplos em Python
- Integre com Google Sheets
- Explore a documentação completa
- Acesse seu dashboard
Conclusão
A integração da API da brapi.dev com TypeScript e JavaScript é simples e poderosa. Com apenas algumas linhas de código, você tem acesso a dados completos do mercado brasileiro para criar aplicações financeiras profissionais.
Comece agora: Copie os exemplos acima e adapte para seu projeto!