A modern data pipeline for the Indonesian Stock Exchange (IDX). Built with Next.js 15, NeonDB, and Drizzle ORM to sync official market data into a structured PostgreSQL database. It features molecular architecture design, automated retries for network stability, and provides RESTful API endpoints for company info, indices, and trading data.
- RESTful API - Next.js App Router API endpoints for all IDX data
- Automated Sync - Scheduled data synchronization with retry logic
- Official IDX Data - Direct integration with Indonesian Stock Exchange APIs
- Structured Storage - PostgreSQL database with Drizzle ORM for type-safe queries
- Serverless Ready - Optimized for deployment on Vercel, Neon, and edge platforms
- Molecular Architecture - Modular design with separated concerns (Company, Market, Participants, Trading)
Note
Prerequisites: Node.js 18+ and npm/pnpm/yarn. You'll also need a NeonDB account for the PostgreSQL database.
Tip
Want to see the data in action? Check out IDX-UI - the interactive dashboard for your market data!
Clone Repository:
# Clone the repository
git clone https://github.com/NeaByteLab/IDX-API.git
# Enter the project directory
cd IDX-API/
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Edit .env and add your DATABASE_URL from NeonDB
# Initialize the database (Drizzle generate & push)
npm run db:generate
npm run db:pushRequirements:
- Node.js (v18.0.0 or higher recommended)
- NeonDB Account (Free tier available)
- Git (for cloning the repository)
- Framework: Next.js 15 (React Server Components, App Router)
- Database: NeonDB (Serverless PostgreSQL)
- ORM: Drizzle ORM (Type-Safe SQL ORM)
- Runtime: Node.js / Edge Runtime compatible
flowchart TD
%% Define Nodes
A[(NeonDB PostgreSQL)]:::db
B(Drizzle Schema Sync):::process
C[IDX API Endpoints]:::api
D[Next.js API Routes]:::process
E{Data Valid?}:::decision
F(Data Processing):::process
G(Drizzle Upsert):::process
H[Your Application / Frontend]:::app
%% Define Flow
B -->|Setup Tables| A
C -.->|HTTP Res| D
D -->|Raw JSON| E
E -->|No: Retry| D
E -->|Yes: Parse| F
F -->|Clean Data| G
G -->|Store| A
A -->|Query via ORM| H
D -->|REST API| H
%% Styling
classDef db fill:#e0f7fa,stroke:#006064,stroke-width:2px,color:#000000;
classDef process fill:#f5f5f5,stroke:#9e9e9e,color:#000000;
classDef api fill:#fff3e0,stroke:#e65100,stroke-dasharray: 5 5,color:#000000;
classDef decision fill:#e8f5e9,stroke:#2e7d32,color:#000000,shape:rhombus;
classDef app fill:#ede7f6,stroke:#4527a0,stroke-width:2px,color:#000000;
# Start the development server
npm run dev
# Access the API endpoints
curl http://localhost:3000/api/company/profile
curl http://localhost:3000/api/market/indices
curl http://localhost:3000/api/trading/summary?date=20240220import { db } from '@/lib/db'
import { companyProfile, stockSummary } from '@/db/schema'
import { eq } from 'drizzle-orm'
// Query company profiles
const companies = await db.select().from(companyProfile)
// Get stock summary for a specific date
const dailyData = await db
.select()
.from(stockSummary)
.where(eq(stockSummary.date, '20240220'))
// Access via molecular modules
import { CompanyModule } from '@/src/Company/module'
import { MarketModule } from '@/src/Market/module'
import { TradingModule } from '@/src/Trading/module'
const company = new CompanyModule()
const profile = await company.getProfile('BBCA')
const market = new MarketModule()
const indices = await market.getIndexList()
const trading = new TradingModule()
const summary = await trading.getStockSummary('20240220')For detailed usage examples, see USAGE.md.
The project maintains a molecular architecture with separated modules that can be accessed programmatically or via REST API endpoints.
GET /company/profile- Company metadata and profilesGET /company/announcement- Corporate news and announcementsGET /company/financial-ratio- Financial indicators (PER, PBV, ROE, DER)GET /company/financial-report- Detailed financial reportsGET /company/dividend- Dividend payment dataGET /company/stock-split- Stock split eventsGET /company/new-listing- IPO and new listingsGET /company/delisting- Delisted companies
GET /market/daily-index- Daily index performanceGET /market/index-list- Current index pricesGET /market/index-summary- Daily index snapshotsGET /market/foreign-trading- Foreign investor flowsGET /market/top-gainer- Top gaining stocksGET /market/top-loser- Top losing stocks
GET /trading/stock-summary- Daily OHLC and volume dataGET /trading/trade-summary- Market aggregate dataGET /trading/broker-summary- Broker trading activityGET /trading/daily- Real-time price snapshotsGET /trading/historical- Historical trading data
GET /participants/broker- Exchange member brokersGET /participants/dealer- Primary dealersGET /participants/profile- Participant profiles
GET /general/market-calendar- Trading holidays and eventsGET /general/security-stock- Master security list
.
├── src/ # Core modules (Molecular Architecture)
│ ├── Backend/ # Database schema, sync logic, and utilities
│ ├── Company/ # Corporate information module
│ ├── Market/ # Market and index module
│ ├── Participants/ # Broker and dealer module
│ ├── Statistics/ # Stock activity module
│ └── Trading/ # Trading summary module
├── app/ # Next.js App Router
│ ├── api/ # REST API endpoints
│ │ ├── company/ # Corporate data endpoints
│ │ ├── market/ # Market data endpoints
│ │ ├── trading/ # Trading data endpoints
│ │ └── participants/ # Participant data endpoints
│ ├── layout.tsx # Root layout
│ └── page.tsx # Home page
├── lib/ # Shared utilities
│ └── db.ts # Database connection (NeonDB + Drizzle)
├── db/ # Database layer
│ └── schema/ # Drizzle ORM schemas (PostgreSQL)
├── public/ # Static assets
├── tests/ # Unit test suites
├── sample/ # Documentation generator
└── .env.example # Environment variables template
This project is licensed under the MIT license. See the LICENSE file for more info.