Connector API for ingesting accounts and transactions directly.
The Connector API allows you to bypass bank connections and directly ingest account and transaction data into Tink. This is useful for:
- Testing and development
- Custom data sources
- Legacy system integration
- Mock data scenarios
Features
- Create users programmatically
- Ingest accounts with balance information
- Ingest transactions in bulk
- Real-time and batch transaction updates
- Support for pending transactions
Prerequisites
To use the Connector API, ensure you have:
- Client credentials with appropriate scopes
- User creation permissions
Flow
# Step 1: Get access token with required scopes
client = Tink.client(
scope: "user:create,user:read,transactions:write,transactions:read,accounts:write,accounts:read"
)
# Step 2: Create user
{:ok, user} = Tink.Connector.create_user(client, %{
external_user_id: "test-user-1",
market: "GB",
locale: "en_US"
})
# Step 3: Ingest accounts
{:ok, accounts} = Tink.Connector.ingest_accounts(client, "test-user-1", %{
accounts: [
%{
external_id: "checking-001",
name: "Checking Account",
type: "CHECKING",
balance: 15000.50,
number: "1234567890"
}
]
})
# Step 4: Ingest transactions
{:ok, result} = Tink.Connector.ingest_transactions(client, "test-user-1", %{
type: "REAL_TIME",
transaction_accounts: [
%{
external_id: "checking-001",
balance: 15000.50,
transactions: [
%{
external_id: "txn-001",
amount: -45.50,
date: System.system_time(:millisecond),
description: "Grocery Store",
type: "DEFAULT",
pending: false
}
]
}
]
})Use Cases
Testing Financial Products
@spec setup_test_user_with_data() :: {:ok, map()} | {:error, Error.t()}
def setup_test_user_with_data do
client = Tink.client(scope: connector_scopes())
{:ok, user} = Tink.Connector.create_user(client, %{
external_user_id: "test-user-#{:rand.uniform(10000)}",
market: "GB",
locale: "en_US"
})
{:ok, _} = Tink.Connector.ingest_accounts(client, user["external_user_id"], %{
accounts: test_accounts()
})
{:ok, _} = Tink.Connector.ingest_transactions(
client,
user["external_user_id"],
%{type: "REAL_TIME", transaction_accounts: test_transactions()}
)
user
endLegacy System Integration
@spec sync_from_legacy_system(String.t()) :: {:ok, map()} | {:error, Error.t()}
def sync_from_legacy_system(external_user_id) do
client = Tink.client(scope: connector_scopes())
legacy_accounts = LegacyDB.get_accounts(external_user_id)
legacy_transactions = LegacyDB.get_transactions(external_user_id)
accounts = transform_accounts(legacy_accounts)
{:ok, _} = Tink.Connector.ingest_accounts(client, external_user_id, accounts)
transactions = transform_transactions(legacy_transactions)
{:ok, _} = Tink.Connector.ingest_transactions(client, external_user_id, transactions)
:ok
endMock Data for Demos
@spec create_demo_user_with_scenario(atom()) :: {:ok, map()} | {:error, Error.t()}
def create_demo_user_with_scenario(scenario_type) when is_atom(scenario_type) do
client = Tink.client(scope: connector_scopes())
scenario_str = Atom.to_string(scenario_type)
{:ok, user} = Tink.Connector.create_user(client, %{
external_user_id: "demo-#{scenario_str}",
market: "GB",
locale: "en_US"
})
case scenario_type do
:high_saver -> setup_high_saver_scenario(client, user["external_user_id"])
:overspender -> setup_overspender_scenario(client, user["external_user_id"])
:stable_income -> setup_stable_income_scenario(client, user["external_user_id"])
end
user
endRequired Scopes
user:create- Create usersuser:read- Read user dataaccounts:write- Ingest accountsaccounts:read- Read accountstransactions:write- Ingest transactionstransactions:read- Read transactions
Links
Summary
Functions
Creates a new user via the Connector API.
Ingests accounts for a user.
Ingests transactions for a user.
Functions
@spec create_user(Tink.Client.t(), map()) :: {:ok, map()} | {:error, Tink.Error.t()}
Creates a new user via the Connector API.
Parameters
client- Tink client withuser:createscopeparams- User parameters::external_user_id- Your unique user identifier (required):market- Market code (e.g., "GB", "SE") (required):locale- Locale code (e.g., "en_US", "sv_SE") (required)
Returns
{:ok, user}- Created user withuser_id{:error, error}- If the request fails
Examples
client = Tink.client(scope: "user:create")
{:ok, user} = Tink.Connector.create_user(client, %{
external_user_id: "test-user-1",
market: "GB",
locale: "en_US"
})
#=> {:ok, %{
# "user_id" => "tink_user_abc123",
# "external_user_id" => "test-user-1",
# "market" => "GB",
# "locale" => "en_US"
# }}Required Scope
user:create
@spec ingest_accounts(Tink.Client.t(), String.t(), map()) :: {:ok, map()} | {:error, Tink.Error.t()}
Ingests accounts for a user.
Creates or updates accounts with balance and metadata.
Parameters
client- Tink client withaccounts:writescopeexternal_user_id- External user IDparams- Account data::accounts- List of accounts (required)
Each account should contain:
:external_id- Unique account identifier (required):name- Account name (required):type- Account type (required):balance- Current balance (required):number- Account number (optional):available_credit- Available credit (optional):reserved_amount- Reserved/pending amount (optional):closed- Whether account is closed (optional, default: false):flags- Account flags (optional):exclusion- Exclusion settings (optional):payload- Custom metadata (optional)
Returns
{:ok, result}- Ingestion result{:error, error}- If the request fails
Examples
client = Tink.client(scope: "accounts:write")
{:ok, result} = Tink.Connector.ingest_accounts(client, "test-user-1", %{
accounts: [
%{
external_id: "checking-001",
name: "Main Checking",
type: "CHECKING",
balance: 15000.50,
number: "1234567890",
available_credit: 0.0,
reserved_amount: 100.0,
closed: false,
flags: [],
exclusion: "NONE",
payload: %{}
},
%{
external_id: "savings-001",
name: "Savings Account",
type: "SAVINGS",
balance: 50000.0,
number: "9876543210",
closed: false
},
%{
external_id: "credit-001",
name: "Credit Card",
type: "CREDIT_CARD",
balance: -2500.0,
available_credit: 20000.0,
number: "4111111111111111"
}
]
})Account Types
CHECKING- Checking/current accountSAVINGS- Savings accountCREDIT_CARD- Credit cardLOAN- Loan accountPENSION- Pension/retirementINVESTMENT- Investment accountMORTGAGE- MortgageOTHER- Other account type
Flags
MANDATE- Account has mandateBUSINESS- Business accountEXTERNAL- External account
Exclusion
NONE- Include in all featuresPFM- Exclude from PFMSEARCH- Exclude from searchPFM_AND_SEARCH- Exclude from both
Required Scope
accounts:write
@spec ingest_transactions(Tink.Client.t(), String.t(), map()) :: {:ok, map()} | {:error, Tink.Error.t()}
Ingests transactions for a user.
Creates or updates transactions with real-time or batch processing.
Parameters
client- Tink client withtransactions:writescopeexternal_user_id- External user IDparams- Transaction data::type- Update type: "REAL_TIME" or "BATCH" (required):transaction_accounts- List of accounts with transactions (required):auto_book- Auto-book pending transactions (optional, default: false):override_pending- Override pending transactions (optional, default: false)
Each transaction_account should contain:
:external_id- Account external ID (required):balance- Updated account balance (required):reserved_amount- Reserved amount (optional):transactions- List of transactions (required)
Each transaction should contain:
:external_id- Unique transaction ID (required):amount- Transaction amount (negative for expenses) (required):date- Transaction timestamp in milliseconds (required):description- Transaction description (required):type- Transaction type (required):pending- Whether transaction is pending (optional, default: false):payload- Custom metadata (optional)
Returns
{:ok, result}- Ingestion result{:error, error}- If the request fails
Examples
client = Tink.client(scope: "transactions:write")
# Real-time transaction ingestion
{:ok, result} = Tink.Connector.ingest_transactions(client, "test-user-1", %{
type: "REAL_TIME",
auto_book: false,
override_pending: false,
transaction_accounts: [
%{
external_id: "checking-001",
balance: 14955.0,
reserved_amount: 0.0,
transactions: [
%{
external_id: "txn-#{System.unique_integer([:positive])}",
amount: -45.50,
date: System.system_time(:millisecond),
description: "Coffee Shop",
type: "DEFAULT",
pending: false,
payload: %{merchant: "Starbucks"}
}
]
}
]
})
# Batch transaction ingestion
{:ok, result} = Tink.Connector.ingest_transactions(client, "test-user-1", %{
type: "BATCH",
transaction_accounts: [
%{
external_id: "checking-001",
balance: 15000.0,
transactions: generate_month_of_transactions()
}
]
})Transaction Types
DEFAULT- Standard transactionCREDIT_CARD- Credit card transactionTRANSFER- Transfer between accountsPAYMENT- Payment transactionWITHDRAWAL- Cash withdrawalDEPOSIT- Deposit
Update Types
REAL_TIME
- Immediate processing
- Updates balances in real-time
- Use for live transaction feeds
BATCH
- Bulk processing
- Efficient for large datasets
- Use for historical data import
Required Scope
transactions:write