# `Tink.Connector`
[🔗](https://github.com/iamkanishka/tink.ex/blob/v0.1.1/lib/tink/connector.ex#L1)

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
    end

### Legacy 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
    end

### Mock 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
    end

## Required Scopes

- `user:create` - Create users
- `user:read` - Read user data
- `accounts:write` - Ingest accounts
- `accounts:read` - Read accounts
- `transactions:write` - Ingest transactions
- `transactions:read` - Read transactions

## Links

- [Connector API Documentation](https://docs.tink.com/api/connector)
- [Testing Guide](https://docs.tink.com/resources/testing)

# `create_user`

```elixir
@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 with `user:create` scope
  * `params` - 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 with `user_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`

# `ingest_accounts`

```elixir
@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 with `accounts:write` scope
  * `external_user_id` - External user ID
  * `params` - 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 account
- `SAVINGS` - Savings account
- `CREDIT_CARD` - Credit card
- `LOAN` - Loan account
- `PENSION` - Pension/retirement
- `INVESTMENT` - Investment account
- `MORTGAGE` - Mortgage
- `OTHER` - Other account type

## Flags

- `MANDATE` - Account has mandate
- `BUSINESS` - Business account
- `EXTERNAL` - External account

## Exclusion

- `NONE` - Include in all features
- `PFM` - Exclude from PFM
- `SEARCH` - Exclude from search
- `PFM_AND_SEARCH` - Exclude from both

## Required Scope

`accounts:write`

# `ingest_transactions`

```elixir
@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 with `transactions:write` scope
  * `external_user_id` - External user ID
  * `params` - 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 transaction
- `CREDIT_CARD` - Credit card transaction
- `TRANSFER` - Transfer between accounts
- `PAYMENT` - Payment transaction
- `WITHDRAWAL` - Cash withdrawal
- `DEPOSIT` - 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`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
