Tink.WebhookHandler (Tink v0.1.1)

Copy Markdown View Source

Handler for Tink API webhooks.

Tink sends webhooks for various events like:

  • User credentials updated
  • Transaction data refreshed
  • Account data changed
  • Credential errors

Setup

  1. Configure webhook secret in your application:

    config :tink, webhook_secret: System.get_env("TINK_WEBHOOK_SECRET")

  2. Create a webhook endpoint in your Phoenix app:

    defmodule MyAppWeb.TinkWebhookController do use MyAppWeb, :controller

    def handle(conn, params) do

     signature = get_req_header(conn, "x-tink-signature") |> List.first()
     body = conn.assigns.raw_body  # You need to capture raw body
    
     case Tink.WebhookHandler.handle_webhook(body, signature) do
       {:ok, event} ->
         # Process event
         process_webhook_event(event)
         send_resp(conn, 200, "OK")
    
       {:error, :invalid_signature} ->
         send_resp(conn, 401, "Invalid signature")
    
       {:error, reason} ->
         send_resp(conn, 400, "Bad request: #{reason}")
     end

    end end

  3. Register webhook handlers:

    Tink.WebhookHandler.register_handler(:credentials_updated, &handle_credentials_update/1)

Webhook Events

Tink sends the following event types:

  • credentials.updated - Credentials were updated
  • credentials.refresh.succeeded - Data refresh succeeded
  • credentials.refresh.failed - Data refresh failed
  • provider_consents.created - Consent was created
  • provider_consents.revoked - Consent was revoked

Examples

# Handle webhook in controller
def webhook(conn, _params) do
  signature = get_req_header(conn, "x-tink-signature") |> List.first()
  body = conn.assigns.raw_body

  case Tink.WebhookHandler.handle_webhook(body, signature) do
    {:ok, event} ->
      MyApp.Webhooks.process(event)
      send_resp(conn, 200, "OK")

    {:error, :invalid_signature} ->
      send_resp(conn, 401, "Unauthorized")
  end
end

# Register event handlers
Tink.WebhookHandler.register_handler(:credentials_updated, fn event ->
  # Update user's credential status
  Users.update_credential_status(event["userId"], :updated)
end)

Verification

Webhooks are verified using HMAC-SHA256 signature.

Summary

Functions

Gets all registered handlers grouped by event type.

Handles an incoming webhook request.

Registers a handler function for a specific event type.

Unregisters all handlers for an event type.

Types

event()

@type event() :: %{
  type: event_type(),
  data: map(),
  timestamp: DateTime.t(),
  raw: map()
}

event_type()

@type event_type() ::
  :credentials_updated
  | :credentials_refresh_succeeded
  | :credentials_refresh_failed
  | :provider_consents_created
  | :provider_consents_revoked
  | :unknown

handler_function()

@type handler_function() :: (event() -> term())

Functions

get_handlers()

@spec get_handlers() :: %{required(event_type()) => [handler_function()]}

Gets all registered handlers grouped by event type.

Examples

handlers = Tink.WebhookHandler.get_handlers()
#=> %{credentials_updated: [#Function<...>]}

handle_webhook(body, signature)

@spec handle_webhook(String.t(), String.t()) :: {:ok, event()} | {:error, atom()}

Handles an incoming webhook request.

Verifies the signature, validates the payload structure, guards against test webhooks, and parses the event.

Parameters

  • body - Raw webhook request body (JSON string)
  • signature - Webhook signature from X-Tink-Signature header

Returns

  • {:ok, event} - Successfully parsed and verified webhook
  • {:error, :invalid_signature} - Signature verification failed
  • {:error, :invalid_payload} - Failed to parse webhook body
  • {:error, :test_webhook} - Payload is a Tink test ping (acknowledged, not dispatched)

Examples

{:ok, event} = Tink.WebhookHandler.handle_webhook(body, signature)
#=> {:ok, %{type: :credentials_updated, data: %{...}}}

register_handler(event_type, handler_fun)

@spec register_handler(event_type(), handler_function()) :: :ok

Registers a handler function for a specific event type.

Uses an ETS :bag table for concurrent-safe registration.

Parameters

  • event_type - Type of event to handle
  • handler_fun - Function to call when event is received (arity 1)

Examples

Tink.WebhookHandler.register_handler(:credentials_updated, fn event ->
  Logger.info("Credentials updated for user: #{event.data["userId"]}")
  MyApp.Users.sync_credentials(event.data["userId"])
end)

unregister_handlers(event_type)

@spec unregister_handlers(event_type()) :: :ok

Unregisters all handlers for an event type.

Examples

Tink.WebhookHandler.unregister_handlers(:credentials_updated)