Skip to main content

Documentation Index

Fetch the complete documentation index at: https://casparser.in/docs/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Inbound Email API lets you create unique email addresses (like ie_xyz@import.casparser.in) where your users can forward their CAS statements. When an email arrives, we validate the sender, upload attachments to cloud storage, and deliver the result to your app. Use Case: Lower-friction alternative to OAuth or manual file upload.

Delivery options

callback_url is optional. It controls how you receive parsed files:

With callback_url

We POST parsed files to your URL whenever an investor forwards a CAS. Files also remain retrievable via GET /v4/inbound-email/{id}/files for 48h.Best for: server-side workflows, recurring statement ingestion.

Without callback_url

Retrieve files via GET /v4/inbound-email/{id}/files. The address is scoped to a 30-min sliding session (each poll extends it). Used by the Portfolio Connect widget when enableInboundEmail: true.Best for: onboarding flows, frontend-heavy apps with no backend.
Sender validation, file format, and security guarantees are identical regardless of callback_url.

How It Works


Quick Start

The Quick Start below provides a callback_url for webhook delivery. For a frontend-only flow with no backend, see Use with Portfolio Connect.

1. Create an Inbound Email

import requests

response = requests.post(
    "https://api.casparser.in/v4/inbound-email",
    headers={"x-api-key": "your-api-key"},
    json={
        "callback_url": "https://yourapp.com/webhooks/cas-email",
        "allowed_sources": ["cdsl", "nsdl"],  # Optional filter
        "reference": "user_12345",            # Your internal ID
        "metadata": {"plan": "premium"}       # Optional key-value pairs
    }
)

data = response.json()
print(f"Forward emails to: {data['email']}")
# ie_a1b2c3d4e5f6@import.casparser.in
Response (201 Created):
{
  "inbound_email_id": "ie_a1b2c3d4e5f6",
  "email": "ie_a1b2c3d4e5f6@import.casparser.in",
  "callback_url": "https://yourapp.com/webhooks/cas-email",
  "allowed_sources": ["cdsl", "nsdl"],
  "reference": "user_12345",
  "metadata": {"plan": "premium"},
  "status": "active",
  "created_at": "2025-02-22T20:00:00Z",
  "updated_at": "2025-02-22T20:00:00Z"
}
status here is the inbound email’s lifecycle (active / paused).

2. Display to User

Show the email address in your UI:
📧 Forward your CAS statement to:
   ie_a1b2c3d4e5f6@import.casparser.in

3. Handle Webhook

When the user forwards an email, we POST to your callback_url:
from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route('/webhooks/cas-email', methods=['POST'])
def handle_cas_webhook():
    data = request.get_json()
    
    # Process the inbound email
    print(f"Forwarded by: {data['forwarded_by']}")  # Investor's email
    print(f"User reference: {data['reference']}")
    print(f"Files received: {data['count']}")
    
    # Download files (URLs expire in 48 hours)
    for file in data['files']:
        url = file['url']
        filename = file['filename']
        cas_type = file['cas_type']
        
        # Download to your storage
        response = requests.get(url)
        if response.status_code == 200:
            # Save to disk or upload to your storage
            with open(f"/tmp/{filename}", 'wb') as f:
                f.write(response.content)
            print(f"Downloaded {cas_type}: {filename}")
    
    return jsonify({"status": "success"})
Webhook Payload:
{
  "inbound_email_id": "ie_a1b2c3d4e5f6",
  "forwarded_by": "investor@gmail.com",
  "reference": "user_12345",
  "metadata": {"plan": "premium"},
  "files": [
    {
      "message_id": "att_xyz789",
      "filename": "cdsl_20250222_att_xyz789.pdf",
      "original_filename": "JAN2026_AA03773313_TXN.pdf",
      "message_date": "2025-02-22",
      "cas_type": "cdsl",
      "sender_email": "ecas@cdslstatement.com",
      "size": 245000,
      "url": "https://storage.casparser.in/inbound-email/...",
      "expires_in": 172800
    }
  ],
  "count": 1
}

Retrieving Files

The GET /v4/inbound-email/{id}/files endpoint returns every file that has been forwarded to a given inbound email address. It’s available on every eligible inbound email, regardless of whether you configured a callback_url. Common uses:
  • Frontend polling — the Portfolio Connect widget polls it automatically when enableInboundEmail: true (see below).
  • Backend polling — use it instead of (or alongside) a webhook if a pull model fits your stack better.
  • Replay / backfill — fetch files that were delivered via webhook if your endpoint was down or needs to re-process them.
GET /v4/inbound-email/{inbound_email_id}/files?since=<last_cursor>&limit=20
Response:
{
  "status": "success",
  "files": [
    {
      "message_id": "att_xyz789",
      "filename": "cdsl_20250222_att_xyz789.pdf",
      "cas_type": "cdsl",
      "url": "https://storage.casparser.in/inbound-email/...",
      "expires_in": 172800,
      "received_at": "2025-02-22T20:01:12.000123+00:00"
    }
  ],
  "count": 1,
  "cursor": "2025-02-22T20:01:12.000123+00:00"
}
Cursor pagination. Pass the returned cursor as since on your next call to receive only files that arrived after it. Timestamps are guaranteed strictly monotonic at microsecond precision, so no entry is returned twice. Persist the cursor on your side between polls.
expires_in differs depending on whether callback_url was set: long-lived presigned URLs (48h) when set, aligned with the session TTL when omitted. Treat the value as authoritative and refresh by re-polling if a download fails.
Retention.
  • With callback_url set: files retained 48 hours from arrival.
  • Without callback_url: files retained for the sliding session TTL; each call extends it.

Use with Portfolio Connect

For frontend-only apps, the Portfolio Connect widget can drive the entire flow: it creates a short-lived inbound email (without a callback_url), displays it to the user, polls the retrieval endpoint above, and auto-parses the forwarded PDF. No webhook required.
React
import { PortfolioConnect } from '@cas-parser/connect';

<PortfolioConnect
  accessToken={accessToken}
  config={{
    enableInboundEmail: true,
    inboundEmail: {
      // All fields optional
      allowedSources: ['cdsl', 'nsdl'],
      reference: 'user_12345',
      metadata: { plan: 'premium' },
      pollIntervalMs: 3000,      // default
      sessionTimeoutMs: 1800000, // 30 min — matches backend TTL
    },
  }}
  onSuccess={(data, metadata) => {
    // metadata.source === 'INBOUND_EMAIL'
    // metadata.received_at === ISO timestamp
    console.log('Parsed:', data);
  }}
/>
The widget automatically:
  • Creates an inbound email via POST /v4/inbound-email (no callback_url).
  • Displays the address with a copy button.
  • Polls GET /v4/inbound-email/{id}/files every few seconds.
  • Parses the first file it receives and emits onSuccess.
  • Deletes the inbound email on widget close (or lets the 30-min TTL expire it).

Sender Validation

We automatically verify that forwarded emails originated from trusted CAS authorities: Forwarded emails are supported — we extract the original sender from email headers and body.

Managing Inbound Emails

List All

GET /v4/inbound-email?status=active&limit=50&offset=0

Get Details

GET /v4/inbound-email/ie_a1b2c3d4e5f6

Delete

DELETE /v4/inbound-email/ie_a1b2c3d4e5f6

Best Practices

1. Download Attachments Promptly

Presigned URLs expire in 48 hours. Download and store attachments in your own storage.

2. Use HTTPS for Callbacks

Production callback URLs must use HTTPS (HTTP is allowed for localhost during development).

3. Use reference for Correlation

Store your user ID in reference to map inbound emails back to your users.

4. Filter by allowed_sources

If you only need CDSL statements, set "allowed_sources": ["cdsl"] to reject others automatically.

Billing

0.2 credits per validated email received, regardless of whether callback_url was set — charged on successful webhook delivery, or when the file is stored for polling. Notes:
  • Inbound email creation, listing, and polling reads (GET /files): free.
  • Emails from unknown senders: not billed.
  • Webhook-delivery failures (after retries): still billed — the email was valid.
  • The Portfolio Connect widget incurs an additional 1.0 credit when it auto-parses the received file (standard smart-parse cost).

Error Handling

Common Issues

ErrorCauseSolution
callback_url must be HTTPSUsing HTTP in productionUse HTTPS or test with localhost
Inbound email not foundWrong ID or deletedCheck ID or recreate
alias already takenAnother inbound email uses this aliasChoose a different alias

Webhook Delivery Failures

If your webhook endpoint is down or returns an error, we retry automatically with exponential backoff.

Security

Email Authentication

We validate:
  • Exact email whitelist: Only emails from official CAS authority addresses
  • Header parsing: Extract original sender from forwarded emails

Webhook Security

  • HTTPS required: Production callbacks must use HTTPS
  • Automatic retries: Failed webhook deliveries are retried automatically
  • Attachment URLs: Time-limited presigned URLs (48h expiry)

Data Retention

  • Inbound email configs with callback_url set: active indefinitely, marked inactive after 30 days without emails.
  • Inbound email configs without callback_url: auto-expire after 30 minutes of no polling activity (sliding TTL).
  • Received file records (for polling): retained 48 hours when callback_url is set; aligned with the session TTL otherwise.

Use Cases

  1. Onboarding Flow: “Forward your CAS to get started” — simpler than OAuth
  2. Recurring Updates: Users forward monthly statements → auto-sync portfolios
  3. Offline Users: Works for investors without OAuth access or app login

Next Steps