My Money Vision integrations

    Two ways to connect My Money Vision to your CRM, notetaker or Zapier. Both are set up by your firm lead or office admin in Settings > Integrations.

    1. Webhooks: My Money Vision tells your system when a family does something worth a call.
    2. Invite API: your system invites a family, or checks on one, without anyone opening the dashboard.

    Webhooks

    Create one: Settings > Integrations > Add webhook. Enter an https URL, pick the events, and save. The signing secret is shown once; store it where your receiver can read it. A firm can have 3 webhooks.

    Each event is sent as a JSON POST with these headers:

    • X-MMV-Event: the event name
    • X-MMV-Delivery: the delivery id (also event_id in the body; use it to ignore a retry you already handled)
    • X-MMV-Signature: sha256= followed by the hex HMAC-SHA256 of the raw body, keyed with your signing secret

    Reply with any 2xx within 10 seconds. Anything else is tried again, 6 tries in all, waiting 2, 4, 8, 16 and 32 minutes between them. After 20 failures in a row the webhook is switched off; switch it back on in Settings.

    Events

    member.joined: a family accepted their invitation.

    { "event": "member.joined", "event_id": "4f0c...", "org_id": "9a1e...", "occurred_at": "2026-10-30T15:04:05Z",
      "member": { "id": "b2d4...", "email": "ana@example.com", "full_name": "Ana Lopez" },
      "invited_by": { "id": "77c1...", "full_name": "Dana Reed" },
      "course_instance_id": "c91f..." }

    lesson.completed: a family finished a lesson.

    { "event": "lesson.completed", "event_id": "...", "org_id": "...", "occurred_at": "...",
      "member": { "id": "...", "email": "ana@example.com", "full_name": "Ana Lopez" },
      "lesson_id": "5e2a...", "lesson_title": "Emergency fund basics", "completed_at": "2026-10-30T15:04:01Z" }

    account.opened: a family reported opening an account (for example a Roth IRA).

    { "event": "account.opened", "event_id": "...", "org_id": "...", "occurred_at": "...",
      "member": { "id": "...", "email": "ana@example.com", "full_name": "Ana Lopez" },
      "milestone_type": "roth_ira", "reported_date": "2026-10-30" }

    Verify the signature

    Node:

    const crypto = require('crypto');
    function verify(rawBody, header, secret) {
      const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
      return header.length === expected.length && crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
    }

    Python:

    import hmac, hashlib
    def verify(raw_body: bytes, header: str, secret: str) -> bool:
        expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
        return hmac.compare_digest(header, expected)

    Always verify against the raw request body, before parsing the JSON.

    Zapier recipes

    Zapier needs no My Money Vision app: "Webhooks by Zapier" catches the POST.

    Wealthbox: a note on the contact when a family finishes a lesson

    1. Trigger: Webhooks by Zapier > Catch Hook. Copy the URL Zapier gives you and add it in Settings > Integrations with only lesson.completed ticked.
    2. Action: Wealthbox > Find Contact, search by member__email.
    3. Action: Wealthbox > Create Note on that contact: "Finished {{lesson_title}} on My Money Vision ({{completed_at}})."

    Redtail: the same, in Redtail

    1. The same Catch Hook trigger.
    2. Action: Redtail CRM > Find Contact by member__email.
    3. Action: Redtail CRM > Create Note (some Redtail connections list this as an activity) with the same text.

    Use the same pattern for member.joined ("Joined My Money Vision") and account.opened ("Reported opening a {{milestone_type}}"). Zapier's Catch Hook does not check signatures; add a "Code by Zapier" step with the Node snippet above if you want it to.

    Invite API

    Create a key: Settings > Integrations > Create key. The full key (mmv_live_...) is shown once. A firm can have 5 active keys; revoke one any time.

    Endpoint: https://yxjgxyxzcypppxzarnrl.supabase.co/functions/v1/api-invite-member

    Invite a family:

    curl -X POST "$URL" -H "Authorization: Bearer $MMV_KEY" -H "Content-Type: application/json" \
      -d '{"email":"ana@example.com","first_name":"Ana","last_name":"Lopez","advisor_email":"dana@yourfirm.com"}'
    Field
    emailrequired
    first_name, last_nameoptional
    advisor_emailoptionalMust be an advisor, coach or office admin at your firm. The invitation email names them and replies go to them. Without it, the person who created the key.
    course_instance_idoptionalA course that advisor can use.
    sendoptional, default truefalse creates the invitation without emailing it.

    Responses:

    • 201: { "invitation_id", "invite_code", "signup_url", "status", "email_status" }
    • 401: missing, wrong or revoked key
    • 402: your firm has used all of its family seats
    • 409: { "error": "already_invited", "invitation_id", "status" }
    • 422: bad email, unknown advisor, or a course that advisor cannot use
    • 429: more than 60 invitations from this key in the last hour (see Retry-After)

    Check before inviting:

    curl "$URL?email=ana@example.com" -H "Authorization: Bearer $MMV_KEY"

    Returns 200 { "invitation_id", "status", "email_status", "created_at", "accepted_at", "expires_at" }, or 404 when that email has no invitation at your firm.

    The invitation email is the same one your dashboard sends. Everything a family sees is education only, never financial advice.