Reallocate Budget
budget_reallocateTransfer a dollar amount from one campaign's daily budget to another, across platforms like Google Ads and Meta Ads, with safeguards against negative budgets.
Instructions
Transfer a dollar amount from one campaign's daily budget to another. Works across platforms (e.g. shift $50/day from a Google Ads search campaign to a Meta Ads retargeting campaign). Input: from_campaign_id, to_campaign_id (UUIDs, must differ), amount (positive number in campaign currency). Rejects the call if from_campaign_id === to_campaign_id or if the source campaign would go below zero. Returns the updated budgets for both campaigns.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| from_campaign_id | Yes | Source campaign | |
| to_campaign_id | Yes | Destination campaign | |
| amount | Yes | Amount to transfer |
Implementation Reference
- src/services/optimizer.ts:163-191 (handler)Core handler: reallocateBudget function that transfers daily budget from one campaign to another. Validates source campaign exists, budget availability, then updates both campaigns atomically via storage.
export async function reallocateBudget( fromCampaignId: string, toCampaignId: string, amount: number, store?: Storage, ): Promise<{ from: { id: string; name: string; new_budget: number }; to: { id: string; name: string; new_budget: number }; amount: number }> { const s = store ?? defaultStorage; const fromCamp = await s.getCampaignById(fromCampaignId); if (!fromCamp) throw new NotFoundError('Campaign', fromCampaignId); const toCamp = await s.getCampaignById(toCampaignId); if (!toCamp) throw new NotFoundError('Campaign', toCampaignId); if (amount > fromCamp.daily_budget) { throw new ValidationError(`Cannot reallocate $${amount}. Source campaign "${fromCamp.name}" budget is only $${fromCamp.daily_budget}.`); } const newFromBudget = round(fromCamp.daily_budget - amount); const newToBudget = round(toCamp.daily_budget + amount); await s.updateCampaign(fromCampaignId, { daily_budget: newFromBudget }); await s.updateCampaign(toCampaignId, { daily_budget: newToBudget }); return { from: { id: fromCampaignId, name: fromCamp.name, new_budget: newFromBudget }, to: { id: toCampaignId, name: toCamp.name, new_budget: newToBudget }, amount, }; } - src/models/adops.ts:452-456 (schema)Input schema: BudgetReallocateInputSchema defines the expected inputs: from_campaign_id (UUID), to_campaign_id (UUID), amount (positive number).
export const BudgetReallocateInputSchema = z.object({ from_campaign_id: z.string().uuid().describe('Source campaign'), to_campaign_id: z.string().uuid().describe('Destination campaign'), amount: z.number().min(1).describe('Amount to transfer'), }); - src/index.ts:451-476 (registration)Tool registration: server.registerTool('budget_reallocate', ...) with title, description, input schema, and the async handler that validates inputs then calls reallocateBudget.
// ── Tool 8: budget_reallocate ─────────────────────────────────────── server.registerTool( 'budget_reallocate', { title: 'Reallocate Budget', description: 'Transfer a dollar amount from one campaign\'s daily budget to another. Works across platforms (e.g. shift $50/day from a Google Ads search campaign to a Meta Ads retargeting campaign). Input: from_campaign_id, to_campaign_id (UUIDs, must differ), amount (positive number in campaign currency). Rejects the call if from_campaign_id === to_campaign_id or if the source campaign would go below zero. Returns the updated budgets for both campaigns.', inputSchema: BudgetReallocateInputSchema, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }, }, async ({ from_campaign_id, to_campaign_id, amount }) => { try { if (from_campaign_id === to_campaign_id) { return { content: [{ type: 'text' as const, text: 'from_campaign_id and to_campaign_id must be different campaigns.' }], isError: true }; } if (amount <= 0) { return { content: [{ type: 'text' as const, text: 'amount must be greater than zero.' }], isError: true }; } const result = await reallocateBudget(from_campaign_id, to_campaign_id, amount); return { content: [{ type: 'text' as const, text: JSON.stringify({ message: `Successfully reallocated $${amount}`, ...result, }, null, 2) }] }; } catch (e) { return handleToolError(e); } }, ); - src/index.ts:749-749 (registration)Tool listing: 'budget_reallocate' listed in the server tools array with description 'Transfer budget between campaigns'.
{ name: 'budget_reallocate', description: 'Transfer budget between campaigns' }, - src/services/optimizer.ts:193-195 (helper)Helper function: round() used to round budget values to 2 decimal places.
function round(n: number): number { return Math.round(n * 100) / 100; }