All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

1.0.0 - 2026-08-08

Added

Core infrastructure

  • PlaidEx.Config — NimbleOptions-validated configuration with runtime injection support
  • PlaidEx.HTTP.Client — Req + Finch HTTP client with full jitter backoff, idempotency, and OpenTelemetry spans
  • PlaidEx.HTTP.RateLimiter — ETS token bucket rate limiter with per-tenant isolation
  • PlaidEx.Error — Typed error struct with retry classification, reauthentication detection, and telemetry-safe serialization

API coverage

Reliability

Transaction sync

Webhooks

Multi-tenant

OAuth

Schemas

  • Typed structs for: Account, Transaction, TransactionSyncPage, Item, Institution, Transfer, LinkToken, AccessToken, InvestmentHolding, Security, IdentityData

Observability

Testing

  • PlaidEx.Test.BypassHelpers — Bypass stubs for all major endpoints with realistic fixtures
  • PlaidEx.Test.MockPlaidServer — Full mock Plaid server for integration testing
  • PlaidEx.Test.MockPlaidServer.build_webhook/3 — Typed webhook payload builders
  • PlaidEx.Test.MockPlaidServer.build_signed_webhook/2 — HMAC-signed webhook builder

CI/CD

  • GitHub Actions workflow with matrix testing (Elixir 1.17/1.18, OTP 27/28)
  • Automatic Hex.pm publishing on git tag
  • Dialyzer PLT caching
  • ExCoveralls integration

Changed

  • N/A (initial release)

Deprecated

  • N/A (initial release)

Removed

  • N/A (initial release)

Fixed

  • N/A (initial release)

Security

  • Webhook secrets are never logged (scrubbed in telemetry metadata)
  • Access tokens are masked in log output (only first 20 chars shown)
  • Config.scrub/1 redacts secrets for safe logging

Upgrade Guide

From plaid (the other Elixir Plaid library)

# Before (plaid library):
{:ok, %{"accounts" => accounts}} = Plaid.Accounts.get("access-...")

# After (plaid_ex):
{:ok, %{accounts: accounts}} = PlaidEx.API.Accounts.get(config, "access-...")
# accounts is now [%PlaidEx.Schemas.Account{}] — typed structs

Key differences:

  1. Typed structs — responses are typed structs, not raw maps
  2. Explicit config — pass a PlaidEx.Config struct (enables multi-tenant)
  3. Error structs — errors are PlaidEx.Error structs with retry metadata
  4. Automatic sync — use PlaidEx.start_transaction_sync/2 instead of manual polling