Integration Scripts | AI & MCP | Kick Docs
Sync revenue totals to HubSpot CRM (read from Kick, write to HubSpot)
To push inflow totals by counterparty into HubSpot, aggregate transaction JSON from Kick, search for each company, then update it.
The Script
#!/bin/bash
# sync-revenue-to-hubspot.sh
WORKSPACE_ID="<workspace-id>"
HUBSPOT_API_KEY="your-hubspot-api-key"
SINCE="2026-01-01"
UNTIL="2026-01-31"
kick --workspace "$WORKSPACE_ID" transactions find \
--since "$SINCE" \
--until "$UNTIL" \
--fields amount,counterparty \
--output json | \
jq -c '\n [.[] | select(.amount > 0)] |\n group_by(.counterparty) |\n map({client: .[0].counterparty, revenue: (map(.amount) | add)})\n' | jq -c '.[]' | while IFS= read -r row; do
client=$(echo "$row" | jq -r '.client')
revenue=$(echo "$row" | jq -r '.revenue')
echo "Updating HubSpot for $client: $revenue"
company_id=$(curl -s -X POST "https://api.hubapi.com/crm/v3/objects/companies/search" \
-H "Authorization: Bearer $HUBSPOT_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"filterGroups\":[{\"filters\":[{\"propertyName\":\"name\",\"operator\":\"EQ\",\"value\":\"$client\"}]}]}" \
| jq -r '.results[0].id // empty')
if [ -z "$company_id" ]; then
echo "No HubSpot company found for $client"
continue
fi
curl -s -X PATCH "https://api.hubapi.com/crm/v3/objects/companies/${company_id}" \
-H "Authorization: Bearer $HUBSPOT_API_KEY" \
-H "Content-Type: application/json" \
-d "{\n \"properties\": {\n \"monthly_revenue\": \"$revenue\",\n \"last_revenue_update\": \"$(date -I)\"\n }\n }"
done
echo "HubSpot revenue sync finished"
How to Customize
- Match on a custom HubSpot property instead of
name - Add error handling and retry logic around the curl calls
- Filter inflows to specific categories in the
jqstep
Export transactions to a data warehouse (read from Kick, write to database)
To load transaction rows into PostgreSQL, export JSON and stream CSV into COPY.
The Script
#!/bin/bash
# export-to-warehouse.sh
WORKSPACE_ID="<workspace-id>"
DB_HOST="your-db-host"
DB_NAME="analytics"
DB_USER="etl_user"
SINCE="2026-01-01"
kick --workspace "$WORKSPACE_ID" transactions find \
--since "$SINCE" \
--fields id,date,amount,counterparty,category \
--output json \
> /tmp/kick-transactions.json
jq -r '.[] | [.id, .date, .amount, .counterparty, (.category // "null")] | @csv' /tmp/kick-transactions.json | \
psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c "\n COPY transactions (id, date, amount, counterparty, category)\n FROM STDIN WITH CSV\n "
echo "Transactions loaded to warehouse"
How to Customize
- Track the last loaded date and pass it to
--sincefor incremental loads - Page with
--cursorwhen you exceed the default limit
Export project expenses to Notion (read from Kick, write to Notion)
To mirror expense rows into a Notion database, filter transactions by category in jq and create one page per row.
The Script
#!/bin/bash
# export-to-notion.sh
WORKSPACE_ID="<workspace-id>"
NOTION_API_KEY="your-notion-api-key"
DATABASE_ID="your-notion-database-id"
CATEGORY_NAME="Marketing"
SINCE="2026-01-01"
UNTIL="2026-03-31"
kick --workspace "$WORKSPACE_ID" transactions find \
--since "$SINCE" \
--until "$UNTIL" \
--fields date,amount,counterparty,category,memo \
--output json | \
jq -c --arg cat "$CATEGORY_NAME" '.[] | select(.amount < 0 and .category == $cat)' | \
while IFS= read -r txn; do
date=$(echo "$txn" | jq -r '.date')
amount=$(echo "$txn" | jq -r '.amount | fabs')
category=$(echo "$txn" | jq -r '.category')
counterparty=$(echo "$txn" | jq -r '.counterparty')
memo=$(echo "$txn" | jq -r '.memo // """)
echo "Adding $counterparty ($amount) to Notion"
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Content-Type: application/json" \
-H "Notion-Version: 2022-06-28" \
-d "{\n \"parent\": { \"database_id\": \"$DATABASE_ID\" },\n \"properties\": {\n \"Date\": { \"date\": { \"start\": \"$date\" } },\n \"Vendor\": { \"title\": [{ \"text\": { \"content\": \"$counterparty\" } }] },\n \"Category\": { \"select\": { \"name\": \"$category\" } },\n \"Amount\": { \"number\": $amount },\n \"Notes\": { \"rich_text\": [{ \"text\": { \"content\": \"$memo\" } }] }\n }\n }"
done
echo "Project expenses exported to Notion"
How to Customize
- Change
CATEGORY_NAMEor filter on counterparty instead - Map property names to match your Notion database schema
Send weekly expense summary to Slack (read from Kick, write to Slack)
To post last week's spend and top categories to a channel, aggregate transaction JSON and call a webhook.
The Script
#!/bin/bash
# weekly-expense-summary.sh
WORKSPACE_ID="<workspace-id>"
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
SINCE="$(date -v-7d +%Y-%m-%d 2>/dev/null || date -d '7 days ago' +%Y-%m-%d)"
UNTIL="$(date +%Y-%m-%d)"
expenses=$(kick --workspace "$WORKSPACE_ID" transactions find \
--since "$SINCE" \
--until "$UNTIL" \
--fields amount,category \
--output json \
| jq '[.[] | select(.amount < 0)]')
total=$(echo "$expenses" | jq '[.[].amount] | add | fabs')
top_categories=$(echo "$expenses" | jq -r '\n group_by(.category) |\n map({\n category: (.[0].category // "Uncategorized"),\n total: (map(.amount | fabs) | add)\n }) |\n sort_by(.total) | reverse | .[0:3] |\n map("• \(.category): $\(.total)") |\n join("\n")\n')
message="*Weekly expense summary*\n*$SINCE to $UNTIL*\n\n*Total expenses:* \$$total\n\n*Top categories:*\n$top_categories\n\n<https://app.kick.co/transactions|View in Kick>"
curl -X POST "$WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"$message\"}"
echo "Weekly summary sent to Slack"
How to Customize
- Change the date window for daily or monthly summaries
- Add entity-scoped review in Kick before running the export
What It Outputs
- Slack message with total expenses and top three categories.