2.8 Ingestion (inbound feeds and mappings)
Outcome
The customer's source systems can deliver members, encounters, eligibility files, and EHR exports into the tenant — via SFTP, real-time push API, or both.
Prerequisites
- 2.7 Rules and modifiers complete.
Two inbound channels
Pick whichever fits the customer:
- SFTP: best for nightly batch from EHRs that already export files.
- Push API: best for low-latency event streams or modern EHR webhooks.
Steps
Choose a transport
Impersonate the tenant →
Admin → Ingestion → Feeds → Add feed. Pick:- SFTP (inbound): Platform polls a configured SFTP server every N minutes.
- SFTP (outbound): Platform exposes an SFTP endpoint to which the customer drops files.
- Push API: Platform issues a bearer key; customer POSTs JSON or X12 to
https://api.rcm.medsuite.com/api/v1/ingest/<feed-slug>.
Configure the transport
For SFTP (inbound):
Field Value Host customer-sftp.example.comPort 22 Username the credentials the customer provides Auth password OR private key (write-only — paste once, never displayed again) Remote path /outbound/medsuiteCron */15 * * * *(every 15 min) or shorthandevery-15-minArchive on success yes — moves to /archiveafter pickupFor Push API:
Admin → Ingestion → API keys → Mint key— capture the secret immediately (shown once). Up to 5 active keys per tenant; rotation supported.Create the mapping definition
Admin → Ingestion → Mappings → New mappingThis is the YAML spec that turns raw inbound rows into canonical entities (member, encounter, etc.). Use the visual
FieldMapperfor drag-drop, or hand-edit Monaco YAML for power users.name: acme-members-csvversion: 1input:format: csvencoding: utf-8delimiter: ','skipLines: 1output:entity: memberfields:- source: 'External ID'target: external_idtransform: trim- source: 'DOB'target: dobtransform: dateFromString('MM/dd/yyyy')- source: 'First Name'target: first_name- source: 'Last Name'target: last_name- source: 'Coverage Plan'target: coverage_plan_codetransform:- lookup:table: program_config_aliaskey: codefallback: REJECTvalidation:required: [external_id, first_name, last_name, dob]The Mapping editor includes a live dry-run panel — paste 3–5 sample rows and see the parsed entities + any validation errors before publishing.
Set lifecycle: DRAFT → SUBMITTED → ACTIVE
Mapping lifecycle:
- DRAFT — your edits, never seen by the live engine.
- SUBMITTED — handed off for peer review (no engine effect yet).
- ACTIVE — the live engine picks it up. Only one ACTIVE per (tenant, feed_slug).
- ARCHIVED — superseded by a newer version.
Click
Activateonce peer-reviewed. The engine starts using it at the next polling interval (SFTP) or immediately (push).Test the feed
For SFTP: drop a small test file in the remote path. After the next poll cycle, the file should appear in
Admin → Ingestion → Artifactswith statusparsed.For Push API:
curl -X POST https://api.rcm.medsuite.com/api/v1/ingest/acme-members-csv \-H "Authorization: Bearer <api-key>" \-H "Content-Type: text/csv" \--data-binary @sample.csvSet up alerts
Admin → Ingestion → Feeds → <feed> → Alerts:- No file received within N hours: warn at 24, alert at 48.
- Validation error rate > 5%: alert.
- Push API quota approaching: warn at 80%, alert at 95%.
Validation
| Check | Expected |
|---|---|
Test file appears in Artifacts | status parsed |
| Tenant DB entities exist | row counts match input rows after dedupe |
| Audit log shows the ingestion | INGESTION_BATCH_PROCESSED events |
| Push API key works | 200 response from POST |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| SFTP poll never fires | Cron disabled at feed level | Edit feed → Toggle 'Active'. |
| Files arrive but not picked up | Wrong remote path | Inspect with an sftp client; correct the path. |
| 401 from Push API | Key revoked or expired | Mint a new key. |
| Validation rejects all rows | Mapping schema mismatch | Use the dry-run panel; correct the YAML. |
| Encoding errors on European customer files | UTF-8 BOM / Windows-1252 | Set input.encoding correctly in the mapping. |