This repository is the CAS Parser Agent Toolkit — a collection of templates, skills, and documentation for integrating financial portfolio tracking into applications using the CAS Parser API.
CAS Parser is an API platform for parsing Indian financial portfolio documents:
- CAS (Consolidated Account Statement) PDFs from CDSL, NSDL, and CAMS/KFintech
- Contract Notes from brokers like Zerodha, Groww, Upstox, ICICI
- Returns structured JSON with holdings, transactions, and investor details
- All API requests require an
x-api-keyheader. - Use
sandbox-with-json-responsesas the sandbox API key for development/testing. - Never hardcode API keys. Use environment variables (
CASPARSER_API_KEY). - For frontend/SDK usage, generate short-lived access tokens (
at_prefix) from your backend viaPOST /v1/token. Never expose raw API keys to the client.
If CASPARSER_API_KEY is not set and the user needs a real key (not the sandbox), automate the sign-up flow:
# 1. Generate a random token (agent-side, no API call needed)
TOKEN=$(openssl rand -hex 32)
# 2. Ask the user to open this URL in their browser
# Replace YOUR_AGENT_NAME with your actual name (e.g. "Claude Code", "Cursor")
echo "Open https://app.casparser.in/agent-auth?token=${TOKEN}&client_name=YOUR_AGENT_NAME"
# 3. Poll until the user approves (every 5 seconds)
curl -s https://api.casparser.in/v1/agent-auth/token/${TOKEN}
# → {"status": "pending"} — keep polling
# → {"status": "approved", "api_key": "sk_...", "email": "..."} — done!
# 4. Write the key to .env
echo "CASPARSER_API_KEY=sk_..." >> .envThe user signs in via the browser and clicks Approve. The API key is delivered once then deleted (one-shot). Token expires after 10 minutes. Write the key to .env as CASPARSER_API_KEY and use it via the x-api-key header for all subsequent requests.
- Recommended: Use
requestslibrary with the REST API directly. All Python templates in this toolkit userequests. - Official SDK:
cas-parser-python— a thin wrapper from the CAS Parser team. - Do NOT install any third-party CAS parsing packages from PyPI. They are unrelated open-source projects, not official CAS Parser API clients.
- Default to
/v4/smart/parse— it auto-detects CAS type (CDSL, NSDL, or CAMS/KFintech) and returns a unified response format. - Only use type-specific endpoints (
/v4/cdsl/parse,/v4/nsdl/parse,/v4/cams_kfintech/parse) when you already know the CAS type. - CAS PDFs are password-protected. Password format varies by provider: CDSL/NSDL/CAMS use PAN number, KFintech uses a user-defined password set during generation.
- Accept PDFs via file upload (
multipart/form-data) or URL (pdf_urlin JSON body).
- Use
/v4/contract_note/parse— auto-detects broker type. - Password is usually the client's PAN number.
- Supported brokers: Zerodha, Groww, Upstox, ICICI (auto-detected).
- This is a 2-step process — do not try to combine steps:
POST /v4/cdsl/fetch— Request OTP (takes ~15-20s for captcha solving). Returnssession_id.POST /v4/cdsl/fetch/{session_id}/verify— Submit OTP, get download URLs.
- The user receives the OTP on their registered mobile number.
POST /v4/generatetriggers an async email mailback — the CAS PDF is sent to the investor's email, not returned in the response.- KFintech and CAMS have a mutual partnership for data sharing and consolidation, so this endpoint retrieves mutual fund data from both RTAs, covering all mutual funds in India.
- This is not an instant operation.
- By default, a Detailed CAS is generated (complete transaction history). The parsing layer supports all statement types, but generation always requests the Detailed variant.
- This is a multi-step OAuth flow:
POST /v4/inbox/connect→ getoauth_url, redirect user to it.- User authorizes → redirected back with
inbox_token. POST /v4/inbox/caswithx-inbox-tokenheader → list CAS files from inbox.- Download URLs expire in 24 hours.
- Read-only access — the API cannot send emails.
- User can revoke via
POST /v4/inbox/disconnect.
- Create dedicated email addresses for investors to forward CAS statements to.
- Use case: Lower-friction alternative when OAuth or file upload isn't practical.
callback_urlis optional at creation time and controls delivery:- Set → we POST each parsed email to your webhook as it arrives. Files also remain retrievable via
GET /v4/inbound-email/{id}/filesfor 48h. - Omitted → no webhook. The inbound email is scoped to a 30-minute sliding session (each poll extends the TTL). Retrieve files via
GET /v4/inbound-email/{id}/files. The Portfolio Connect widget uses this variant whenenableInboundEmail: true.
- Set → we POST each parsed email to your webhook as it arrives. Files also remain retrievable via
- Flow (webhook variant):
POST /v4/inbound-emailwithcallback_url→ returns unique email likeie_xxx@import.casparser.in.- Investor forwards CAS email to this address.
- We validate the sender against known CAS authorities, upload PDF attachments to cloud storage, and POST to your
callback_url.
GET /v4/inbound-email/{id}/filesis available regardless of whethercallback_urlis set — use it for polling, as a backend alternative to webhooks, or to replay/backfill missed webhook deliveries. Cursor-paginated byreceived_at(microsecond-monotonic); pass the returned cursor assinceon the next call.- Only emails from verified CAS authorities are processed:
- CDSL:
eCAS@cdslstatement.com - NSDL:
NSDL-CAS@nsdl.co.in - CAMS:
donotreply@camsonline.com - KFintech:
samfS@kfintech.com
- CDSL:
- Webhook payload includes
forwarded_by(investor's email) at the top level, andfilesarray uses the sameEmailCASFileschema as Gmail Import. The polling endpoint returnsReceivedEmailCASFile— the same fields plus areceived_atcursor. sender_emailin files is the CAS authority email (lowercase),forwarded_byis the investor who forwarded the email.- Presigned download URLs expire in 48 hours when
callback_urlis set; without it, they're aligned with the 30-min session TTL. - Optional
aliasfield for friendly addresses (e.g.,john-portfolio@import.casparser.in). Not recommended whencallback_urlis omitted, since the inbound email is short-lived. - Manage with
GET /v4/inbound-email,GET /v4/inbound-email/{id},GET /v4/inbound-email/{id}/files,DELETE /v4/inbound-email/{id}. - Billing:
- 0.2 credits per validated email received, regardless of whether
callback_urlis set (charged on successful webhook delivery, or when the file is stored for polling). - Inbound email creation and polling reads (
GET /files) are free. - Portfolio Connect widget additionally incurs 1.0 credit when it auto-parses the received file (standard smart parse cost).
- 0.2 credits per validated email received, regardless of whether
- For advisors/wealth managers who want to collect CAS from clients without writing code.
- Create branded collection pages at
link.casparser.in/{your-company}. Clients visit the link, upload their CAS, and parsed data is emailed to the advisor. - Zero code, zero API integration required — managed entirely via the web portal.
- This is not a public API feature — it's a self-service tool for advisors.
- For web/frontend apps, start here. The
@cas-parser/connectnpm package provides a drop-in modal widget. - The widget handles file upload, password entry, Gmail inbox import, and CDSL OTP fetch — all in a single UI.
- Works with React, Next.js, Vue, Angular, or vanilla HTML/JS (via UMD bundle).
- Install:
npm install @cas-parser/connect - Always generate an
accessToken(at_prefix) from your backend viaPOST /v1/token. Never expose raw API keys to the frontend. - See
references/portfolio-connect-sdk.mdfor full integration guide.
POST /v1/kyc/pan/status— check KYC registration status for a PAN across all five SEBI-registered KRAs (CVL, NDML, CAMS, Karvy, KFin).- Returns normalized status (
validated,registered,under_process,on_hold,rejected,legacy,not_available,unknown) plus per-KRA breakdown. - Use
kyc_compliant: true/falseas the primary onboarding gate signal. - When
kyc_statusison_hold, checkremarkson the active KRA object for the reason. - Set timeout to 90s — the upstream portal can be slow.
- 0.25 credits per successful lookup. Failed lookups are free.
- Consent-based flow to fetch an investor's government-issued documents (Aadhaar, PAN, driving licence) directly from DigiLocker. Separate from KYC PAN Status — both sit under the KYC/Identity offering but are independent features.
- This is a multi-step, consent-driven flow (do not try to combine steps):
POST /v1/kyc/digilocker/account-lookup(optional, free) — pre-consent check whether amobileoraadhaar_numberis already registered with DigiLocker. Usesuggested_user_flowto decidesigninvssignup. Provide exactly one ofaadhaar_numberormobile.POST /v1/kyc/digilocker/session(free) — start a session. Returnsauthorization_url+session_id. Redirect the investor toauthorization_urlto log in and grant consent. Requires explicitconsent: trueand aconsent_purpose(min 20 chars) captured for DPDP/RBI audit.- Investor consents on DigiLocker → redirected back to your
redirect_urlwith query params (success,id=session_id,state,documents,has_verified_data). POST /v1/kyc/digilocker/result/{session_id}— one-call aggregate:identity, issueddocumentslist, and parsed docs viafetch_documents(pan/aadhaar/driving_licence). Each section is independent — unavailable sections are reported undererrorswithout failing the response.
session_idis the single identifier used across the flow.- Supported document types:
aadhaar,pan,driving_licence,email,mobile. - Parsed documents include a
signatureblock with the issuer's certificate details. - Never hardcode; never expose raw API keys to the frontend. Use access tokens (
at_) for client-facing calls. - Credits: account-lookup and session are free;
resultis 0.25 credits per call regardless of how many documents are fetched. Failed operations are free.
- Only original, digitally-generated PDFs are supported. No scanned/photographed PDFs (no OCR).
- Tampered or modified PDFs are rejected — the API has built-in fraud prevention for credit underwriting use-cases.
- Data is extracted verbatim from the PDF — no estimation, interpolation, or enrichment. Missing fields are
null, never fabricated.
- 400/401/403 errors are NOT retryable — fix the request (wrong password, invalid key, quota exceeded).
- 500/502/503 errors ARE retryable — use exponential backoff (1s, 2s, 4s).
- Set timeouts to 60s for parse operations, 50s for CDSL fetch Step 1, 10s for credits/tokens.
- See
references/error-handling.mdfor retry code examples and timeout guidance.
- All CAS parse endpoints return a unified response regardless of CAS type (CDSL, NSDL, or CAMS/KFintech).
- Top-level keys:
meta,investor,summary,demat_accounts,mutual_funds,insurance,nps. - Use
summary.total_valuefor portfolio value. Usesummary.accountsfor counts per category.
- Success:
{"status": "success", ...} - Failure:
{"status": "failed", "msg": "..."}for API errors,{"status": "error", "msg": "..."}for authentication errors - Common errors: invalid PDF, wrong password, quota exceeded, invalid API key.
- All responses include an
X-Request-IDheader (req_*format) — use it for support requests.
- Each API call consumes credits. Check quota with
POST /v1/credits. - Credit costs per operation:
Feature Credits CAS Parse (smart, CDSL, NSDL, CAMS/KFintech) 1.0 Contract Note Parse 0.5 KYC PAN Status 0.25 KYC DigiLocker (result) 0.25 CDSL OTP Fetch 0.5 CAS Generator (KFintech + CAMS) 0.5 Gmail Inbox Pull 0.2 Inbound Email 0.2 Portfolio Links 0.2 Failed operations 0 - Monitor usage with
POST /v1/usageandPOST /v1/usage/summary.
Always check skills/casparser/SKILL.md for existing templates and patterns before writing new CAS Parser integration code. The skill contains ready-to-use examples for:
- Portfolio Connect SDK — React, Next.js, vanilla HTML (recommended for frontend)
- Portfolio Links — No-code branded CAS collection pages for advisors
- Parsing CAS PDFs — Python, Node.js, curl (for backend/server-side)
- CDSL OTP fetch flow
- KFintech mailback generation
- Gmail inbox import
- Inbound email (email forwarding)
- KYC PAN status check
- KYC DigiLocker document fetch
- Credits and usage monitoring
The official cas-parser-node-mcp package provides an MCP server with all CAS Parser API endpoints as tools. It's auto-generated by Stainless from the OpenAPI spec and includes Code Mode — agents can write TypeScript SDK code that runs in a sandboxed environment, plus a doc search tool for exploring the API.
Claude Code (recommended — CLI):
claude mcp add cas_parser_node_mcp -e CAS_PARSER_API_KEY=your-api-key -- npx -y cas-parser-node-mcp@latestClaude Code (manual — ~/.claude.json):
{
"mcpServers": {
"cas_parser_node_mcp": {
"command": "npx",
"args": ["-y", "cas-parser-node-mcp@latest"],
"env": {
"CAS_PARSER_API_KEY": "your-api-key"
}
}
}
}Cursor (mcp.json in Cursor Settings > Tools & MCP):
{
"mcpServers": {
"cas_parser_node_mcp": {
"command": "npx",
"args": ["-y", "cas-parser-node-mcp@latest"],
"env": {
"CAS_PARSER_API_KEY": "your-api-key"
}
}
}
}Windsurf:
- Open Windsurf Settings
- Navigate to Cascade > MCP
- Click Add Server
- Enter:
- Name:
cas_parser_node_mcp - Type:
command - Command:
npx -y cas-parser-node-mcp@latest - Set env var:
CAS_PARSER_API_KEY=your-api-key
- Name:
VS Code:
{
"mcpServers": {
"cas_parser_node_mcp": {
"command": "npx",
"args": ["-y", "cas-parser-node-mcp@latest"],
"env": {
"CAS_PARSER_API_KEY": "your-api-key"
}
}
}
}Alternative — Remote (Streamable HTTP): If you prefer not to install the npm package, use the hosted server directly:
{
"mcpServers": {
"cas_parser_node_mcp": {
"url": "https://cas-parser.stlmcp.com",
"headers": {
"x-api-key": "your-api-key"
}
}
}
}Important: Replace your-api-key with your actual API key, or use sandbox-with-json-responses for testing.