mitgliederverwaltung/docs/vereinfacht-api.md
Moritz e879958e53
All checks were successful
continuous-integration/drone/push Build is passing
Vereinfacht: sync country with finance contact API
2026-03-04 20:16:37 +01:00

3.2 KiB

Vereinfacht API Integration

This document describes the current integration with the Vereinfacht (verein.visuel.dev) accounting API for syncing members as finance contacts.

Overview

  • Purpose: Create and update external finance contacts in Vereinfacht when members are created or updated; support bulk sync for members without a contact ID.
  • Configuration: ENV or Settings: VEREINFACHT_API_URL, VEREINFACHT_API_KEY, VEREINFACHT_CLUB_ID, optional VEREINFACHT_APP_URL for contact view links.
  • Modules: Mv.Vereinfacht (business logic), Mv.Vereinfacht.Client (HTTP client), Mv.Vereinfacht.Changes.SyncContact (Ash after_transaction change).

API Usage

Finding an existing contact by email

The API supports filtered list requests. Use a single GET instead of paginating:

  • Endpoint: GET /api/v1/finance-contacts?filter[isExternal]=true&filter[email]=<email>
  • Client: Mv.Vereinfacht.Client.find_contact_by_email/1 builds this URL (with encoded email) and returns {:ok, contact_id} if the first match exists, {:error, :not_found} otherwise.
  • No member fields are required in the app solely for this lookup.

Creating a contact

When creating an external finance contact, the API only requires:

  • Attributes: contactType (e.g. "person"), isExternal: true
  • Relationship: club (club ID from config)

Additional attributes (firstName, lastName, email, address, zipCode, city, country) are optional and are sent when present on the member so the contact is filled in. The app does not enforce extra required member fields for Vereinfacht; only Settings-based required fields and email apply.

  • Client: Mv.Vereinfacht.Client.create_contact/1 builds the JSON:API body from the member; Mv.Constants.vereinfacht_required_member_fields/0 is an empty list.

Updating a contact

  • Endpoint: PATCH /api/v1/finance-contacts/:id
  • Client: Mv.Vereinfacht.Client.update_contact/2 sends current member attributes. The API may still validate presence/format of fields on update.

Flow

  1. Member create/update: SyncContact runs after the transaction. If the member has no vereinfacht_contact_id, the client tries find_contact_by_email(email); if found, it updates that contact and stores the ID on the member; otherwise it creates a contact and stores the new ID. If the member already has a contact ID, the client updates the contact.
  2. Bulk sync: “Sync all members without Vereinfacht contact” calls Vereinfacht.sync_members_without_contact/0, which loads members with nil/blank vereinfacht_contact_id and runs the same create/update flow per member.

References

  • Config: Mv.Config (vereinfacht_api_url, vereinfacht_api_key, vereinfacht_club_id, vereinfacht_app_url, vereinfacht_configured?/0).
  • Constants: Mv.Constants.vereinfacht_required_member_fields/0 (empty), vereinfacht_required_field?/1.
  • Tests: test/mv/vereinfacht/, test/mv/config_vereinfacht_test.exs; see test/mv/vereinfacht/vereinfacht_test_README.md for scope.
  • Roadmap: Payment/transaction import and deeper integration are tracked in docs/feature-roadmap.md and docs/membership-fee-architecture.md.