API B3 com TypeScript e JavaScript: Integração Completa 2025

Guia completo de integração da API brapi.dev com TypeScript e JavaScript. Exemplos práticos com fetch, Axios, Next.js e Node.js para buscar cotações da B3.

Categoria:Tutoriais e Integrações • Desenvolvimento Web
10 min
Atualizado em:
Expertise: Desenvolvimento web com TypeScript e Next.js - 8+ anos
Tags:
TypeScriptJavaScriptAPINext.jsNode.jsDesenvolvimento

Neste artigo

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.

Publicado em 12 de Outubro de 2025

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

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!

Artigos Relacionados