How to use¶
This page walks you through using the Cost Codes API, from getting access to submitting your first batch of cost codes and dealing with anything that goes wrong along the way.
During Phase 1, the API is used by the Integration Hub team: a file of cost codes is received from ERP/Finance, converted into a JSON payload, and posted to the Experience API, which loads the codes into Sapio LIMS.
Prerequisites¶
Before you can use the API, make sure you have the following in place:
- Credentials – A valid authorisation token issued by the organisation's identity provider. Every request must carry this token, and it needs the right scopes for the cost codes operation.
- User permissions – Your token must include the role/scope required to load cost codes. Without it, requests are rejected with a 401 or 403 before they reach the API.
- An HTTP client – Anything that can send a POST request with a JSON body will do, such as Postman or curl.
Authentication & Authorisation Strategy¶
Like for many integrations that the Integration Hub provide, the Barcode Printing integration require (at the time of this writing) client-credentials based OAuth 2.0 authentication. OAuth 2.0 is a standard authentication strategy that takes in a credential pair and uses a token-based validation scheme for authorisation.
Info
The token used in this scheme is a JSON Web Token (JWT).
Hence, each request that the client sends would need to be authenticated as per the authentication scheme. If authorised, the client would get access to the API which is a protected resource sitting behind a token validator.
Obtaining the client credentials need to be done by raising a FreshService ticket. Displayed below is the OAuth 2.0 procedure for authorisation and authentication.
sequenceDiagram
autonumber
participant Client
participant AS as Authorization Server
participant RO as Resource Owner
participant RS as Resource Server
Client->>AS: Authorization Request
AS->>AS: Authenticate Client & Validate requested scopes
RO->>AS: Grant access / consent
AS-->>Client: Return access token
Client->>RS: Request protected resource using access token (as per the protocol)
RS-->>Client: Return protected resource
The details underlying the authentication providers are out of scope of this document.
Getting Started¶
- Obtain a token from the identity provider with the scopes needed for the Cost Codes API.
-
Prepare your payload. The request body must be a JSON array of project payloads — even if you are only sending one. Each item needs two mandatory fields:
Body.Project.ProjectIdentifier.ID– the project code (the cost code itself)Body.Project.Description– the project description
Optional fields such as
Type,Lifecycle,EffectivePeriod, andRolescan be included in the payload, but only fields with a matching Sapio project field are actually created. The full mapping is:Integration Hub field Sapio field Notes ProjectIdentifier.IDProjectIdThe cost code — mandatory DescriptionProjectDescMandatory Lifecycle.StatusC_StatusOptional Lifecycle.EffectivePeriod.StartDateStartDateOptional Lifecycle.EffectivePeriod.EndDateEndDateOptional Anything else in the payload — such as
TypeorRoles— is accepted but not stored in Sapio.[ { "Body": { "Project": { "ProjectIdentifier": { "ID": "S-12345", "Type": "Science Project" }, "Description": "Leukaemia in Children with Down Syndrome", "Lifecycle": { "Status": "Active", "EffectivePeriod": { "StartDate": "2026-06-01T00:00:00Z", "EndDate": "2026-12-31T23:59:59Z" } } } } } ] -
Send the request to the endpoint with your token in the
Authorizationheader:POST /cost_codes/v1 -
Check the response. A successful load returns
201 Created, with one entry per submitted project containing the project ID and theRecordIDgenerated by Sapio:[ { "Project": { "ProjectIdentifier": { "ID": "S-12345", "RecordID": "XXXXXXX" } } } ]
Common Tasks¶
- Load a single cost code – Send a JSON array containing one project payload with the mandatory ID and description fields. You should get a
201 Createdwith the newRecordID. - Load a batch of cost codes – Include multiple project payloads in the same array. All entries are validated together, and the response contains a result for each submitted project. Note that the load is all-or-nothing: if any entry fails (for example, a duplicate code), the whole batch is rejected.
- Include optional details – Add the lifecycle status and effective start/end dates alongside the mandatory fields to have them stored against the project in Sapio. Other fields, such as
TypeorRoles, are accepted and forwarded but are not created in Sapio. - Verify a load – Match the entries in the response against what you submitted. Each successful project comes back with its ID and a Sapio-generated
RecordID.
Troubleshooting¶
All error responses are returned as JSON with the details of what went wrong. The most common cases are:
| Status | What it means | What to do |
|---|---|---|
| 400 Bad Request | The payload failed validation — malformed JSON, a body that isn't an array, an empty list, or a missing/invalid project_code or project_description. |
Check the response message; it identifies the offending field or item. Fix the payload and resubmit. |
| 400 Bad Request (duplicate) | One or more of the cost codes already exists in Sapio. Because the load is atomic, the entire batch is rejected. | Remove or correct the duplicate entries and resubmit the batch. |
| 401 / 403 | Your token was missing, expired, or lacked the required role. | Request a fresh token with the correct scopes and try again. |
| 500 Runtime Error | Something went wrong inside the Process or System layer. | Retry the request; if it persists, contact support with your correlation ID. |
| 503 Service Unavailable | Sapio rejected the request or is unreachable. | Wait and retry; if the problem continues, contact support. |
| 504 Gateway Timeout | Sapio did not respond within the configured timeout, even after retries. | Retry later; if it persists, contact support. |
Every response includes a correlation ID (the X-Amzn-Trace-Id header). Quote it when reporting a problem — it lets the team trace your request across all three API layers.
Support¶
For questions, access requests, or help with any of the errors above, contact the Sanger Integration Hub at integration-hub@sanger.ac.uk. Include the correlation ID from your response headers and the approximate time of the request so the team can find it in the logs.