High-Level Architecture¶
This page gives a technical overview of how the Cost Codes integration is put together. It is aimed at anyone who wants to understand the moving parts and how they interact, without going into implementation-level detail.
Overview¶
The Cost Codes integration moves cost code data from ERP/Finance into the new Sapio LIMS instance, so that spend can be assigned to the correct cost code. For this initial integration, only two attributes are exchanged: the cost code and its description. The data is passed through as-is, with no pre- or post-processing.
Because the ERP system is not yet available, the integration is being delivered in two phases:
- Phase 1 – A POST endpoint accepts a list of cost codes. Until the ERP is live, the data arrives as a file; the contents are extracted and pushed into Sapio LIMS through the API.
- Phase 2 – Once the ERP is in place, an Experience API with a GET endpoint will be made available for Sapio LIMS to consume. Sapio then retrieves cost codes on demand, with a dedicated System API providing the connection to the ERP.
The solution is built on AWS and follows the API-led connectivity pattern, separating the integration into three layers: an Experience API, a Process API, and a System API.
Architecture Diagram¶
In Phase 1, cost code data flows into Sapio LIMS. A file received from ERP/Finance is converted internally into a JSON payload, which is then posted to the Experience API and passed down through the layers until it reaches Sapio.
flowchart TD
A[Cost Code Request / Response] <-->|HTTP REST| B[cost_codes_xapi<br/>Experience API]
B <--> C[cost_codes_papi<br/>Process API]
C <--> D[cost_codes_sapi<br/>System API]
D <--> E[Sapio LIMS]
Components¶
The integration is made up of three main components, each with a clear role.
Experience API¶
- Purpose: The entry point for HTTP clients, fronted by CloudFront and Amazon API Gateway, with a Lambda Authoriser protecting access.
- Responsibilities: Handles authentication and authorisation, validates and normalises incoming requests, attaches and propagates a correlation ID for traceability, orchestrates calls to the Process API, and returns responses in the agreed format.
- Dependencies: Amazon API Gateway, the Lambda Authoriser, and the Process API.
Process API¶
- Purpose: The business logic and validation layer that sits between the consumer-facing API and the backend systems.
- Responsibilities: Maps Experience API requests onto System API calls, shapes responses into the harmonised data model, and normalises any errors into a consistent format.
- Dependencies: The Experience API (upstream) and the System API (downstream).
System API¶
- Purpose: The abstraction layer over Sapio LIMS, shielding the rest of the integration from the specifics of the backend.
- Responsibilities: Executes operations against Sapio, maps the raw results into a standard JSON format, and returns them to the Process API.
- Dependencies: Sapio LIMS.
Data Flow¶
The interface exposes a single endpoint for this phase:
POST /cost_codes– Load the cost code information into Sapio.
A typical request travels through the layers as follows:
- Request receipt – A client sends a
POST /cost_codesrequest with an authorisation token and a JSON payload. API Gateway invokes the Lambda Authoriser, which checks the token's signature, expiry, audience, and scopes. Invalid requests are rejected with a 401 or 403 before they go any further. - Experience layer – API Gateway invokes
cost_codes_xapiwith the claims, headers, and parameters. The Experience API runs its VETRO components (validate, enrich, transform, route, operate) and calls the Process API. - Process layer –
cost_codes_papiruns its own VETRO components and invokes the System API. - Loading into Sapio –
cost_codes_sapisends the payload to Sapio LIMS over HTTPS, and Sapio returns its response. - Response mapping – The System API maps Sapio's response into the required output format and returns the harmonised data, with any available metadata, to the Process API.
- Response delivery – The Process API passes the finalised payload back to the Experience API, which responds to the client with the appropriate HTTP status. A successful load returns a 200 from Sapio.
Error Handling¶
When something goes wrong, the error is caught at the layer where it occurs and returned to the client as a JSON body with the details:
| Where it fails | What the client receives |
|---|---|
| Lambda Authoriser rejects the token | 401 Unauthorized or 403 Forbidden |
| Experience API validation fails | 400 Bad Request |
| Process API transformation or runtime error | 500 Runtime Error |
| System API credential or runtime error | 500 Runtime Error |
| Sapio LIMS returns an HTTP error | The corresponding 4XX or 5XX status |
If the Sapio API times out, the request is retried and, if it still cannot complete, a 504 is returned.
External Dependencies¶
- ERP/Finance – The origin of the cost code data. In this phase it arrives as a file, which is converted internally into a JSON payload that conforms to the agreed schema.
- Sapio LIMS – The destination system into which the cost codes are loaded.
- Identity Provider (IDP) – Authentication and authorisation are based on the organisation's IDP solutions.
- AWS services – API Gateway, CloudFront, Lambda, Secrets Manager, and AWS WAF underpin the platform.
Considerations¶
- Interim approach – This design is a stepping stone. Once the ERP is available, Phase 2 replaces the file-based intake with a GET endpoint that Sapio calls directly to retrieve cost codes from the ERP.
- Data model – The harmonised data model is still to be agreed with ERP/Finance, but the intermediate mapping into Sapio is established: the project code maps to
ProjectId, the description toProjectDesc, the lifecycle status toC_Status, and the effective start and end dates toStartDateandEndDate. Fields in the payload without a corresponding Sapio project field are not created. - Scope – The integration centres on the cost code and its description; other properties in the payload are stored only where a matching field exists on the Sapio project object.
- Security – All traffic is encrypted with SSL/TLS, endpoints are protected by authentication and authorisation, and credentials are held in AWS Secrets Manager with rotation capability. Access between the layers follows the principle of least privilege.
- Observability – Every response carries a correlation ID so requests can be traced end to end across the Experience, Process, and System APIs. Logs and metrics capture the correlation ID, the cost code details, and latency. The non-functional requirements for this phase follow those set out in the main high-level design.