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 CharterThe 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.
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.
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.
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.
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.
altscore/erp-connector:v1altscore-connector.yaml)http://localhost:9000<ENVELOPE><BODY><EXPORTDATA> structure| Tally TDL Field | AltScore Bronze Field | Transformation |
|---|---|---|
VOUCHERNUMBER | invoice_id | Prefix with distributor_id: {dist_id}::{VOUCHERNUMBER} |
DATE (YYYYMMDD) | invoice_date | Parse to ISO-8601 date |
PARTYLEDGERNAME | retailer_name | Raw value; GST resolved via party master lookup |
PARTYGSTIN | retailer_gst | Raw GSTIN; pseudonymized in Silver pipeline |
AMOUNT | amount_inr | Tally stores as negative for sales; abs() applied |
BILLREF.DUEDATE | due_date | Extract from BILLALLOCATIONS; ISO-8601 parse |
VOUCHERTYPE = "Receipt" | bronze_payments record | Match to invoice via BILLREF.NAME = invoice VOUCHERNUMBER |
AMOUNT (Receipt) | amount_paid_inr | abs() of receipt amount |
DATE (Receipt) | paid_date | ISO-8601 parse |
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.
https://{sap_host}:50000/b1s/v1//Login for session cookie; 30-min TTL$top / $skip with $count$filter=DocDate ge '2026-04-01'GET /Invoices — A/R invoices (Type: Customer)GET /IncomingPayments — customer receiptsGET /CreditNotes — return / credit note documentsGET /BusinessPartners — GSTIN resolution from BP master$select to fetch only required fields| SAP B1 OData Field | AltScore Bronze Field | Transformation |
|---|---|---|
DocNum | invoice_id | Prefix: {dist_id}::SAP::{DocNum} |
DocDate | invoice_date | ISO-8601 (SAP returns YYYY-MM-DDThh:mm:ss) |
CardCode | BP lookup key | Resolve to GSTIN via BusinessPartners endpoint |
CardName | retailer_name | Raw value |
FederalTaxID (from BP) | retailer_gst | Raw GSTIN from BusinessPartners master |
DocTotal | amount_inr | Direct; SAP stores in company currency (INR assumed) |
PaymentTermsGroupCode | Due date derivation | Lookup payment terms → due_date = invoice_date + net_days |
IncomingPayments.DocDate | paid_date | ISO-8601 |
IncomingPayments.CashSum + CheckSum + TransferSum | amount_paid_inr | Sum of all payment components |
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.
| File | Required Columns | Format Notes |
|---|---|---|
invoices.csv | invoice_id, retailer_gst, invoice_date, due_date, amount_inr | Dates: YYYY-MM-DD. Amount: numeric, no currency symbol. |
payments.csv | payment_id, invoice_id, paid_date, amount_paid_inr | invoice_id must match a row in invoices.csv. |
returns.csv (optional) | return_id, original_invoice_id, return_date, return_amount_inr | Optional but improves completeness score. |
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.
Distributor logs into distributor dashboard and uploads CSV files directly. Immediate schema validation feedback. Suitable for one-off backfills or troubleshooting.
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.
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.
| Field | Validation Rule | On Failure |
|---|---|---|
retailer_gst | Regex: ^[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_date | Valid ISO-8601 date; not in future; not before 2018-01-01 | Quarantine with INVALID_DATE |
due_date | ≥ invoice_date if present; not more than 180 days after invoice_date | Set to null; flag for review |
amount_inr | Positive numeric; < ₹50,00,000 (₹5 crore per invoice) | Quarantine with AMOUNT_OUTLIER |
paid_date | ≥ invoice_date if present; not in future | Quarantine payment with INVALID_PAYMENT_DATE |
invoice_id | Unique within distributor_id + invoice_id composite | Deduplicated silently (idempotent) |
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.
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.
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.
Run all normalisation and validation rules (Section 06). Invalid records are quarantined to local quarantine log. Valid records are serialised to canonical JSON.
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.
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).
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.
| Error Scenario | SDK Behaviour | Retry Policy | Escalation |
|---|---|---|---|
| ERP unreachable (Tally not running / SAP down) | Log error; do not update watermark; exit gracefully | Next scheduled run (24h) | Alert after 3 consecutive missed syncs → Ops email |
| ERP GSTIN missing on record | Attempt phone fallback; if both missing → quarantine record; continue batch | No retry — quarantine log for Ops review | Quarantine count >10% of batch → alert distributor |
| Ingestion API 429 (rate limit) | Back off per Retry-After header; hold and retry same batch | Up to 3 retries with Retry-After delay | If all retries fail → defer to next scheduled run |
| Ingestion API 5xx | Exponential backoff: 30s → 5min → 30min | 3 retries; watermark not updated | Alert Ops after 3 failures; batch queued for manual retry |
| mTLS certificate error | Abort entire run; do not retry automatically | Manual — cert may be expired | Immediate Ops alert: certificate expiry check required |
| HMAC signature mismatch (server-side) | Server returns 401; SDK logs error | No retry — key rotation may be needed | Immediate Ops alert: API key rotation procedure |
| Partial batch failure (some records quarantined) | Batch submitted with accepted records; quarantine log written locally | Quarantined records not re-attempted automatically | Daily quarantine report to Ops; distributor notified if >5% |
| Network timeout (>120s) | Treat as 5xx; exponential backoff applies | 3 retries | Alert after all retries exhausted |
Note: quarantine logs never contain raw PII — only hashed values and error codes.
altscore-ca.crt).altscore_state.json) contains no secrets or PII| ERP | Required Credential | Minimum Permission | Recommended Setup |
|---|---|---|---|
| Tally Prime | None (local HTTP API, no auth by default) | Tally Gateway must be enabled; no additional auth | Restrict Tally HTTP API to localhost only (firewall rule) |
| SAP Business One | Service Layer username + password | Read-only role: AltScore_ReadOnly (custom B1 role) | Dedicated SAP service user; disable login from SAP UI |
| CSV Upload | SFTP key pair or dashboard credentials | Write to landing zone only; no other SFTP access | Dedicated SFTP key; chroot jail to landing directory |
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).
| # | Step | Owner | Tooling | SLA |
|---|---|---|---|---|
| 1 | Data Partnership Agreement signed | AltScore BD + Distributor | DocuSign | Day 0 |
| 2 | Distributor registered in Admin Service; distributor_id assigned | AltScore Ops | Admin API POST /v1/admin/distributors | Day 1 |
| 3 | mTLS client certificate issued; API key generated; HMAC secret provisioned | AltScore Ops (automated) | cert-manager + Admin Service | Day 1 |
| 4 | Secrets securely shared with distributor IT (via encrypted email or vault) | AltScore Ops + Distributor IT | PGP-encrypted email or AltScore secure share portal | Day 1–2 |
| 5 | SDK installed and configured on distributor server | Distributor IT (AltScore support) | Docker / Python package; altscore-connector.yaml | Day 2–3 |
| 6 | Connectivity test: altscore-connector test command verifies mTLS + HMAC + API reachability | Distributor IT + AltScore Ops | SDK built-in test mode | Day 3 |
| 7 | Full historical backfill run (24–36 months) | SDK (automated once config complete) | SDK with mode: full_backfill | Day 3–4 (may take several hours) |
| 8 | Data quality review: completeness score ≥70% confirmed in Admin dashboard | AltScore Data Engineering | Admin dashboard | Day 4 |
| 9 | Retailer consent campaign initiated via WhatsApp | AltScore + Distributor | WhatsApp Business API via Admin Service | Day 4–5 |
| 10 | Daily delta sync scheduled; first scores computed | SDK (cron) | Automated post-consent | Day 5+ |