Tink.FinancialCalendar (Tink v0.1.1)

Copy Markdown View Source

Financial Calendar API for managing scheduled financial events.

This module provides comprehensive financial calendar management for tracking:

  • Upcoming bills and payments
  • Income events (salary, invoices)
  • Recurring financial events
  • Event reconciliation with actual transactions
  • Calendar summaries and overviews

Features

  • Event Management: Create, update, delete financial events
  • Recurring Events: Support for recurring patterns (daily, weekly, monthly)
  • Attachments: Add documents/links to events (invoices, receipts)
  • Reconciliation: Match events with actual transactions
  • Summaries: Get calendar overviews by time period
  • Suggestions: AI-powered reconciliation suggestions

Prerequisites

  • Generated user with bearer token
  • Accounts created and linked to user
  • (Optional) Transactions ingested for reconciliation

Flow Overview

# Create client with user bearer token
client = Tink.client(access_token: user_bearer_token)

# Create a bill event
{:ok, event} = Tink.FinancialCalendar.create_event(client, %{
  title: "Electricity Bill",
  description: "Monthly electricity payment",
  due_date: "2024-02-15",
  event_amount: %{
    currency_code: "EUR",
    value: %{unscaled_value: 12500, scale: 2}  # €125.00
  }
})

# Get event details
{:ok, details} = Tink.FinancialCalendar.get_event(client, event["id"])

# Add attachment (invoice PDF)
{:ok, attachment} = Tink.FinancialCalendar.add_attachment(client, event["id"], %{
  title: "Invoice February 2024",
  url: "https://storage.example.com/invoice.pdf"
})

# Create recurring event
{:ok, recurring} = Tink.FinancialCalendar.create_recurring_group(
  client,
  event["id"],
  %{rrule_pattern: "FREQ=MONTHLY;COUNT=12"}
)

# List upcoming events
{:ok, events} = Tink.FinancialCalendar.list_events(client,
  due_date_gte: "2024-02-01",
  due_date_lte: "2024-02-29"
)

# Get calendar summary
{:ok, summary} = Tink.FinancialCalendar.get_summaries(client,
  resolution: "WEEKLY",
  period_gte: "2024-02-01",
  period_lte: "2024-02-29"
)

# Reconcile with transaction
{:ok, reconciliation} = Tink.FinancialCalendar.create_reconciliation(
  client,
  event["id"],
  %{transaction_id: "txn_123"}
)

Use Cases

Bill Tracking

@spec track_monthly_bills(Client.t()) :: {:ok, list(map())} | {:error, Error.t()}

def track_monthly_bills(client) do
  bills = [
    {"Rent", "2024-02-01", 150000},
    {"Electricity", "2024-02-15", 8500},
    {"Internet", "2024-02-20", 4999}
  ]

  Enum.map(bills, fn {title, due_date, amount} ->
    Tink.FinancialCalendar.create_event(client, %{
      title: title,
      due_date: due_date,
      event_amount: money_amount(amount, "EUR")
    })
  end)
end

Salary Tracking

@spec setup_salary_events(Client.t(), integer()) :: {:ok, list(map())} | {:error, Error.t()}

def setup_salary_events(client, monthly_salary) do
  # Create first salary event
  {:ok, event} = Tink.FinancialCalendar.create_event(client, %{
    title: "Monthly Salary",
    due_date: next_salary_date(),
    event_amount: money_amount(monthly_salary, "EUR")
  })

  # Make it recurring (monthly for a year)
  Tink.FinancialCalendar.create_recurring_group(client, event["id"], %{
    rrule_pattern: "FREQ=MONTHLY;COUNT=12"
  })
end

Budget Planning

@spec get_upcoming_obligations(Client.t(), non_neg_integer()) :: {:ok, list(map())} | {:error, Error.t()}

def get_upcoming_obligations(client, days \ 30) do
  start_date = Date.to_iso8601(Date.utc_today())
  end_date = Date.add(Date.utc_today(), days) |> Date.to_iso8601()

  {:ok, events} = Tink.FinancialCalendar.list_events(client,
    due_date_gte: start_date,
    due_date_lte: end_date
  )

  total = calculate_total_amount(events["events"])

  %{
    event_count: length(events["events"]),
    total_amount: total,
    events: events["events"]
  }
end

Recurring Patterns

Uses RFC 5545 RRULE format:

  • Daily: FREQ=DAILY;COUNT=30
  • Weekly: FREQ=WEEKLY;COUNT=52
  • Monthly: FREQ=MONTHLY;COUNT=12
  • Yearly: FREQ=YEARLY;COUNT=5
  • Every 2 weeks: FREQ=WEEKLY;INTERVAL=2;COUNT=26

Required Scope

User bearer token (user authentication, not client credentials)

Summary

Functions

Adds an attachment to a calendar event.

Creates a new financial calendar event.

Creates a reconciliation between an event and a transaction.

Creates a recurring group for an event.

Deletes an attachment from a calendar event.

Deletes a calendar event.

Gets details for a specific calendar event.

Gets reconciliation details for an event.

Gets reconciliation suggestions for an event.

Gets calendar summaries for a period with specified resolution.

Lists calendar events with optional filtering.

Updates a calendar event.

Functions

add_attachment(client, event_id, params)

@spec add_attachment(Tink.Client.t(), String.t(), map()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Adds an attachment to a calendar event.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID
  • params - Attachment parameters:
    • :title - Attachment title (required)
    • :url - Attachment URL (required)

Returns

  • {:ok, attachment} - Created attachment with id
  • {:error, error} - If the request fails

Examples

{:ok, attachment} = Tink.FinancialCalendar.add_attachment(
  client,
  "event_abc123",
  %{
    title: "Invoice February 2024",
    url: "https://storage.example.com/invoices/feb-2024.pdf"
  }
)
#=> {:ok, %{
#     "id" => "attachment_xyz",
#     "title" => "Invoice February 2024",
#     "url" => "https://storage.example.com/invoices/feb-2024.pdf"
#   }}

create_event(client, params)

@spec create_event(Tink.Client.t(), map()) :: {:ok, map()} | {:error, Tink.Error.t()}

Creates a new financial calendar event.

Parameters

  • client - Tink client with user bearer token
  • params - Event parameters:
    • :title - Event title (required)
    • :due_date - Due date (ISO-8601: "YYYY-MM-DD") (required)
    • :event_amount - Amount (required):
      • :currency_code - Currency code (e.g., "EUR", "USD")
      • :value - Amount value:
        • :unscaled_value - Amount in smallest unit
        • :scale - Decimal places
    • :description - Event description (optional)

Returns

  • {:ok, event} - Created event with id
  • {:error, error} - If the request fails

Examples

# Create a bill event
{:ok, event} = Tink.FinancialCalendar.create_event(client, %{
  title: "Electricity Bill",
  description: "Monthly electricity payment",
  due_date: "2024-02-15",
  event_amount: %{
    currency_code: "EUR",
    value: %{
      unscaled_value: 12500,
      scale: 2  # €125.00
    }
  }
})
#=> {:ok, %{
#     "id" => "event_abc123",
#     "title" => "Electricity Bill",
#     "description" => "Monthly electricity payment",
#     "dueDate" => "2024-02-15",
#     "eventAmount" => %{
#       "currencyCode" => "EUR",
#       "value" => %{"unscaledValue" => 12500, "scale" => 2}
#     },
#     "reconciled" => false
#   }}

# Create income event
{:ok, salary} = Tink.FinancialCalendar.create_event(client, %{
  title: "Monthly Salary",
  due_date: "2024-02-28",
  event_amount: %{
    currency_code: "EUR",
    value: %{unscaled_value: 350000, scale: 2}  # €3,500.00
  }
})

create_reconciliation(client, event_id, params)

@spec create_reconciliation(Tink.Client.t(), String.t(), map()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Creates a reconciliation between an event and a transaction.

Links a calendar event with an actual transaction to mark it as paid/received.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID
  • params - Reconciliation parameters:
    • :transaction_id - Transaction ID to link (required)

Returns

  • {:ok, reconciliation} - Created reconciliation
  • {:error, error} - If the request fails

Examples

{:ok, reconciliation} = Tink.FinancialCalendar.create_reconciliation(
  client,
  "event_abc123",
  %{transaction_id: "9b2c283a73ba49679798cb2105571661"}
)
#=> {:ok, %{
#     "eventId" => "event_abc123",
#     "transactionId" => "9b2c283a73ba49679798cb2105571661",
#     "reconciledAt" => "2024-02-15T10:30:00Z"
#   }}

create_recurring_group(client, event_id, params)

@spec create_recurring_group(Tink.Client.t(), String.t(), map()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Creates a recurring group for an event.

Uses RFC 5545 RRULE format to define recurrence pattern.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID (becomes first event in recurring series)
  • params - Recurring parameters:
    • :rrule_pattern - RRULE pattern string (required)

Returns

  • {:ok, recurring_group} - Created recurring group
  • {:error, error} - If the request fails

Examples

# Daily for 10 days
{:ok, group} = Tink.FinancialCalendar.create_recurring_group(
  client,
  "event_abc123",
  %{rrule_pattern: "FREQ=DAILY;INTERVAL=10;COUNT=5"}
)

# Weekly for a year
{:ok, group} = Tink.FinancialCalendar.create_recurring_group(
  client,
  "event_abc123",
  %{rrule_pattern: "FREQ=WEEKLY;COUNT=52"}
)

# Monthly for a year
{:ok, group} = Tink.FinancialCalendar.create_recurring_group(
  client,
  "event_abc123",
  %{rrule_pattern: "FREQ=MONTHLY;COUNT=12"}
)

# Every 2 weeks for 6 months
{:ok, group} = Tink.FinancialCalendar.create_recurring_group(
  client,
  "event_abc123",
  %{rrule_pattern: "FREQ=WEEKLY;INTERVAL=2;COUNT=13"}
)

RRULE Pattern Format

Common patterns:

  • FREQ=DAILY;COUNT=30 - Daily for 30 days
  • FREQ=WEEKLY;COUNT=52 - Weekly for a year
  • FREQ=MONTHLY;COUNT=12 - Monthly for a year
  • FREQ=YEARLY;COUNT=5 - Yearly for 5 years
  • FREQ=DAILY;INTERVAL=2;COUNT=15 - Every 2 days, 15 times

delete_attachment(client, event_id, attachment_id)

@spec delete_attachment(Tink.Client.t(), String.t(), String.t()) ::
  :ok | {:error, Tink.Error.t()}

Deletes an attachment from a calendar event.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID
  • attachment_id - Attachment ID

Returns

  • :ok - Attachment deleted successfully
  • {:error, error} - If the request fails

Examples

:ok = Tink.FinancialCalendar.delete_attachment(
  client,
  "event_abc123",
  "attachment_xyz"
)

delete_event(client, event_id, opts \\ [])

@spec delete_event(Tink.Client.t(), String.t(), keyword()) ::
  :ok | {:error, Tink.Error.t()}

Deletes a calendar event.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID
  • opts - Delete options:
    • :recurring - How to handle recurring: "SINGLE", "ALL", "FUTURE"

Returns

  • :ok - Event deleted successfully
  • {:error, error} - If the request fails

Examples

# Delete single event
:ok = Tink.FinancialCalendar.delete_event(client, "event_abc123",
  recurring: "SINGLE"
)

# Delete all events in recurring group
:ok = Tink.FinancialCalendar.delete_event(client, "event_abc123",
  recurring: "ALL"
)

# Delete this and future events
:ok = Tink.FinancialCalendar.delete_event(client, "event_abc123",
  recurring: "FUTURE"
)

delete_reconciliation(client, event_id, transaction_id)

@spec delete_reconciliation(Tink.Client.t(), String.t(), String.t()) ::
  :ok | {:error, Tink.Error.t()}

Deletes a reconciliation.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID
  • transaction_id - Transaction ID to unlink

Returns

  • :ok - Reconciliation deleted successfully
  • {:error, error} - If the request fails

Examples

:ok = Tink.FinancialCalendar.delete_reconciliation(
  client,
  "event_abc123",
  "txn_xyz"
)

get_event(client, event_id)

@spec get_event(Tink.Client.t(), String.t()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Gets details for a specific calendar event.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID

Returns

  • {:ok, event} - Event details
  • {:error, error} - If the request fails

Examples

{:ok, event} = Tink.FinancialCalendar.get_event(client, "event_abc123")
#=> {:ok, %{
#     "id" => "event_abc123",
#     "title" => "Electricity Bill",
#     "dueDate" => "2024-02-15",
#     "eventAmount" => %{...},
#     "reconciled" => false,
#     "attachments" => [],
#     "recurringGroup" => nil
#   }}

get_reconciliation_details(client, event_id)

@spec get_reconciliation_details(Tink.Client.t(), String.t()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Gets reconciliation details for an event.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID

Returns

  • {:ok, details} - Reconciliation details
  • {:error, error} - If the request fails

Examples

{:ok, details} = Tink.FinancialCalendar.get_reconciliation_details(
  client,
  "event_abc123"
)

get_reconciliation_suggestions(client, event_id)

@spec get_reconciliation_suggestions(Tink.Client.t(), String.t()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Gets reconciliation suggestions for an event.

Returns AI-powered suggestions for matching transactions.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID

Returns

  • {:ok, suggestions} - List of suggested transactions
  • {:error, error} - If the request fails

Examples

{:ok, suggestions} = Tink.FinancialCalendar.get_reconciliation_suggestions(
  client,
  "event_abc123"
)
#=> {:ok, %{
#     "suggestions" => [
#       %{
#         "transactionId" => "txn_1",
#         "description" => "Electricity Company",
#         "amount" => 125.00,
#         "date" => "2024-02-14",
#         "confidence" => "HIGH"
#       },
#       ...
#     ]
#   }}

get_summaries(client, opts)

@spec get_summaries(
  Tink.Client.t(),
  keyword()
) :: {:ok, map()} | {:error, Tink.Error.t()}

Gets calendar summaries for a period with specified resolution.

Parameters

  • client - Tink client with user bearer token
  • opts - Query options:
    • :resolution - Time resolution: "WEEKLY", "MONTHLY" (required)
    • :period_gte - Period start (ISO-8601: "YYYY-MM-DD") (required)
    • :period_lte - Period end (ISO-8601: "YYYY-MM-DD") (required)
    • :account_id_in - Filter by accounts (list) (optional)

Returns

  • {:ok, summaries} - Calendar summaries
  • {:error, error} - If the request fails

Examples

# Get weekly summaries
{:ok, weekly} = Tink.FinancialCalendar.get_summaries(client,
  resolution: "WEEKLY",
  period_gte: "2024-02-01",
  period_lte: "2024-02-29"
)
#=> {:ok, %{
#     "resolution" => "WEEKLY",
#     "periods" => [
#       %{
#         "periodStart" => "2024-02-01",
#         "periodEnd" => "2024-02-07",
#         "totalAmount" => %{
#           "currencyCode" => "EUR",
#           "value" => %{"unscaledValue" => 45000, "scale" => 2}
#         },
#         "eventCount" => 3
#       },
#       ...
#     ]
#   }}

# Get monthly summaries for the year
{:ok, monthly} = Tink.FinancialCalendar.get_summaries(client,
  resolution: "MONTHLY",
  period_gte: "2024-01-01",
  period_lte: "2024-12-31"
)

list_events(client, opts \\ [])

@spec list_events(
  Tink.Client.t(),
  keyword()
) :: {:ok, map()} | {:error, Tink.Error.t()}

Lists calendar events with optional filtering.

Parameters

  • client - Tink client with user bearer token
  • opts - Query options:
    • :due_date_gte - Due date >= (ISO-8601: "YYYY-MM-DD")
    • :due_date_lte - Due date <= (ISO-8601: "YYYY-MM-DD")
    • :account_id_in - Filter by account IDs (list)

Returns

  • {:ok, events} - List of events
  • {:error, error} - If the request fails

Examples

# List events for February
{:ok, events} = Tink.FinancialCalendar.list_events(client,
  due_date_gte: "2024-02-01",
  due_date_lte: "2024-02-29"
)
#=> {:ok, %{
#     "events" => [
#       %{"id" => "event_1", "title" => "Rent", ...},
#       %{"id" => "event_2", "title" => "Electricity", ...}
#     ]
#   }}

# List upcoming events (next 30 days)
{:ok, upcoming} = Tink.FinancialCalendar.list_events(client,
  due_date_gte: Date.to_iso8601(Date.utc_today()),
  due_date_lte: Date.add(Date.utc_today(), 30) |> Date.to_iso8601()
)

# Filter by account
{:ok, account_events} = Tink.FinancialCalendar.list_events(client,
  due_date_gte: "2024-01-01",
  due_date_lte: "2024-12-31",
  account_id_in: ["account_1", "account_2"]
)

update_event(client, event_id, updates)

@spec update_event(Tink.Client.t(), String.t(), map()) ::
  {:ok, map()} | {:error, Tink.Error.t()}

Updates a calendar event.

Parameters

  • client - Tink client with user bearer token
  • event_id - Calendar event ID
  • updates - Fields to update:
    • :title - New title (optional)
    • :description - New description (optional)
    • :event_amount - New amount (optional)

Returns

  • {:ok, event} - Updated event
  • {:error, error} - If the request fails

Examples

{:ok, updated} = Tink.FinancialCalendar.update_event(
  client,
  "event_abc123",
  %{
    description: "Updated description",
    event_amount: %{
      currency_code: "EUR",
      value: %{unscaled_value: 13000, scale: 2}
    }
  }
)