Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.
cost, minimizeCosts, and custom objectives are deliberately powerful, but only a minority of plans need them. Before reaching for this page, check whether a standard objective (minimizeDistance, minimizeWorkingDuration, minimizeResources, and so on) already expresses the trade-off you’re after — see Built-in objectives.
A resource’s cost object accumulates several independent contributions into a single currency figure that the minimizeCosts objective then optimizes: using (a flat cost per resource used), workedHours, km, costsByStopTag, costsByCapacity, costPerCapacityPerTravelledKm, and costPerCapacityPerTravelledHour.These fields reformulate, in a real currency, the same underlying quantities that minimizeDistance, minimizeWorkingDuration, and minimizeResources already count in raw units (km, hours, vehicles). This isn’t a strict one-to-one equivalence — it’s a different objective, built on a monetary version of the same data, not a guaranteed substitute for the raw-unit objectives.
Every cost field preceding this section except using accepts a CostFloorsAndCoeffs-shaped object: a constantCost base, a costCoeff rate applied past costFloor, and an optional overcostCoeff rate that replaces costCoeff past a second, higher overcostFloor (usually a higher rate, and 0 caps the cost) — the same shape as a salary with a base, a free allowance, and an overtime-style rate beyond it. Capacities already has a worked costsByCapacity example using this object, to make capacity overflow on delivery-only tours economically unattractive rather than infeasible.costFloor is the threshold below which costCoeff doesn’t apply; constantCost is a fixed amount charged regardless of it, once per tour, as soon as the base is greater than zero. A tour whose base is 0 pays nothing, not even constantCost. So costFloor never gives a minimum, and constantCost gives one only on tours that handle at least one unit. costsByCapacity works on any capacity the stops carry (weight, revenue, a counter such as nbDeliveries…); the resource doesn’t need to declare it. The cost is computed on the quantities handled at the tour’s stops, not on the vehicle’s load: each stop adds the absolute value of its quantity for that capacity, whatever its kind or sign. Loading at departure isn’t a stop and doesn’t count, so a delivery counts once; a pickup and a delivery of the same 100 units count 200. With stopTags, only stops carrying one of those tags count. costFloor and overcostFloor then apply once, to that tour total. On a delivery-only tour, the total equals the load at departure.
Guaranteeing a minimum per-tour revenue via costsByCapacity
Create a capacity that only counts deliveries rather than any real load — for example deliveredUnits. The cost doesn’t need it declared on the resource; declare it there with a ceiling high enough never to bind only if you want to read it back in the tour’s filledCapacities values. Set it on every delivery stop (1 to count stops, or the number of units delivered there) and on no other stop, then give the resource a flat using cost and a costFloor on that capacity, so a tour that ends below the threshold keeps paying a flat penalty:
With these figures, a tour pays a flat 200 up to 50 delivered units; past that, each extra unit lowers the cost by 4, so it reaches 0 at 100 units. Nothing stops it there: past 100 units the contribution keeps falling below zero and acts as a bonus, so size costCoeff and costFloor accordingly.The flat 200 sits in using rather than in constantCost on purpose. using is charged once for every resource that is used, even when its tour delivers nothing. A constantCost on deliveredUnits is skipped when the base is 0, so a tour that delivers nothing would pay nothing and the minimum would disappear exactly where it matters. using is a single field. If the resource already has a using, for example 120 for the vehicle, write the sum ("using": 320) to keep the same total as the constantCost writing.
Rebuilding the default objective list with customCost
A CustomObjective (type: "custom") lets you optimize a cost expression built from costsByResourceTag instead of a built-in ObjectivesEnum entry — for example scoping a custom fuel-cost objective to just the resources carrying a given tag:
name must not collide with a built-in ObjectivesEnum value (the schema enforces this). costsByResourceTag maps a Cost-shaped object to a resource tag, so a custom objective can apply to a subset of the fleet rather than every resource.
A negative costCoeff under costsByStopTag represents a revenue (a negative cost) rather than a charge, combined with minimizeCosts. It sits in the resource’s cost. The base is the number of tagged stops the tour visits, so each visited stop carrying that tag adds costCoeff once:
Here van-1 earns 30 for serving stop-1 and 63 for serving stop-2.A constantCost cannot carry an amount per stop. It is paid once per tour that visits at least one stop of the tag, however many stops that is, so use costCoeff for a per-stop amount.Because maximizeMandatoryStops comes first, this revenue never makes the engine serve fewer mandatory stops.minimizeCosts compares the total cost of the possible plans. So a revenue that every plan earns alike does not change which plan is cheapest. For example, if two vans earn the same revenue for a stop, the stop stays on the van that was already the better choice. If the two vans earn different revenues for it, the stop can move to the van with the higher revenue.The revenue is included in tourCost, so it lowers tourCost, which can become negative when the resource has no other costs. If you report tourCost as money, take the revenue out of it first.
If you’d rather reason entirely in positive revenue figures, use a CustomObjective with direction: "maximize" and positive costCoeff values instead of negating them under the built-in minimizeCosts — there is no built-in maximizeCosts objective in ObjectivesEnum, only minimizeCosts. The two approaches aren’t interchangeable as they stand. objectives is a strict priority order, so put the custom objective at the exact position minimizeCosts held (third in the default list, after maximizeMandatoryStops and minimizeDelay); anywhere else, the engine trades revenue off against different objectives and can return a different plan. Also adjust whatever thresholds you’ve set elsewhere to the sign change.
The Cost object also drives a constraint, not only minimizeCosts. A maxCumulatedCost entry in the plan’s globalConstraints adds up the cost written in its costsByResourceTag over every resource that carries the tag, across the whole fleet, and caps that total at maximum. The costsByResourceTag map works as described in Rebuilding the default objective list with customCost.
Here the combined spend on subcontractor vehicles, 150 per vehicle used plus 0.6 per kilometre driven, stays at or under 1,500. The cost is set on the constraint itself, so it does not depend on each vehicle’s own cost, and it is not added to tourCost. With only "using": 1, the same constraint caps the number of vehicles in use.The wildcard "*" is not accepted, so every resource the cap must count has to carry the tag. To cap the whole fleet, give every resource a common tag. A tag that no resource carries, for example one with a typing error, counts nothing. The API still accepts the plan, but its response carries a warning for that tag, in warnings, whose properties.path points to the tag, for example plan.globalConstraints.0.costsByResourceTag["subcontractors"]. Read it from the response to the POST or PUT that sent the plan: warnings aren’t stored with the plan, so a later GET doesn’t return them. If none of the cap’s tags matches a resource, the cap has no effect.When the cap is too tight, the engine first moves work to vehicles outside the tag, if it can. Otherwise it leaves stops unplanned, mandatory ones included, and nothing in the solution names the cap as the cause: globalViolations stays empty. To confirm the cause, lock the tours as described in Handling infeasibility. A broken cap then appears in globalViolations, with the counted resourceIds and an exceededCost that is the total cost counted, not the excess over maximum.maximum is required and has no default value. The API rejects a maxCumulatedCost entry without it: the response is a 400 with an INVALID_VALUE error, whose properties.path points to the missing field, for example plan.globalConstraints.0.maximum.
Capacities — the existing costsByCapacity worked example for tolerated overflow.
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Kardinal Route Optimization API","description":"Documentation for Kardinal's self-service logistics optimization API. Create an account and get an API key at https://console.kardinal.ai.","colors":{"primary":"#4D6AFF","light":"#C5A4FF","dark":"#1B1813"},"logo":{"light":"https://mintcdn.com/kardinal/NzVu4E70FNnktm7V/images/Logo-blue-black.png?fit=max\u0026auto=format\u0026n=NzVu4E70FNnktm7V\u0026q=85\u0026s=877e4130943370aa62e85ed76662c9bc","dark":"https://mintcdn.com/kardinal/NzVu4E70FNnktm7V/images/Logo-blue-white.png?fit=max\u0026auto=format\u0026n=NzVu4E70FNnktm7V\u0026q=85\u0026s=65aa4a2a695f749b32d5fe890b8017ec","href":"/"},"favicon":"https://mintcdn.com/kardinal/NzVu4E70FNnktm7V/images/Icon-blue.png?fit=max\u0026auto=format\u0026n=NzVu4E70FNnktm7V\u0026q=85\u0026s=e8d6c833a0278ea081ea2f0507ed7cd5","navbar":{"links":[{"href":"mailto:customer.success@kardinal.ai","label":"Support"},{"href":"https://console.kardinal.ai","label":"Sign in"}],"primary":{"type":"button","label":"Get API key","href":"https://console.kardinal.ai/keys"}},"footer":{"socials":{"website":"https://kardinal.ai"}},"seo":{"organization":{"id":"https://kardinal.ai/#organization","name":"Kardinal","url":"https://kardinal.ai/","sameAs":["https://www.linkedin.com/company/kardinalai","https://github.com/KardinalAI"]},"indexing":"navigable"},"integrations":{"gtm":{"tagId":"GTM-W6RBWSX"}},"banner":{"content":"Every new account starts with 1,000 free credits. [Create your account](https://console.kardinal.ai)","dismissible":true},"styling":{"latex":false},"navigation":{"languages":[{"language":"en","default":true,"href":""}]}},"deployment":{"deploymentMetadataValue":{"subdomain":"kardinal","hasAudioNarration":false,"actualSubdomain":"kardinal","customDomains":["developers.kardinal.ai"],"gitSource":{"type":"gitlab","owner":"public-docs","repo":"mintlify","deployBranch":"main","contentDirectory":"","isPrivate":true,"projectId":682,"hostUrl":"https://gitlab.kardinal.ai","mountPath":"","label":""},"chroma":{"collectionId":"44807bae-0c5b-41f5-baf0-105d62e503c8","liveDeploymentHistoryId":"6ae45060aff4ffe6b582b403","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae45060aff4ffe6b582b403"},"feedback":{"thumbs":true,"agentFeedback":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae45060aff4ffe6b582b403","clientVersion":"0.0.4039","searchFilterCounts":[{"language":"en","tag":"Guides","count":16},{"language":"en","tag":"API Reference","count":14},{"language":"en","tag":"SDKs","count":12},{"language":"en","tag":"API","count":9},{"language":"en","tag":"Modeling examples by industry","count":8},{"language":"en","tag":"By industry","count":8},{"language":"en","tag":"Plan","count":7},{"language":"en","tag":"Advanced modeling","count":5},{"language":"en","tag":"Concepts","count":4},{"language":"en","tag":"Getting started","count":4}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"html.dark #topbar-cta-button .bg-primary-dark{background-color:rgb(var(--primary))}"}],"page":{"pagePath":"guides/cost-modeling","slug":"/guides/cost-modeling","pageMetadata":{"title":"Cost modeling","description":"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.","href":"/guides/cost-modeling"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,p:`p`,pre:`pre`,span:`span`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Tip,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Tip)_missingMdxReference(`Tip`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(Tip,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`cost`}),`, `,_jsx(_components.code,{children:`minimizeCosts`}),`, and custom objectives are deliberately powerful, but only a minority of plans need them. Before reaching for this page, check whether a standard objective (`,_jsx(_components.code,{children:`minimizeDistance`}),`, `,_jsx(_components.code,{children:`minimizeWorkingDuration`}),`, `,_jsx(_components.code,{children:`minimizeResources`}),`, and so on) already expresses the trade-off you’re after — see `,_jsx(_components.a,{href:`/concepts/objectives#built-in-objectives`,children:`Built-in objectives`}),`.`]})}),`\n`,_jsxs(Heading,{level:`2`,id:`the-cost-object`,children:[`The `,_jsx(_components.code,{children:`cost`}),` object`]}),`\n`,_jsxs(_components.p,{children:[`A resource’s `,_jsx(_components.code,{children:`cost`}),` object accumulates several independent contributions into a single currency figure that the `,_jsx(_components.code,{children:`minimizeCosts`}),` objective then optimizes: `,_jsx(_components.code,{children:`using`}),` (a flat cost per resource used), `,_jsx(_components.code,{children:`workedHours`}),`, `,_jsx(_components.code,{children:`km`}),`, `,_jsx(_components.code,{children:`costsByStopTag`}),`, `,_jsx(_components.code,{children:`costsByCapacity`}),`, `,_jsx(_components.code,{children:`costPerCapacityPerTravelledKm`}),`, and `,_jsx(_components.code,{children:`costPerCapacityPerTravelledHour`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`These fields reformulate, in a real currency, the same underlying quantities that `,_jsx(_components.code,{children:`minimizeDistance`}),`, `,_jsx(_components.code,{children:`minimizeWorkingDuration`}),`, and `,_jsx(_components.code,{children:`minimizeResources`}),` already count in raw units (km, hours, vehicles). This isn’t a strict one-to-one equivalence — it’s a different objective, built on a monetary version of the same data, not a guaranteed substitute for the raw-unit objectives.`]}),`\n`,_jsx(Heading,{level:`2`,id:`piecewise-linear-cost-functions`,children:`Piecewise-linear cost functions`}),`\n`,_jsxs(_components.p,{children:[`Every cost field preceding this section except `,_jsx(_components.code,{children:`using`}),` accepts a `,_jsx(_components.code,{children:`CostFloorsAndCoeffs`}),`-shaped object: a `,_jsx(_components.code,{children:`constantCost`}),` base, a `,_jsx(_components.code,{children:`costCoeff`}),` rate applied past `,_jsx(_components.code,{children:`costFloor`}),`, and an optional `,_jsx(_components.code,{children:`overcostCoeff`}),` rate that replaces `,_jsx(_components.code,{children:`costCoeff`}),` past a second, higher `,_jsx(_components.code,{children:`overcostFloor`}),` (usually a higher rate, and 0 caps the cost) — the same shape as a salary with a base, a free allowance, and an overtime-style rate beyond it. `,_jsx(_components.a,{href:`/guides/capacities#tolerated-overload`,children:`Capacities`}),` already has a worked `,_jsx(_components.code,{children:`costsByCapacity`}),` example using this object, to make capacity overflow on delivery-only tours economically unattractive rather than infeasible.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`costFloor`}),` is the threshold below which `,_jsx(_components.code,{children:`costCoeff`}),` doesn’t apply; `,_jsx(_components.code,{children:`constantCost`}),` is a fixed amount charged regardless of it, once per tour, as soon as the base is greater than zero. A tour whose base is 0 pays nothing, not even `,_jsx(_components.code,{children:`constantCost`}),`. So `,_jsx(_components.code,{children:`costFloor`}),` never gives a minimum, and `,_jsx(_components.code,{children:`constantCost`}),` gives one only on tours that handle at least one unit. `,_jsx(_components.code,{children:`costsByCapacity`}),` works on any capacity the stops carry (`,_jsx(_components.code,{children:`weight`}),`, `,_jsx(_components.code,{children:`revenue`}),`, a counter such as `,_jsx(_components.code,{children:`nbDeliveries`}),`…); the resource doesn’t need to declare it. The cost is computed on the quantities handled at the tour’s stops, not on the vehicle’s load: each stop adds the absolute value of its quantity for that capacity, whatever its `,_jsx(_components.code,{children:`kind`}),` or sign. Loading at departure isn’t a stop and doesn’t count, so a delivery counts once; a pickup and a delivery of the same 100 units count 200. With `,_jsx(_components.code,{children:`stopTags`}),`, only stops carrying one of those tags count. `,_jsx(_components.code,{children:`costFloor`}),` and `,_jsx(_components.code,{children:`overcostFloor`}),` then apply once, to that tour total. On a delivery-only tour, the total equals the load at departure.`]}),`\n`,_jsxs(Heading,{level:`2`,id:`guaranteeing-a-minimum-per-tour-revenue-via-costsbycapacity`,children:[`Guaranteeing a minimum per-tour revenue via `,_jsx(_components.code,{children:`costsByCapacity`})]}),`\n`,_jsxs(_components.p,{children:[`Create a capacity that only counts deliveries rather than any real load — for example `,_jsx(_components.code,{children:`deliveredUnits`}),`. The cost doesn’t need it declared on the resource; declare it there with a ceiling high enough never to bind only if you want to read it back in the tour’s `,_jsx(_components.code,{children:`filledCapacities`}),` values. Set it on every delivery stop (`,_jsx(_components.code,{children:`1`}),` to count stops, or the number of units delivered there) and on no other stop, then give the resource a flat `,_jsx(_components.code,{children:`using`}),` cost and a `,_jsx(_components.code,{children:`costFloor`}),` on that capacity, so a tour that ends below the threshold keeps paying a flat penalty:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`23`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`23`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"resources\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"subcontractor-van-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"capacities\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"weight\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`800`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"deliveredUnits\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`500`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` },`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"cost\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"using\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`200`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"costsByCapacity\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"deliveredUnits\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"costFloor\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`50`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"costCoeff\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`-4`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ],`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"orders\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"order-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"stops\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"single\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"delivery-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"position\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"lon\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`2.3522`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"lat\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`48.8566`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"kind\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"delivery\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"capacities\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"weight\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`12`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"deliveredUnits\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } }`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ]`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ],`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"objectives\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"maximizeMandatoryStops\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"minimizeCosts\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`With these figures, a tour pays a flat 200 up to 50 delivered units; past that, each extra unit lowers the cost by 4, so it reaches 0 at 100 units. Nothing stops it there: past 100 units the contribution keeps falling below zero and acts as a bonus, so size `,_jsx(_components.code,{children:`costCoeff`}),` and `,_jsx(_components.code,{children:`costFloor`}),` accordingly.`]}),`\n`,_jsxs(_components.p,{children:[`The flat 200 sits in `,_jsx(_components.code,{children:`using`}),` rather than in `,_jsx(_components.code,{children:`constantCost`}),` on purpose. `,_jsx(_components.code,{children:`using`}),` is charged once for every resource that is used, even when its tour delivers nothing. A `,_jsx(_components.code,{children:`constantCost`}),` on `,_jsx(_components.code,{children:`deliveredUnits`}),` is skipped when the base is 0, so a tour that delivers nothing would pay nothing and the minimum would disappear exactly where it matters. `,_jsx(_components.code,{children:`using`}),` is a single field. If the resource already has a `,_jsx(_components.code,{children:`using`}),`, for example 120 for the vehicle, write the sum (`,_jsx(_components.code,{children:`\"using\": 320`}),`) to keep the same total as the `,_jsx(_components.code,{children:`constantCost`}),` writing.`]}),`\n`,_jsxs(Heading,{level:`2`,id:`rebuilding-the-default-objective-list-with-customcost`,children:[`Rebuilding the default objective list with `,_jsx(_components.code,{children:`customCost`})]}),`\n`,_jsxs(_components.p,{children:[`A `,_jsx(_components.code,{children:`CustomObjective`}),` (`,_jsx(_components.code,{children:`type: \"custom\"`}),`) lets you optimize a cost expression built from `,_jsx(_components.code,{children:`costsByResourceTag`}),` instead of a built-in `,_jsx(_components.code,{children:`ObjectivesEnum`}),` entry — for example scoping a custom fuel-cost objective to just the resources carrying a given tag:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`12`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`12`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"objectives\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"custom\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"name\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"minimizeFuelCost\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"direction\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"minimize\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"costsByResourceTag\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"subcontractorA\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"km\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"costCoeff\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`0.18`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } }`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ]`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`name`}),` must not collide with a built-in `,_jsx(_components.code,{children:`ObjectivesEnum`}),` value (the schema enforces this). `,_jsx(_components.code,{children:`costsByResourceTag`}),` maps a `,_jsx(_components.code,{children:`Cost`}),`-shaped object to a resource tag, so a custom objective can apply to a subset of the fleet rather than every resource.`]}),`\n`,_jsx(Heading,{level:`2`,id:`modeling-revenue-or-margin-per-stop`,children:`Modeling revenue or margin per stop`}),`\n`,_jsxs(_components.p,{children:[`A negative `,_jsx(_components.code,{children:`costCoeff`}),` under `,_jsx(_components.code,{children:`costsByStopTag`}),` represents a revenue (a negative cost) rather than a charge, combined with `,_jsx(_components.code,{children:`minimizeCosts`}),`. It sits in the resource’s `,_jsx(_components.code,{children:`cost`}),`. The base is the number of tagged stops the tour visits, so each visited stop carrying that tag adds `,_jsx(_components.code,{children:`costCoeff`}),` once:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`18`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`18`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"resources\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"van-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"cost\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"costsByStopTag\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"standard\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"costCoeff\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`-30`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` },`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"premium\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"costCoeff\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`-63`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ],`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"orders\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"order-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"stops\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [{ `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"single\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"stop-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"position\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"lon\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`2.3522`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"lat\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`48.8566`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"tags\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"standard\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`] }] },`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"order-2\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"stops\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [{ `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"single\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"stop-2\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"position\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"lon\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`2.37`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"lat\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`48.84`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"tags\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"premium\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`] }] }`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ],`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"objectives\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"maximizeMandatoryStops\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"minimizeCosts\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Here `,_jsx(_components.code,{children:`van-1`}),` earns 30 for serving `,_jsx(_components.code,{children:`stop-1`}),` and 63 for serving `,_jsx(_components.code,{children:`stop-2`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`A `,_jsx(_components.code,{children:`constantCost`}),` cannot carry an amount per stop. It is paid once per tour that visits at least one stop of the tag, however many stops that is, so use `,_jsx(_components.code,{children:`costCoeff`}),` for a per-stop amount.`]}),`\n`,_jsxs(_components.p,{children:[`Because `,_jsx(_components.code,{children:`maximizeMandatoryStops`}),` comes first, this revenue never makes the engine serve fewer mandatory stops.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`minimizeCosts`}),` compares the total cost of the possible plans. So a revenue that every plan earns alike does not change which plan is cheapest. For example, if two vans earn the same revenue for a stop, the stop stays on the van that was already the better choice. If the two vans earn different revenues for it, the stop can move to the van with the higher revenue.`]}),`\n`,_jsxs(_components.p,{children:[`The revenue is included in `,_jsx(_components.code,{children:`tourCost`}),`, so it lowers `,_jsx(_components.code,{children:`tourCost`}),`, which can become negative when the resource has no other costs. If you report `,_jsx(_components.code,{children:`tourCost`}),` as money, take the revenue out of it first.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`If you’d rather reason entirely in positive revenue figures, use a `,_jsx(_components.code,{children:`CustomObjective`}),` with `,_jsx(_components.code,{children:`direction: \"maximize\"`}),` and positive `,_jsx(_components.code,{children:`costCoeff`}),` values instead of negating them under the built-in `,_jsx(_components.code,{children:`minimizeCosts`}),` — there is no built-in `,_jsx(_components.code,{children:`maximizeCosts`}),` objective in `,_jsx(_components.code,{children:`ObjectivesEnum`}),`, only `,_jsx(_components.code,{children:`minimizeCosts`}),`. The two approaches aren’t interchangeable as they stand. `,_jsx(_components.code,{children:`objectives`}),` is a strict priority order, so put the custom objective at the exact position `,_jsx(_components.code,{children:`minimizeCosts`}),` held (third in the default list, after `,_jsx(_components.code,{children:`maximizeMandatoryStops`}),` and `,_jsx(_components.code,{children:`minimizeDelay`}),`); anywhere else, the engine trades revenue off against different objectives and can return a different plan. Also adjust whatever thresholds you’ve set elsewhere to the sign change.`]})}),`\n`,_jsxs(Heading,{level:`2`,id:`capping-a-fleet-wide-cost-with-maxcumulatedcost`,children:[`Capping a fleet-wide cost with `,_jsx(_components.code,{children:`maxCumulatedCost`})]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`Cost`}),` object also drives a constraint, not only `,_jsx(_components.code,{children:`minimizeCosts`}),`. A `,_jsx(_components.code,{children:`maxCumulatedCost`}),` entry in the plan’s `,_jsx(_components.code,{children:`globalConstraints`}),` adds up the cost written in its `,_jsx(_components.code,{children:`costsByResourceTag`}),` over every resource that carries the tag, across the whole fleet, and caps that total at `,_jsx(_components.code,{children:`maximum`}),`. The `,_jsx(_components.code,{children:`costsByResourceTag`}),` map works as described in `,_jsxs(_components.a,{href:`#rebuilding-the-default-objective-list-with-customcost`,children:[`Rebuilding the default objective list with `,_jsx(_components.code,{children:`customCost`})]}),`.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`18`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`18`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"resources\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"id\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"subcontractor-van-1\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"tags\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"subcontractor\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`]`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ],`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"globalConstraints\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: [`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"type\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"maxCumulatedCost\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"name\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"subcontractor-budget\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"maximum\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`1500`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"costsByResourceTag\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:` \"subcontractor\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"using\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`150`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"km\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: { `}),_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#9CDCFE`},children:`\"costCoeff\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:`0.6`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` } }`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` ]`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Here the combined spend on `,_jsx(_components.code,{children:`subcontractor`}),` vehicles, 150 per vehicle used plus 0.6 per kilometre driven, stays at or under 1,500. The cost is set on the constraint itself, so it does not depend on each vehicle’s own `,_jsx(_components.code,{children:`cost`}),`, and it is not added to `,_jsx(_components.code,{children:`tourCost`}),`. With only `,_jsx(_components.code,{children:`\"using\": 1`}),`, the same constraint caps the number of vehicles in use.`]}),`\n`,_jsxs(_components.p,{children:[`The wildcard `,_jsx(_components.code,{children:`\"*\"`}),` is not accepted, so every resource the cap must count has to carry the tag. To cap the whole fleet, give every resource a common tag. A tag that no resource carries, for example one with a typing error, counts nothing. The API still accepts the plan, but its response carries a warning for that tag, in `,_jsx(_components.code,{children:`warnings`}),`, whose `,_jsx(_components.code,{children:`properties.path`}),` points to the tag, for example `,_jsx(_components.code,{children:`plan.globalConstraints.0.costsByResourceTag[\"subcontractors\"]`}),`. Read it from the response to the `,_jsx(_components.code,{children:`POST`}),` or `,_jsx(_components.code,{children:`PUT`}),` that sent the plan: warnings aren’t stored with the plan, so a later `,_jsx(_components.code,{children:`GET`}),` doesn’t return them. If none of the cap’s tags matches a resource, the cap has no effect.`]}),`\n`,_jsxs(_components.p,{children:[`When the cap is too tight, the engine first moves work to vehicles outside the tag, if it can. Otherwise it leaves stops unplanned, mandatory ones included, and nothing in the solution names the cap as the cause: `,_jsx(_components.code,{children:`globalViolations`}),` stays empty. To confirm the cause, lock the tours as described in `,_jsx(_components.a,{href:`/guides/handling-infeasibility#testing-a-stop-on-a-specific-resource-with-state-assignments`,children:`Handling infeasibility`}),`. A broken cap then appears in `,_jsx(_components.code,{children:`globalViolations`}),`, with the counted `,_jsx(_components.code,{children:`resourceIds`}),` and an `,_jsx(_components.code,{children:`exceededCost`}),` that is the total cost counted, not the excess over `,_jsx(_components.code,{children:`maximum`}),`.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`maximum`}),` is required and has no default value. The API rejects a `,_jsx(_components.code,{children:`maxCumulatedCost`}),` entry without it: the response is a `,_jsx(_components.code,{children:`400`}),` with an `,_jsx(_components.code,{children:`INVALID_VALUE`}),` error, whose `,_jsx(_components.code,{children:`properties.path`}),` points to the missing field, for example `,_jsx(_components.code,{children:`plan.globalConstraints.0.maximum`}),`.`]}),`\n`,_jsx(Heading,{level:`2`,id:`see-also`,children:`See also`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/concepts/objectives#the-default-list`,children:`Objectives and how they’re ranked`}),` — where `,_jsx(_components.code,{children:`minimizeCosts`}),` sits in the default objective order.`]}),`\n`,_jsxs(_components.li,{children:[_jsx(_components.a,{href:`/guides/capacities#tolerated-overload`,children:`Capacities`}),` — the existing `,_jsx(_components.code,{children:`costsByCapacity`}),` worked example for tolerated overflow.`]}),`\n`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Cost modeling","description":"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.","href":"/guides/cost-modeling"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"The cost object","slug":"the-cost-object","depth":2,"children":[]},{"title":"Piecewise-linear cost functions","slug":"piecewise-linear-cost-functions","depth":2,"children":[]},{"title":"Guaranteeing a minimum per-tour revenue via costsByCapacity","slug":"guaranteeing-a-minimum-per-tour-revenue-via-costsbycapacity","depth":2,"children":[]},{"title":"Rebuilding the default objective list with customCost","slug":"rebuilding-the-default-objective-list-with-customcost","depth":2,"children":[]},{"title":"Modeling revenue or margin per stop","slug":"modeling-revenue-or-margin-per-stop","depth":2,"children":[]},{"title":"Capping a fleet-wide cost with maxCumulatedCost","slug":"capping-a-fleet-wide-cost-with-maxcumulatedcost","depth":2,"children":[]},{"title":"See also","slug":"see-also","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/_mintlify/custom/kardinal/d55e84efee54b775/kd-att-docs.js"],"subdomain":"kardinal","siteName":"Kardinal Route Optimization API","title":"Cost modeling - Kardinal Route Optimization API","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{"en":{"href":"/guides/cost-modeling","matchLevel":0}}},"lastModified":"2026-10-30T08:08:07.657Z","originalFileLocation":"guides/cost-modeling.mdx","locale":"en"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Kardinal Route Optimization API\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Cost modeling - Kardinal Route Optimization API\">\u003cmeta data-mint-head property=\"og:description\" content=\"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Kardinal Route Optimization API\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://developers.kardinal.ai/guides/cost-modeling\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://kardinal.mintlify.app/_mintlify/api/og/v2?division=Advanced+modeling\u0026amp;title=Cost+modeling\u0026amp;description=Express+cost+in+real+currency%2C+use+piecewise-linear+cost+functions%2C+guarantee+a+minimum+revenue+per+tour%2C+cap+fleet-wide+cost%2C+and+write+custom+objectives.\u0026amp;theme=36328a05d721350f0182956e\u0026amp;signature=91b2f7538af95a84ec0ac1159dcb22b4c8eb6c29df47f7cd0fe947d829fbc388\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Cost modeling - Kardinal Route Optimization API\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://kardinal.mintlify.app/_mintlify/api/og/v2?division=Advanced+modeling\u0026amp;title=Cost+modeling\u0026amp;description=Express+cost+in+real+currency%2C+use+piecewise-linear+cost+functions%2C+guarantee+a+minimum+revenue+per+tour%2C+cap+fleet-wide+cost%2C+and+write+custom+objectives.\u0026amp;theme=36328a05d721350f0182956e\u0026amp;signature=91b2f7538af95a84ec0ac1159dcb22b4c8eb6c29df47f7cd0fe947d829fbc388\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/kardinal/4VnUJAe0ozIKpmRZ/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Kardinal Route Optimization API\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#4D6AFF\">\u003clink data-mint-head rel=\"canonical\" href=\"https://developers.kardinal.ai/guides/cost-modeling\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/guides/cost-modeling.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://kardinal.ai/#organization\",\"name\":\"Kardinal\",\"url\":\"https://kardinal.ai/\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/kardinal/NzVu4E70FNnktm7V/images/Logo-blue-black.png?fit=max\u0026auto=format\u0026n=NzVu4E70FNnktm7V\u0026q=85\u0026s=877e4130943370aa62e85ed76662c9bc\"},\"sameAs\":[\"https://www.linkedin.com/company/kardinalai\",\"https://github.com/KardinalAI\"]},{\"@type\":\"WebSite\",\"@id\":\"https://developers.kardinal.ai#website\",\"name\":\"Kardinal Route Optimization API\",\"url\":\"https://developers.kardinal.ai\",\"publisher\":{\"@id\":\"https://kardinal.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://developers.kardinal.ai/guides/cost-modeling#webpage\",\"url\":\"https://developers.kardinal.ai/guides/cost-modeling\",\"name\":\"Cost modeling\",\"description\":\"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.\",\"dateModified\":\"2026-10-30T08:08:07.657Z\",\"isPartOf\":{\"@id\":\"https://developers.kardinal.ai#website\"},\"breadcrumb\":{\"@id\":\"https://developers.kardinal.ai/guides/cost-modeling#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://developers.kardinal.ai/guides/cost-modeling#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Advanced modeling\",\"item\":\"https://developers.kardinal.ai/guides/advanced-constraints\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Cost modeling\",\"item\":\"https://developers.kardinal.ai/guides/cost-modeling\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://developers.kardinal.ai/guides/cost-modeling#article\",\"headline\":\"Cost modeling\",\"name\":\"Cost modeling\",\"description\":\"Express cost in real currency, use piecewise-linear cost functions, guarantee a minimum revenue per tour, cap fleet-wide cost, and write custom objectives.\",\"url\":\"https://developers.kardinal.ai/guides/cost-modeling\",\"mainEntityOfPage\":{\"@id\":\"https://developers.kardinal.ai/guides/cost-modeling#webpage\"},\"dateModified\":\"2026-10-30T08:08:07.657Z\",\"publisher\":{\"@id\":\"https://kardinal.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://developers.kardinal.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Kardinal Route Optimization API\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Kardinal Route Optimization API","nav":{"global":null,"languages":[{"language":"en","default":true,"tabs":[{"tab":"Getting started","pages":[{"title":"Getting started","href":""}]},{"tab":"Concepts","pages":[{"title":"Concepts","href":"/concepts/how-the-optimization-engine-works"}]},{"tab":"Guides","groups":[{"group":"Vocabulary mapping","pages":[{"title":"Vocabulary mapping","mode":"wide","href":"/guides/vocabulary-mapping"}]},{"group":"Before modeling","pages":[{"title":"Requirements briefing checklist","href":"/guides/requirements-briefing"}]},{"group":"Modeling business rules","pages":[{"title":"Time windows","href":"/guides/time-windows"},{"title":"Breaks","href":"/guides/breaks"},{"title":"Skills and assignments","href":"/guides/skills-and-assignments"},{"title":"Capacities","href":"/guides/capacities"}]},{"group":"Integration","pages":[{"title":"Authentication and API keys","href":"/guides/authentication"},{"title":"Moving from sandbox to production","href":"/guides/sandbox-to-production"},{"title":"Handling large volumes","href":"/guides/handling-large-volumes"}]},{"group":"Advanced modeling","pages":[{"title":"Modeling advanced constraints","description":"Model a fleet that isn't uniform: varied vehicle capacities, driver skills, mandatory breaks, multiple time windows per stop, optional steps gating a stop, and keeping stops on the same vehicle in any order.","href":"/guides/advanced-constraints"},{"title":"Cost modeling","href":"/guides/cost-modeling"},{"title":"Multi-trip tours (depot returns)","description":"Model vehicles that reload at the depot and run several rounds in one shift, count depot time once per visit, and limit simultaneous depot visits and returns.","href":"/guides/multi-trip-tours"},{"title":"Swap-body and container-exchange orders","href":"/guides/swap-body-exchange"},{"title":"Handling infeasibility","href":"/guides/handling-infeasibility"}]},{"group":"Operations","pages":[{"title":"Real-time re-optimization","href":"/guides/real-time-reoptimization"},{"title":"Manual assignment and supervision","href":"/guides/manual-assignment-and-supervision"}]}]},{"tab":"SDKs","pages":[{"title":"SDKs","href":"/sdks/overview"}]},{"tab":"API Reference","pages":[{"title":"API Reference","href":"/api-reference/plan/retrieve-the-list-of-plans-in-a-light-representation"}]},{"tab":"Modeling examples by industry","pages":[{"title":"Modeling examples by industry","href":"/case-studies/overview"}]}]}]},"basePath":"","title":"Cost modeling - Kardinal Route Optimization API","buildId":"dpl_77Hw7ZuAABM8E3WMbYAf2ohQCr3v","deploymentId":"dpl_77Hw7ZuAABM8E3WMbYAf2ohQCr3v","dynamics":["10e4515597"],"chunks":["BannerMarkdown-Br4Fx2_Z.js","dist-ptfS1uB_.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","clsx-rIpTdK8h.js","html-void-elements-mCSPHezU.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js"]}