Project Funding
Title
Project Funding Upload API (V3) is used for creating bulk entries of project funding items.
Description
The Project Funding API allows programmatic upload and management of project funding records in Fluid. It supports uploading bulk project funding entries via a RESTful JSON API.
Project funding items represent the allocated budget for a project, optionally broken down by fiscal year and expense category. Each record stores the funding amount in local currency, default currency (converted), and restated currency (if configured). When fiscal year is omitted, the record is treated as a Life-to-Date (full project) funding entry.
Required Permission
The following Fluid roles are required to use this API:
Role | Description |
|---|---|
Financial Administrator (or App Admin) | Required to create or update project funding. The |
User | Base role required for all API access. |
Endpoints
Method | URL | Content-Type |
|---|---|---|
POST |
|
|
Request Body
Each request is treated as the complete funding snapshot for every project it contains. On submission, existing rows for those projects are replaced by the rows in the payload.
For accurate, predictable results:
Send each project's full funding in one request — include every fiscal year, expense category, and the full-project (Life-to-Date) entry. Anything omitted will be removed.
Use the bulk endpoint (
POST /rest/api/projectfunding/bulk) — it is sized to hold a project's complete funding history in a single call.Combine multiple projects in one request when convenient. Each project is processed independently, so unrelated projects are unaffected.
Tip: Treat each call as "this is the complete funding picture for project X", not "add these rows to project X".
Example
Single bulk request containing the full funding set for MM1000 (three FY rows + one Life-to-Date row):
[
{
"fields": {
"projectRef": "MM1000",
"fiscalYear": 2024,
"expenseCategory": "Resource Cost",
"amount": 50000
}
},
{
"fields": {
"projectRef": "MM1000",
"fiscalYear": 2024,
"expenseCategory": "Non-resource Cost",
"amount": 20000
}
},
{
"fields": {
"projectRef": "MM1000",
"fiscalYear": 2025,
"expenseCategory": "Resource Cost",
"amount": 70000
}
},
{
"fields": {
"projectRef": "MM1000",
"expenseCategory": "Resource Cost",
"amount": 120000
}
}
]
If MM1000 is split across two calls, the second call's payload becomes the new state for MM1000 — rows sent in the first call are no longer retained.
Type
JSON array for bulk create.
Full Field Reference
Field | Type | Required? | Description |
|---|---|---|---|
| string | Conditional | External reference of the project (e.g., |
| integer | Conditional | Integer principal ID of the project. At least one of |
| string | Conditional | GUID of the project (e.g., |
| integer | No | The fiscal year for this funding entry (e.g., |
| string | No | The expense category for the funding (e.g., |
| string | No | ISO currency code for the local currency (e.g., |
| decimal | Yes | The total funding amount in local currency. A value of |
| decimal | No | Capital expenditure portion of the funding in local currency. If both |
| decimal | No | Operating expenditure portion of the funding in local currency. If both |
Custom Properties
NOTE: Custom properties are currently not supported for project funding records via this API.
Example Requests
Bulk Create Request
POST {rooturl}/rest/api/projectfunding/bulk
Content-Type: application/json
[
{
"Fields": {
"ProjectRef": "MM1000",
"FiscalYear": 2024,
"ExpenseCategory": "Non-resource Cost",
"Amount": 50000.00
}
},
{
"Fields": {
"ProjectRef": "MM1000",
"FiscalYear": 2025,
"ExpenseCategory": "Non-resource Cost",
"Amount": 60000.00
}
},
{
"Fields": {
"ProjectRef": "HD1000",
"FiscalYear": 2024,
"ExpenseCategory": "Resource Cost",
"Amount": 80000.00,
"Capex": 20000.00,
"Opex": 60000.00
}
}
]
Response
Bulk Create Response
Returns a BulkProjectFundingResponseModel with:
Field | Type | Description |
|---|---|---|
| string | Overall status: |
| integer | Total number of records submitted. |
| integer | Number of records successfully processed. |
| integer | Number of records that failed validation or processing. |
| string | Unique correlation ID for tracking this request. |
| array | Per-row results, ordered by |
Example Bulk Response (Partial Success)
{
"Status": "partial",
"TotalCount": 3,
"ValidCount": 2,
"InvalidCount": 1,
"CorrelationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Results": [
{
"Fields": {
"IsValid": true,
"Status": "valid",
"RowIndex": 1,
"ValidationMessages": []
}
},
{
"Fields": {
"IsValid": true,
"Status": "valid",
"RowIndex": 2,
"ValidationMessages": []
}
},
{
"Fields": {
"IsValid": false,
"Status": "invalid",
"RowIndex": 3,
"ValidationMessages": [
"This row was skipped as no projects could be found with ProjectRef specified in the file."
]
}
}
]
}
Validation Rules
Project Identifier: At least one of
ProjectRef,ProjectId, orProjectGuidmust be provided. The project must exist in the Fluid database.Amount: The
Amountfield is required. A value of0will remove the existing fiscal year funding record for that project and expense category combination.ExpenseCategory: Optional. The original Excel-upload loader treated this as optional, and the V3 API preserves that behaviour for parity.
Currency Code: Optional. Currency Code is defaulted to the system currency when not provided, and it is ignored when no Secondary Currency is defined in Fluid system.
FiscalYear: Optional. If omitted or
null, the record is treated as a Life-to-Date / full project funding entry.Capex and Opex: Both optional. If neither is provided (or both are
0), the fullAmountis applied toOpex.Duplicate Handling: If a record already exists for the same project, fiscal year, and expense category, it will be updated (else a new record will be created). The entire set of records for a given project + fiscal year combination is replaced on each upload.
Full Year Auto-Generation: If fiscal year records exist but no explicit Life-to-Date record is provided, a full year summary record is automatically generated by summing all fiscal year records per project and expense category.
HTTP Status Codes
Code | Description |
|---|---|
200 OK | Request processed. Check |
400 Bad Request | The request body is malformed or missing required fields. |
401 Unauthorized | The caller is not authenticated. |
403 Forbidden | The |
429 Too Many Requests | Rate limit exceeded. See |
500 Internal Server Error | An unexpected error occurred during processing. |
Rate Limits
Endpoint | Requests | Window |
|---|---|---|
| 100 | 10 seconds |
