Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
517 changes: 510 additions & 7 deletions apps/sim/blocks/blocks/brex.ts

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions apps/sim/tools/brex/archive_budget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { BrexArchiveBudgetParams, BrexArchiveBudgetResponse } from '@/tools/brex/types'
import { BREX_API_BASE, buildBrexHeaders, parseBrexJson } from '@/tools/brex/utils'
import type { ToolConfig } from '@/tools/types'

export const brexArchiveBudgetTool: ToolConfig<BrexArchiveBudgetParams, BrexArchiveBudgetResponse> =
{
id: 'brex_archive_budget',
name: 'Brex Archive Budget',
description:
'Archive a Brex budget, making any spend limits beneath it unusable for future expenses and removing it from the UI',
version: '1.0.0',

params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Brex user token (generated from Developer Settings in the Brex dashboard)',
},
budgetId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the budget to archive',
},
},

request: {
url: (params) =>
`${BREX_API_BASE}/v2/budgets/${encodeURIComponent(params.budgetId.trim())}/archive`,
method: 'POST',
headers: (params) => buildBrexHeaders(params.apiKey),
},

transformResponse: async (response, params) => {
if (!response.ok) {
// parseBrexJson throws a descriptive error for non-2xx responses; it never
// returns in this branch since the body cannot be a successful JSON payload.
await parseBrexJson(response)
}

// Brex's archive endpoint does not document a response body schema; fall back
// to the request's budget ID and an ARCHIVED status when the body is empty.
let data: Record<string, unknown> = {}
const text = await response.text()
if (text) {
try {
data = JSON.parse(text)
} catch {
data = {}
}
}

return {
success: true,
output: {
budgetId: (data.budget_id as string) ?? params?.budgetId ?? '',
spendBudgetStatus: (data.spend_budget_status as string) ?? 'ARCHIVED',
},
}
},

outputs: {
budgetId: { type: 'string', description: 'ID of the archived budget' },
spendBudgetStatus: {
type: 'string',
description: 'Status of the budget after archiving',
optional: true,
},
},
}
145 changes: 145 additions & 0 deletions apps/sim/tools/brex/create_budget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { generateId } from '@sim/utils/id'
import type { BrexCreateBudgetParams, BrexCreateBudgetResponse } from '@/tools/brex/types'
import { BREX_MONEY_PROPERTIES } from '@/tools/brex/types'
import { BREX_API_BASE, buildBrexHeaders, parseBrexJson, splitBrexIdList } from '@/tools/brex/utils'
import type { ToolConfig } from '@/tools/types'

export const brexCreateBudgetTool: ToolConfig<BrexCreateBudgetParams, BrexCreateBudgetResponse> = {
id: 'brex_create_budget',
name: 'Brex Create Budget',
description: 'Create a new budget in the Brex account',
version: '1.0.0',

params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Brex user token (generated from Developer Settings in the Brex dashboard)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name for the budget',
},
description: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Description of what the budget is used for',
},
parentBudgetId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the parent budget',
},
periodRecurrenceType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Period type of the budget (WEEKLY, MONTHLY, QUARTERLY, YEARLY, ONE_TIME)',
},
amount: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'Budget amount, in the smallest unit of the currency (e.g., cents for USD)',
},
currency: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ISO 4217 currency code (defaults to USD)',
},
ownerUserIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated user IDs of the budget owners',
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date the budget should start counting (YYYY-MM-DD)',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date the budget should stop counting (YYYY-MM-DD)',
},
},

request: {
url: () => `${BREX_API_BASE}/v2/budgets`,
method: 'POST',
headers: (params) => ({
...buildBrexHeaders(params.apiKey),
'Idempotency-Key': generateId(),
}),
body: (params) => {
const body: Record<string, unknown> = {
name: params.name,
description: params.description,
parent_budget_id: params.parentBudgetId,
period_recurrence_type: params.periodRecurrenceType,
amount: {
amount: params.amount,
currency: params.currency || 'USD',
},
}
const ownerUserIds = splitBrexIdList(params.ownerUserIds)
if (ownerUserIds) body.owner_user_ids = ownerUserIds
if (params.startDate) body.start_date = params.startDate
if (params.endDate) body.end_date = params.endDate
return body
},
},

transformResponse: async (response) => {
const data = await parseBrexJson(response)
return {
success: true,
output: {
budgetId: data.budget_id ?? '',
accountId: data.account_id ?? '',
name: data.name ?? '',
description: data.description ?? null,
parentBudgetId: data.parent_budget_id ?? null,
ownerUserIds: data.owner_user_ids ?? [],
periodRecurrenceType: data.period_recurrence_type ?? '',
startDate: data.start_date ?? null,
endDate: data.end_date ?? null,
amount: data.amount ?? null,
spendBudgetStatus: data.spend_budget_status ?? '',
limitType: data.limit_type ?? null,
},
}
},

outputs: {
budgetId: { type: 'string', description: 'Unique budget ID' },
accountId: { type: 'string', description: 'Account ID the budget belongs to' },
name: { type: 'string', description: 'Budget name' },
description: { type: 'string', description: 'Budget description', optional: true },
parentBudgetId: { type: 'string', description: 'Parent budget ID', optional: true },
ownerUserIds: { type: 'array', description: 'User IDs of the budget owners' },
periodRecurrenceType: {
type: 'string',
description: 'Budget period recurrence (WEEKLY, MONTHLY, QUARTERLY, YEARLY, ONE_TIME)',
},
startDate: { type: 'string', description: 'Budget start date', optional: true },
endDate: { type: 'string', description: 'Budget end date', optional: true },
amount: {
type: 'json',
description: 'Budget amount',
optional: true,
properties: BREX_MONEY_PROPERTIES,
},
spendBudgetStatus: { type: 'string', description: 'Status of the created budget' },
limitType: { type: 'string', description: 'Budget limit type', optional: true },
},
}
Loading
Loading