← Hub
AltScore Platform · Integrations
ERP Integration
Specification
DOC-ID: ERP-ALTSCORE-001
Version: 1.0 · May 2026
Classification: CONFIDENTIAL — Engineering & Distributor Partners
Owner: Data Engineering, AltScore Technologies
3Supported ERP SourcesTally Prime · SAP Business One · CSV/Manual Upload
mTLSConnector AuthPer-distributor client certificate + API key + HMAC payload signing
DeltaSync StrategyIncremental daily sync; full historical backfill on onboarding (24–36 months)
Read-OnlyERP Access ModelSDK never writes to distributor ERP; pull-only via voucher/transaction APIs
01 —

Overview & Design Principles

The AltScore ERP Connector SDK is a lightweight, read-only agent deployed on the distributor's infrastructure. It extracts invoice and payment records from the local ERP, normalises them to the AltScore schema, and pushes encrypted batches to the Ingestion API over mTLS. It never modifies ERP data and never stores raw data beyond the current batch window.

ERP-ALTSCORE-001 · Connector Design Charter
Principle 1

Read-Only Always

The SDK has no write permissions to the ERP system. It uses read-only API credentials or database roles. Any ERP change detected is reported, never originated.

Principle 2

Minimal Data Extract

Only invoice header, payment, and return records are extracted. No customer master data beyond GST and name (which are pseudonymized before transmission). No bank account, pricing, or inventory data.

Principle 3

Fail Loudly, Fail Safely

On any extraction error, the SDK logs the failure, alerts Ops, and stops — it never sends a partial or corrupted batch. Partial batches are worse than no batch for feature quality.

Distributor Disclosure Requirement

Before deploying the SDK, distributors must disclose to their retail partners (via WhatsApp consent flow) that transaction data will be shared with AltScore for credit scoring purposes. SDK installation without consent completion is a DPDP Act violation and grounds for partnership termination.

02 —

SDK Architecture

The connector SDK is packaged as a Docker container (preferred) or a Python 3.11 virtualenv for distributors who cannot run Docker. It runs as a scheduled job (cron or Windows Task Scheduler) rather than a persistent daemon, minimising attack surface.

SDK Components

Internal Modules

  • Extractor — ERP-specific pull module (Tally / SAP / CSV)
  • Normaliser — maps ERP fields to AltScore canonical schema
  • Validator — schema validation + completeness scoring
  • Deduplicator — invoice-level idempotency (no re-sends)
  • Encryptor — AES-256-GCM payload encryption
  • Signer — HMAC-SHA256 payload signature
  • Transmitter — mTLS HTTPS POST to Ingestion API
  • Logger — structured JSON logs, no PII in log lines
Deployment Options

Supported Environments

  • Docker container (preferred): altscore/erp-connector:v1
  • Python virtualenv on distributor server (Windows / Linux)
  • Scheduled via cron (Linux) or Windows Task Scheduler
  • Default schedule: 2 AM local time daily (configurable)
  • No inbound ports required — outbound HTTPS 443 only
  • Proxy support: HTTP_PROXY / HTTPS_PROXY env vars respected
  • Air-gapped option: CSV export + manual SFTP (Section 05)

SDK Configuration File (altscore-connector.yaml)

# Distributor-specific config — never commit to version control
distributor_id: dist_c4f9ee2a
erp_type: tally_prime # tally_prime | sap_b1 | csv
erp:
  host: localhost
  port: 9000                    # Tally Prime HTTP server port
  company_name: "Sharma FMCG Dist"
altscore:
  api_endpoint: https://api.altscore.in/v1/ingest/batch
  api_key_path: /secrets/altscore_api_key # never inline
  cert_path: /secrets/client.crt
  key_path: /secrets/client.key
sync:
  mode: delta # delta | full_backfill
  lookback_days: 7                     # overlap window for missed records
  max_records_per_batch: 1000
schedule: "0 2 * * *"                   # cron: daily at 2 AM local
03 —

Tally Prime Connector

Tally Prime (v2.0+)
HTTP XML API · Local port 9000 · TDL schema · ~60% of distributor base
Extraction Method
  • Tally Prime exposes a local HTTP server on port 9000 (must be enabled in Tally Gateway of Tally.ERP 9)
  • SDK sends TDL (Tally Definition Language) XML requests to http://localhost:9000
  • Requests are wrapped in <ENVELOPE><BODY><EXPORTDATA> structure
  • Returns XML response; SDK parses to canonical JSON schema
  • No Tally credentials required if running on same machine as Tally
  • Read-only: uses LEDGER and VOUCHER report exports only
Data Extracted
  • Sales vouchers (Type: Sales) → invoice records
  • Receipt vouchers (Type: Receipt) → payment records
  • Credit notes (Type: Credit Note) → return records
  • Party ledger entries for credit term resolution
  • Filter: only vouchers where party is in Sundry Debtors group
  • Date range: configurable (default: 36-month backfill, then daily delta)

Tally TDL Request Template — Invoice Extract

<!-- POST to http://localhost:9000 -->
<ENVELOPE>
  <HEADER><TALLYREQUEST>Export Data</TALLYREQUEST></HEADER>
  <BODY><EXPORTDATA>
    <REQUESTDESC>
      <REPORTNAME>Voucher Register</REPORTNAME>
      <STATICVARIABLES>
        <SVFROMDATE>20260401</SVFROMDATE>
        <SVTODATE>20260519</SVTODATE>
        <VOUCHERTYPENAME>Sales</VOUCHERTYPENAME>
      </STATICVARIABLES>
    </REQUESTDESC>
  </EXPORTDATA></BODY>
</ENVELOPE>

Tally Field Mapping to AltScore Schema

Tally TDL FieldAltScore Bronze FieldTransformation
VOUCHERNUMBERinvoice_idPrefix with distributor_id: {dist_id}::{VOUCHERNUMBER}
DATE (YYYYMMDD)invoice_dateParse to ISO-8601 date
PARTYLEDGERNAMEretailer_nameRaw value; GST resolved via party master lookup
PARTYGSTINretailer_gstRaw GSTIN; pseudonymized in Silver pipeline
AMOUNTamount_inrTally stores as negative for sales; abs() applied
BILLREF.DUEDATEdue_dateExtract from BILLALLOCATIONS; ISO-8601 parse
VOUCHERTYPE = "Receipt"bronze_payments recordMatch to invoice via BILLREF.NAME = invoice VOUCHERNUMBER
AMOUNT (Receipt)amount_paid_inrabs() of receipt amount
DATE (Receipt)paid_dateISO-8601 parse
Tally GSTIN Gap

Older Tally Prime installations (pre-2022) may not store GSTIN in PARTYGSTIN. In this case, the SDK falls back to phone number extraction from the party master. If neither is available, the record is quarantined with error code IDENTITY_UNRESOLVABLE.

04 —

SAP Business One Connector

SAP Business One (v9.3+)
Service Layer REST API · HTTPS · OData v4 · ~25% of distributor base
Extraction Method
  • SAP B1 Service Layer REST API (OData v4)
  • Base URL: https://{sap_host}:50000/b1s/v1/
  • Session-based auth: POST to /Login for session cookie; 30-min TTL
  • Read-only service user (custom role: AltScore_ReadOnly)
  • Pagination via $top / $skip with $count
  • Date filter via OData $filter=DocDate ge '2026-04-01'
Endpoints Used
  • GET /Invoices — A/R invoices (Type: Customer)
  • GET /IncomingPayments — customer receipts
  • GET /CreditNotes — return / credit note documents
  • GET /BusinessPartners — GSTIN resolution from BP master
  • All calls include $select to fetch only required fields
  • No POST/PATCH/DELETE permissions on read-only role

SAP B1 Field Mapping

SAP B1 OData FieldAltScore Bronze FieldTransformation
DocNuminvoice_idPrefix: {dist_id}::SAP::{DocNum}
DocDateinvoice_dateISO-8601 (SAP returns YYYY-MM-DDThh:mm:ss)
CardCodeBP lookup keyResolve to GSTIN via BusinessPartners endpoint
CardNameretailer_nameRaw value
FederalTaxID (from BP)retailer_gstRaw GSTIN from BusinessPartners master
DocTotalamount_inrDirect; SAP stores in company currency (INR assumed)
PaymentTermsGroupCodeDue date derivationLookup payment terms → due_date = invoice_date + net_days
IncomingPayments.DocDatepaid_dateISO-8601
IncomingPayments.CashSum + CheckSum + TransferSumamount_paid_inrSum of all payment components
05 —

CSV / Manual Upload

For distributors who cannot deploy the SDK (air-gapped systems, legacy ERPs, or low-tech operators), a CSV template upload pathway is available. The distributor exports data manually from their ERP and uploads via SFTP or the distributor dashboard. This path has lower data freshness (typically weekly vs. daily) and counts toward the data completeness score.

Required CSV Templates

FileRequired ColumnsFormat Notes
invoices.csvinvoice_id, retailer_gst, invoice_date, due_date, amount_inrDates: YYYY-MM-DD. Amount: numeric, no currency symbol.
payments.csvpayment_id, invoice_id, paid_date, amount_paid_inrinvoice_id must match a row in invoices.csv.
returns.csv (optional)return_id, original_invoice_id, return_date, return_amount_inrOptional but improves completeness score.

CSV Upload Paths

SFTP Upload

Automated Batch

Distributor drops CSV files into SFTP landing zone (sftp://ingest.altscore.in/dist_{id}/). AltScore SFTP server picks up files, validates, and processes within 1 hour. Files are deleted from SFTP after successful ingestion.

Dashboard Upload

Manual Upload

Distributor logs into distributor dashboard and uploads CSV files directly. Immediate schema validation feedback. Suitable for one-off backfills or troubleshooting.

CSV Data Quality Note

CSV uploads have a data_completeness_score ceiling of 75 (vs. 100 for ERP connectors) because CSV exports frequently miss intra-day payments and return records. Retailers scored from CSV-only data will often receive a low_confidence flag at lower credit limits.

06 —

Canonical Schema Mapping

All three ERP sources (Tally, SAP B1, CSV) map to the AltScore canonical Bronze schema before transmission. The normaliser module handles all source-specific transformations; downstream services only ever see the canonical format.

// Canonical Invoice Payload (sent to POST /v1/ingest/batch)
{
  "invoice_id": "dist_c4f9::INV-2026-00142", // unique within AltScore
  "retailer_gst": "29AABCT1332L1Z2", // 15-char GSTIN
  "retailer_name": "Sharma General Store",
  "retailer_phone": "9876543210", // 10-digit, no +91
  "invoice_date": "2026-05-03",
  "due_date": "2026-05-17", // null if payment terms unknown
  "amount_inr": 42000.00,
  "is_return": false, // true for credit notes
  "original_invoice_id": null, // set for returns
  "erp_type": "tally_prime"
}

// Canonical Payment Payload
{
  "payment_id": "dist_c4f9::REC-2026-00087",
  "invoice_id": "dist_c4f9::INV-2026-00142",
  "retailer_gst": "29AABCT1332L1Z2",
  "paid_date": "2026-05-15",
  "amount_paid_inr": 42000.00,
  "payment_method": "NEFT" // NEFT | RTGS | IMPS | cheque | cash | null
}

Validation Rules Applied at Normalisation

FieldValidation RuleOn Failure
retailer_gstRegex: ^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$Quarantine with INVALID_GSTIN
invoice_dateValid ISO-8601 date; not in future; not before 2018-01-01Quarantine with INVALID_DATE
due_date≥ invoice_date if present; not more than 180 days after invoice_dateSet to null; flag for review
amount_inrPositive numeric; < ₹50,00,000 (₹5 crore per invoice)Quarantine with AMOUNT_OUTLIER
paid_date≥ invoice_date if present; not in futureQuarantine payment with INVALID_PAYMENT_DATE
invoice_idUnique within distributor_id + invoice_id compositeDeduplicated silently (idempotent)
07 —

Delta Sync Protocol

After the initial full backfill (24–36 months of history), the connector switches to daily incremental (delta) sync. The delta strategy extracts records modified or created since the last successful sync, with a 7-day overlap window to catch late-recorded payments.

1

Load Last Sync Watermark

SDK reads last_sync_at from local state file (.altscore_state.json). On first run (or state file missing), defaults to full backfill mode from today - 36 months.

2

Extract with Overlap Window

Query ERP for records with date >= last_sync_at - 7 days. The 7-day overlap catches payment receipts recorded late in Tally or SAP (common for cheque payments). Duplicates are handled by invoice-level deduplication.

3

Normalise & Validate

Run all normalisation and validation rules (Section 06). Invalid records are quarantined to local quarantine log. Valid records are serialised to canonical JSON.

4

Chunk into Batches

Records are split into batches of max 1,000 records each. Each batch gets a unique batch_id (UUID). Batches are numbered sequentially for ordering: batch_seq: 1/3, 2/3, 3/3.

5

Sign & Transmit

Each batch payload is HMAC-SHA256 signed using the distributor's signing secret. Transmitted via mTLS HTTPS POST to /v1/ingest/batch. Retry on failure (Section 08).

6

Update Watermark

On receipt of 202 Accepted for all batches, SDK updates last_sync_at to sync_to timestamp. State is persisted atomically (write temp → rename) to prevent corruption on crash.

State File Format

// .altscore_state.json — stored on connector host, not transmitted
{
  "distributor_id": "dist_c4f9",
  "last_sync_at": "2026-05-18T02:00:00Z",
  "last_batch_id": "bat_8f3c",
  "last_sync_status": "success",
  "records_sent_total": 18742,
  "backfill_complete": true
}
08 —

Error Handling & Retry Logic

Error ScenarioSDK BehaviourRetry PolicyEscalation
ERP unreachable (Tally not running / SAP down)Log error; do not update watermark; exit gracefullyNext scheduled run (24h)Alert after 3 consecutive missed syncs → Ops email
ERP GSTIN missing on recordAttempt phone fallback; if both missing → quarantine record; continue batchNo retry — quarantine log for Ops reviewQuarantine count >10% of batch → alert distributor
Ingestion API 429 (rate limit)Back off per Retry-After header; hold and retry same batchUp to 3 retries with Retry-After delayIf all retries fail → defer to next scheduled run
Ingestion API 5xxExponential backoff: 30s → 5min → 30min3 retries; watermark not updatedAlert Ops after 3 failures; batch queued for manual retry
mTLS certificate errorAbort entire run; do not retry automaticallyManual — cert may be expiredImmediate Ops alert: certificate expiry check required
HMAC signature mismatch (server-side)Server returns 401; SDK logs errorNo retry — key rotation may be neededImmediate Ops alert: API key rotation procedure
Partial batch failure (some records quarantined)Batch submitted with accepted records; quarantine log written locallyQuarantined records not re-attempted automaticallyDaily quarantine report to Ops; distributor notified if >5%
Network timeout (>120s)Treat as 5xx; exponential backoff applies3 retriesAlert after all retries exhausted

Quarantine Log Format

// quarantine_{batch_id}.jsonl — one JSON object per line
{"record_type":"invoice","original_id":"INV-2026-00099","error_code":"INVALID_GSTIN","field":"retailer_gst","value_hash":"sha256_of_bad_value","quarantined_at":"2026-05-19T02:04:11Z"}

Note: quarantine logs never contain raw PII — only hashed values and error codes.

09 —

Connector Security

Transport Security

mTLS + HMAC

  • All transmission over TLS 1.3 (minimum TLS 1.2)
  • Per-distributor client certificate (EC P-256, 90-day rotation)
  • Certificate issued by AltScore internal CA (cert-manager on K8s)
  • Connector verifies AltScore server cert (cert pinning via altscore-ca.crt)
  • HMAC-SHA256 payload signature on every batch (prevents tampering in transit)
  • Signature key: 32-byte secret, rotated annually by Ops
Local Security

Secrets & Storage

  • All secrets (cert, key, API key, HMAC secret) stored in OS keystore or HashiCorp Vault — never in config files
  • State file (.altscore_state.json) contains no secrets or PII
  • Quarantine logs use hashed values only
  • Extracted batch data held in memory only; never written to disk mid-process
  • Container runs as non-root user (UID 1000)
  • Read-only filesystem except for state file path

ERP Credentials Required

ERPRequired CredentialMinimum PermissionRecommended Setup
Tally PrimeNone (local HTTP API, no auth by default)Tally Gateway must be enabled; no additional authRestrict Tally HTTP API to localhost only (firewall rule)
SAP Business OneService Layer username + passwordRead-only role: AltScore_ReadOnly (custom B1 role)Dedicated SAP service user; disable login from SAP UI
CSV UploadSFTP key pair or dashboard credentialsWrite to landing zone only; no other SFTP accessDedicated SFTP key; chroot jail to landing directory
10 —

Distributor Onboarding Checklist

End-to-end onboarding from contract signing to first successful sync takes approximately 3–5 business days for a Tally Prime distributor and 5–7 days for SAP B1 (due to SAP service user setup).

#StepOwnerToolingSLA
1Data Partnership Agreement signedAltScore BD + DistributorDocuSignDay 0
2Distributor registered in Admin Service; distributor_id assignedAltScore OpsAdmin API POST /v1/admin/distributorsDay 1
3mTLS client certificate issued; API key generated; HMAC secret provisionedAltScore Ops (automated)cert-manager + Admin ServiceDay 1
4Secrets securely shared with distributor IT (via encrypted email or vault)AltScore Ops + Distributor ITPGP-encrypted email or AltScore secure share portalDay 1–2
5SDK installed and configured on distributor serverDistributor IT (AltScore support)Docker / Python package; altscore-connector.yamlDay 2–3
6Connectivity test: altscore-connector test command verifies mTLS + HMAC + API reachabilityDistributor IT + AltScore OpsSDK built-in test modeDay 3
7Full historical backfill run (24–36 months)SDK (automated once config complete)SDK with mode: full_backfillDay 3–4 (may take several hours)
8Data quality review: completeness score ≥70% confirmed in Admin dashboardAltScore Data EngineeringAdmin dashboardDay 4
9Retailer consent campaign initiated via WhatsAppAltScore + DistributorWhatsApp Business API via Admin ServiceDay 4–5
10Daily delta sync scheduled; first scores computedSDK (cron)Automated post-consentDay 5+