estimate_project
What it answers
Run the Scope Predictor estimator for a described project: hours per task category fitted to the comparable projects you name (projectNames, at most 10, by Project Name from list_project_entries), the likely range, how similar each of the account's projects is to the brief, the account's ABR target and, when a range is given and the owner may see payroll, Direct Delivery Margin. targetAgi is required. Same calculation and figures as the Scope Predictor page for the same inputs. It estimates only: nothing is saved (list_saved_estimates and get_saved_estimate read what people saved). Direct Delivery Margin is derived from compensation: it is returned only when the current connection owner has People (payroll) grid view on this account, otherwise it is omitted with a compensation-withheld caveat; when it cannot be computed it says why in reasons. Numbers are decimal strings. Read parakeeto://methodology for shared response conventions and INVALID_ARGUMENT guidance.
Read-only.
Arguments
| Argument | Type | Required | Default | Allowed values |
|---|---|---|---|---|
account |
string (uuid) | no | — | — |
includeDefinitions |
boolean | no | true |
— |
projectNames |
array of string | yes | — | maxItems: 10 |
targetAgi |
string | yes | — | pattern ^-?\d+(?:\.\d+)?$ |
overrides |
map of string to string | no | — | — |
brief |
object | no | — | — |
brief.serviceLine |
string | no | — | maxLength: 200 |
brief.product |
string | no | — | maxLength: 200 |
brief.client |
string | no | — | maxLength: 200 |
brief.durationDays |
string | no | — | pattern ^-?\d+(?:\.\d+)?$ |
range |
object | no | — | — |
range.from |
string | yes | — | pattern ^\d{4}-\d{2}-\d{2}$ |
range.to |
string | yes | — | pattern ^\d{4}-\d{2}-\d{2}$ |
Returned fields
The result is an envelope: ok: true with data, or ok: false with error. Error codes: MODEL_CALCULATOR_ACCESS_REQUIRED, PAYROLL_GRID_MISSING, PAYROLL_GRID_REQUIRED, PROJECT_GRID_REQUIRED, EXPENSE_GRID_REQUIRED, PAYROLL_ENTRY_REFERENCE_STALE, ACCOUNT_NOT_FOUND, ACCOUNT_CONFIGURATION_MISSING, NO_IMPORTED_TIME, NOTHING_IMPORTED, ACCOUNT_REQUIRED, NO_REACHABLE_ACCOUNTS, FEATURE_NOT_ENTITLED, PERMISSION_DENIED, CALCULATION_FAILED, INTERNAL_ERROR, INVALID_ARGUMENT.
data: objectdata.account: string (uuid)data.targetAgi: string (pattern^-?\d+(?:\.\d+)?$)data.comparables: array of objectdata.comparables[].project: stringdata.comparables[].client: string or null, optionaldata.comparables[].product: string or null, optionaldata.comparables[].serviceLine: string or null, optionaldata.comparables[].status: string or null, optionaldata.comparables[].agi: string (pattern^-?\d+(?:\.\d+)?$)data.comparables[].plannedHours: string (pattern^-?\d+(?:\.\d+)?$)data.comparables[].actualHours: string (pattern^-?\d+(?:\.\d+)?$)data.comparables[].plannedAbr: string (pattern^-?\d+(?:\.\d+)?$)data.comparables[].actualAbr: string or null, optional (pattern^-?\d+(?:\.\d+)?$)data.comparables[].startDate: string or null, optionaldata.comparables[].firstUsedDate: string or null, optionaldata.comparables[].endDate: string or null, optionaldata.comparables[].lastUsedDate: string or null, optional
data.taskCategories: array of stringdata.actuals: array of objectdata.actuals[].project: stringdata.actuals[].overallHours: string (pattern^-?\d+(?:\.\d+)?$)data.actuals[].taskCategories: map of string to stringdata.actuals[].taskCategories.*: string (pattern^-?\d+(?:\.\d+)?$)
data.plans: array of objectdata.plans[]: same shape asdata.actuals[]
data.regressions: array of objectdata.regressions[].taskCategory: stringdata.regressions[].slope: string (pattern^-?\d+(?:\.\d+)?$)data.regressions[].intercept: string (pattern^-?\d+(?:\.\d+)?$)data.regressions[].predictedHours: string (pattern^-?\d+(?:\.\d+)?$)data.regressions[].determinedHours: string (pattern^-?\d+(?:\.\d+)?$)data.regressions[].overridden: boolean
data.totalDeterminedHours: string (pattern^-?\d+(?:\.\d+)?$)data.estimatedAbr: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange: objectdata.likelyRange.status: string ("available","approximate","unavailable")data.likelyRange.usableComparables: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.excludedComparables: array of objectdata.likelyRange.excludedComparables[].project: stringdata.likelyRange.excludedComparables[].agi: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.excludedComparables[].reason: string ("non-positive-agi")
data.likelyRange.reason: string or nulldata.likelyRange.categories: array of objectdata.likelyRange.categories[].taskCategory: stringdata.likelyRange.categories[].low: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.categories[].middle: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.categories[].high: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.categories[].comparablesUsed: string (pattern^-?\d+(?:\.\d+)?$)
data.likelyRange.total: object or nulldata.likelyRange.total.low: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.total.middle: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.total.high: string (pattern^-?\d+(?:\.\d+)?$)data.likelyRange.total.comparablesUsed: string (pattern^-?\d+(?:\.\d+)?$)
data.similarity: objectdata.similarity.pointsPossible: string (pattern^-?\d+(?:\.\d+)?$)data.similarity.projects: array of objectdata.similarity.projects[].project: stringdata.similarity.projects[].score: string (pattern^-?\d+(?:\.\d+)?$)
data.similarity.closest: array of objectdata.similarity.closest[]: same shape asdata.similarity.projects[]
data.abrTarget: object or nulldata.abrTarget.value: string (pattern^-?\d+(?:\.\d+)?$)data.abrTarget.months: array of string
data.directDeliveryMargin: object, optional- One of:
- Variant 1 (
statusis"available"):data.directDeliveryMargin.status: string ("available")data.directDeliveryMargin.value: string (pattern^-?\d+(?:\.\d+)?$)data.directDeliveryMargin.directDeliveryCosts: string (pattern^-?\d+(?:\.\d+)?$)data.directDeliveryMargin.targetAgi: string (pattern^-?\d+(?:\.\d+)?$)data.directDeliveryMargin.costWindow: objectdata.directDeliveryMargin.costWindow.startDate: string (pattern^\d{4}-\d{2}-\d{2}$)data.directDeliveryMargin.costWindow.endDate: string (pattern^\d{4}-\d{2}-\d{2}$)
data.directDeliveryMargin.categories: array of objectdata.directDeliveryMargin.categories[].taskCategory: stringdata.directDeliveryMargin.categories[].estimatedHours: string (pattern^-?\d+(?:\.\d+)?$)data.directDeliveryMargin.categories[].hoursSource: string ("override","median")data.directDeliveryMargin.categories[].costPerDeliveryHour: string (pattern^-?\d+(?:\.\d+)?$)data.directDeliveryMargin.categories[].directDeliveryCost: string (pattern^-?\d+(?:\.\d+)?$)
- Variant 2 (
statusis"unavailable"):data.directDeliveryMargin.status: string ("unavailable")data.directDeliveryMargin.reasons: array of stringdata.directDeliveryMargin.categoriesWithoutCostPerDeliveryHour: array of stringdata.directDeliveryMargin.categoriesWithoutEstimatedHours: array of string
- Variant 1 (
- One of:
data.definitions: map of string to string, optionaldata.definitions.*: string
data.caveats: array of objectdata.caveats[].code: stringdata.caveats[].message: string
On failure:
error: objecterror.code: string ("MODEL_CALCULATOR_ACCESS_REQUIRED","PAYROLL_GRID_MISSING","PAYROLL_GRID_REQUIRED","PROJECT_GRID_REQUIRED","EXPENSE_GRID_REQUIRED","PAYROLL_ENTRY_REFERENCE_STALE","ACCOUNT_NOT_FOUND","ACCOUNT_CONFIGURATION_MISSING","NO_IMPORTED_TIME","NOTHING_IMPORTED","ACCOUNT_REQUIRED","NO_REACHABLE_ACCOUNTS","FEATURE_NOT_ENTITLED","PERMISSION_DENIED","CALCULATION_FAILED","INTERNAL_ERROR","INVALID_ARGUMENT")error.argument: string, optional (minLength: 1)error.message: stringerror.accounts: array of object, optionalerror.accounts[].id: string (uuid)error.accounts[].name: string
error.payrollGrids: array of object, optionalerror.payrollGrids[]: same shape aserror.accounts[]
error.projectGrids: array of object, optionalerror.projectGrids[]: same shape aserror.accounts[]
error.expenseGrids: array of object, optionalerror.expenseGrids[]: same shape aserror.accounts[]
error.context: object, optionalerror.context.account: object- Further fields: see the response.
error.context.imports: array of object- Further fields: see the response.
error.context.hasTimeEntries: booleanerror.context.reports: array of object- Further fields: see the response.
Definitions
Returned in definitions when includeDefinitions is true (the default). It is a map of string to string: each key names a field and each value is its definition text.
Caveats
Codes are not enumerated in the schema; read each code and message.
Read every caveat before interpreting a figure. See methodology on how to communicate caveats and data-quality conditions.
Example call
{
"name": "estimate_project",
"arguments": {
"projectNames": [],
"targetAgi": "50000",
"range": {
"from": "2026-01-01",
"to": "2026-03-31"
}
}
}
Add account with an identifier from list_accounts; omit it only when the connection reaches exactly one account.
Questions and answers
What does estimate_project answer?
Run the Scope Predictor estimator for a described project: hours per task category fitted to the comparable projects you name (projectNames, at most 10, by Project Name from list_project_entries), the likely range, how similar each of the account's projects is to the brief, the account's ABR target and, when a range is given and the owner may see payroll, Direct Delivery Margin. targetAgi is required. Same calculation and figures as the Scope Predictor page for the same inputs. It estimates only: nothing is saved (list_saved_estimates and get_saved_estimate read what people saved). Direct Delivery Margin is derived from compensation: it is returned only when the current connection owner has People (payroll) grid view on this account, otherwise it is omitted with a compensation-withheld caveat; when it cannot be computed it says why in reasons. Numbers are decimal strings. Read parakeeto://methodology for shared response conventions and INVALID_ARGUMENT guidance.
Which arguments does estimate_project accept?
Argument Type Required Default Allowed values account string (uuid) no — — includeDefinitions boolean no true — projectNames array of string yes — maxItems: 10 targetAgi string yes — pattern ^-?\d+(?:\.\d+)?$ overrides map of string to string no — — brief object no — — brief.serviceLine string no — maxLength: 200 brief.product string no — maxLength: 200 brief.client string no — maxLength: 200 brief.durationDays string no — pattern ^-?\d+(?:\.\d+)?$ range object no — — range.from string yes — pattern ^\d{4}-\d{2}-\d{2}$ range.to string yes — pattern ^\d{4}-\d{2}-\d{2}$
What does estimate_project return?
The result is an envelope: ok: true with data, or ok: false with error.