{
  "id": "qVcggoinRQjDDDO3",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true,
    "templateCredsSetupCompleted": true
  },
  "name": "Risk n8n Automation (All 3 Worklows) v2",
  "tags": [],
  "nodes": [
    {
      "id": "99aad377-8351-4ffd-a86f-b5f39d084789",
      "name": "Monthly on the 1st",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -432,
        624
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "months",
              "triggerAtHour": 6
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "f1ebcd71-dcb8-4283-9a03-066ee21ea22c",
      "name": "Initialize Run",
      "type": "n8n-nodes-base.set",
      "position": [
        -224,
        624
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "run-month",
              "name": "run_month",
              "type": "string",
              "value": "={{ $now.toFormat(\"yyyy-MM\") }}"
            },
            {
              "id": "run-id",
              "name": "run_id",
              "type": "string",
              "value": "={{ $execution.id }}"
            },
            {
              "id": "triggered-at",
              "name": "triggered_at",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4ae67652-17e5-479a-8a2d-90ee6f32d6b0",
      "name": "Supabase: Get Active Merchants",
      "type": "n8n-nodes-base.supabase",
      "position": [
        800,
        -192
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "status",
              "keyValue": "active",
              "condition": "eq"
            }
          ]
        },
        "tableId": "merchants",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5c44d915-9fa0-46bb-b756-8def8b2f2881",
      "name": "Code: Distinct MCCs + Top Accounts",
      "type": "n8n-nodes-base.code",
      "position": [
        1024,
        -192
      ],
      "parameters": {
        "jsCode": "const merchants = $input.all().map(i => i.json);\nconst counts = {};\nconst samples = {};\nfor (const m of merchants) {\n  if (!m.mcc_code) continue;\n  counts[m.mcc_code] = (counts[m.mcc_code] || 0) + 1;\n  samples[m.mcc_code] = samples[m.mcc_code] || [];\n  if (samples[m.mcc_code].length < 5) samples[m.mcc_code].push(m.name);\n}\nreturn Object.entries(counts).map(([mcc, count]) => ({\n  mcc,\n  account_count: count,\n  top_accounts: samples[mcc]\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "0001a998-675a-4500-be7b-0f35d881b3b3",
      "name": "Merge: Merchants + MCC Codes",
      "type": "n8n-nodes-base.merge",
      "position": [
        1312,
        -96
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "advanced": true,
        "mergeByFields": {
          "values": [
            {
              "field1": "mcc",
              "field2": "code"
            }
          ]
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "ad5a0ba0-98bf-415a-8594-6ed9c715b52f",
      "name": "Supabase: Get MCC Codes",
      "type": "n8n-nodes-base.supabase",
      "position": [
        960,
        0
      ],
      "parameters": {
        "tableId": "mcc_codes",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d4f675e5-271a-41b5-accd-9c6beb30eaaf",
      "name": "Perplexity: MCC News (30d)",
      "type": "n8n-nodes-base.perplexity",
      "position": [
        1600,
        -96
      ],
      "parameters": {
        "query": "=What significant developments happened in the {{ $json.industry }} industry (MCC Code {{ $json.code }})\nin the last 30 days that would matter to a payment-processing risk team?\n\nCover, with specific names, dates, and sources:\n\n1. Federal or state government actions \u2014 regulatory rulings, agency\n   enforcement, new legislation, proposed rules. Specify the agency\n   (DOT, FAA, FTC, CFPB, SEC, FDA, DEA, etc.).\n\n2. Industry health \u2014 bankruptcies, Chapter 11 filings, major company\n   distress, consolidation, mass layoffs of meaningful players.\n\n3. Demand-side trends \u2014 consumer behavior shifts, declining usage,\n   pricing pressure, macro factors affecting this industry.\n\n4. Card-brand actions or chargeback monitoring program changes\n   (Visa VDMP, Mastercard ECP) for this MCC.\n\n5. Material litigation against the industry or key players.\n\nBe specific and source everything. If there's no news in a category,\nsay so explicitly.",
        "options": {
          "searchAfterDate": "={{ $now.minus({ days: 30 }).toFormat(\"MM/dd/yyyy\") }}"
        },
        "resource": "search",
        "requestOptions": {}
      },
      "credentials": {
        "perplexityApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "fa7a0f20-86ab-40d5-aaa2-b0f1aa022cd2",
      "name": "AI Agent: MCC Risk Rating",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1824,
        -96
      ],
      "parameters": {
        "text": "=You are a senior risk analyst at Sentinel Payments evaluating the {{ $('Merge: Merchants + MCC Codes').item.json.industry }} industry (MCC {{ $('Merge: Merchants + MCC Codes').item.json.code }}) for this month's risk review.\n\nVisa's baseline risk rating for this MCC: {{ $('Merge: Merchants + MCC Codes').item.json.mcc_risk_score }} out of 5.\n\nRecent industry research:\n{{ $json.results.map(r => '[' + r.date + '] ' + r.title + '\\nSource: ' + r.url + '\\n' + r.snippet).join('\\n\\n---\\n\\n') }}\n\nYour task: assess the current risk for this industry based on the research above. Consider both the baseline MCC risk AND the direction the industry is moving right now.\n\nProduce:\n- rating: 1 (very low) to 5 (very high)\n- direction: improving, stable, or deteriorating\n- summary: a TWO-SENTENCE summary, maximum 400 characters total, of what is moving and why Sentinel should care\n- key_flags: exactly 3 flags, each with category (govt_action, industry_health, demand, card_brand, litigation), a one-line headline (maximum 110 characters - this is rendered as a single bullet on a slide), and a source\n- rec_action: monitor, document_request, reserve_review, or escalate\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSLIDE OUTPUT CONSTRAINTS (HARD LIMITS - the Risk Committee deck has fixed slide real estate)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n- summary: \u2264 400 characters, ending with a period. Two short sentences.\n- key_flags[].headline: \u2264 110 characters, one line, no trailing ellipsis.\n- Exactly 3 key flags - no more, no fewer.\n\nBe specific. Tie findings to the research provided. Do not invent details. Write tight - every word must earn its place.",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "4a2cfe9f-6f0b-4d2c-8186-c4d375fe3a44",
      "name": "Claude: MCC Agent",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1824,
        128
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.5
    },
    {
      "id": "97b426d4-e1b0-473c-8de1-8bcc1bba9b65",
      "name": "Parser: MCC Snapshot",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1984,
        112
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"rating\": 3,\n  \"direction\": \"stable\",\n  \"summary\": \"Two sentences max. \u2264 400 chars total. Covers what is moving and why Sentinel should care.\",\n  \"key_flags\": [\n    {\n      \"category\": \"govt_action\",\n      \"headline\": \"One-line description, \u2264 110 characters - reads cleanly on a slide bullet\",\n      \"source\": \"URL or publication name\"\n    }\n  ],\n  \"rec_action\": \"monitor\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "5485ab1e-5147-40f0-bbb4-3d25b6e53595",
      "name": "Supabase: Upsert MCC Snapshot",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2304,
        -96
      ],
      "parameters": {
        "tableId": "mcc_risk_snapshots",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "month",
              "fieldValue": "={{ $now.toFormat(\"yyyy-MM\") }}"
            },
            {
              "fieldId": "mcc",
              "fieldValue": "={{ $('Merge: Merchants + MCC Codes').item.json.code }}"
            },
            {
              "fieldId": "account_count",
              "fieldValue": "={{ $('Merge: Merchants + MCC Codes').item.json.account_count }}"
            },
            {
              "fieldId": "risk_rating",
              "fieldValue": "={{ $json.output.rating }}"
            },
            {
              "fieldId": "news_summary",
              "fieldValue": "={{ $json.output.summary }}"
            },
            {
              "fieldId": "key_flags",
              "fieldValue": "={{ JSON.stringify($json.output.key_flags) }}"
            },
            {
              "fieldId": "top_accounts",
              "fieldValue": "={{ JSON.stringify($('Merge: Merchants + MCC Codes').item.json.top_accounts) }}"
            },
            {
              "fieldId": "direction",
              "fieldValue": "={{ $json.output.direction }}"
            },
            {
              "fieldId": "rec_action",
              "fieldValue": "={{ $json.output.rec_action }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8e5c8d36-28be-4a00-9d3d-dbd205c6947f",
      "name": "Aggregate MCC Snapshots",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2704,
        -96
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "mcc_snapshots"
      },
      "typeVersion": 1
    },
    {
      "id": "b0e00ad5-05c3-438e-a882-c8db609cde98",
      "name": "Merge: All Branches",
      "type": "n8n-nodes-base.merge",
      "position": [
        3552,
        944
      ],
      "parameters": {
        "numberInputs": 3
      },
      "typeVersion": 3.2
    },
    {
      "id": "93ba5c34-97b9-4579-8ac7-52cfd25ec606",
      "name": "Supabase: Get High-Risk Merchants",
      "type": "n8n-nodes-base.supabase",
      "position": [
        448,
        976
      ],
      "parameters": {
        "tableId": "monthly_metrics",
        "operation": "getAll",
        "returnAll": true,
        "filterType": "string",
        "filterString": "=month=eq.{{ $now.toFormat(\"yyyy-MM\") }}&or=(cb_rate.gte.0.009,refund_rate.gte.0.10,exposure_score.gte.4)"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7eb85560-2418-4b02-994c-947a232c00e1",
      "name": "OpenSanctions: Company Screen",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        976,
        416
      ],
      "parameters": {
        "url": "https://api.opensanctions.org/search/default",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ '\"' + $json.name + '\"' }}"
            },
            {
              "name": "limit",
              "value": "5"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "c3243dd7-2dd5-4058-bedd-e0c34f4fffa9",
      "name": "Merge: Merchant Findings",
      "type": "n8n-nodes-base.merge",
      "position": [
        1456,
        864
      ],
      "parameters": {
        "numberInputs": 7
      },
      "typeVersion": 3.2
    },
    {
      "id": "55c73934-c490-4db0-a8ad-783ed6459e28",
      "name": "OpenSanctions: Owner Screen",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        960,
        592
      ],
      "parameters": {
        "url": "https://api.opensanctions.org/search/default",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ '\"' + $json.owner_name + '\"' }}"
            },
            {
              "name": "limit",
              "value": "5"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "3a81263d-9e4d-4a93-8446-d15f439bfa1f",
      "name": "CourtListener: Company Cases",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        960,
        784
      ],
      "parameters": {
        "url": "https://www.courtlistener.com/api/rest/v4/search/",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 4,
              "batchInterval": 65000
            }
          },
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ '\"' + $json.name + '\"' }}"
            },
            {
              "name": "type",
              "value": "o"
            },
            {
              "name": "filed_after",
              "value": "={{ $now.minus({ days: 30 }).toFormat(\"yyyy-MM-dd\") }}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "ecd6b08a-e57e-4068-b803-c97b22d70f95",
      "name": "CourtListener: Owner Cases",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        960,
        976
      ],
      "parameters": {
        "url": "https://www.courtlistener.com/api/rest/v4/search/",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 4,
              "batchInterval": 65000
            }
          },
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ '\"' + $json.owner_name + '\"' }}"
            },
            {
              "name": "type",
              "value": "o"
            },
            {
              "name": "filed_after",
              "value": "={{ $now.minus({ days: 30 }).toFormat(\"yyyy-MM-dd\") }}"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "701c2aaa-5bb8-48fd-9653-d2b501e7b478",
      "name": "Apify: Google Reviews",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        960,
        1168
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "url",
          "value": "https://console.apify.com/actors/nwua9Gu5YrADL7ZDj"
        },
        "timeout": {},
        "operation": "Run actor and get dataset",
        "customBody": "={\n  \"searchStringsArray\": [\"{{ $json.name }}\"],\n  \"maxCrawledPlacesPerSearch\": 1,\n  \"maxReviews\": 50,\n  \"language\": \"en\",\n  \"reviewsSort\": \"newest\",\n  \"reviewsStartDate\": \"{{ $now.minus({ days: 30 }).toFormat('yyyy-MM-dd') }}\"\n}"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "89e21f0b-a9de-47bd-8fc8-72ce9930234a",
      "name": "Tavily: Adverse Media",
      "type": "@tavily/n8n-nodes-tavily.tavily",
      "position": [
        960,
        1360
      ],
      "parameters": {
        "query": "=Research the owner of {{ $json.name }}, whose listed beneficial owner is {{ $json.owner_name }}.\n\nAny negative news for either the name of the business or owner. ",
        "options": {
          "topic": "news",
          "time_range": "month"
        }
      },
      "credentials": {
        "tavilyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "78fe14cb-b309-4ec2-9f46-4197b10cfcc8",
      "name": "Firecrawl: Scrape Merchant Site",
      "type": "@mendable/n8n-nodes-firecrawl.firecrawl",
      "position": [
        768,
        1584
      ],
      "parameters": {
        "url": "={{ $json.website }}",
        "operation": "scrape",
        "requestOptions": {}
      },
      "credentials": {
        "firecrawlApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "463d6add-d4fb-4afd-a9eb-eb587ec2ffd9",
      "name": "AI Agent: Classify Website",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        992,
        1584
      ],
      "parameters": {
        "text": "=Analyze this merchant website content. Identify restricted verticals (marijuana, CBD, kratom, GLP-1, gambling, payday lending, firearms, adult content, supplements making unsupported claims). Identify primary business vertical and red flags. Site content (markdown): {{ ($json.data && $json.data.markdown) ? $json.data.markdown.slice(0, 8000) : \"\" }}. Respond as JSON: {\"primary_vertical\": \"...\", \"restricted_verticals_found\": [], \"red_flags\": [], \"notes\": \"...\"}",
        "options": {
          "systemMessage": "You are a payments-risk analyst classifying merchant websites for restricted content. Output only valid JSON."
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "e8062a94-7c9d-4e14-9955-09da4aac18e0",
      "name": "Claude: Website Classifier",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        992,
        1776
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.5
    },
    {
      "id": "0d883dca-875b-4db0-ad5b-348f65eb9e61",
      "name": "Aggregate Merchant Findings",
      "type": "n8n-nodes-base.code",
      "position": [
        1696,
        944
      ],
      "parameters": {
        "jsCode": "// Loop over each high-risk merchant and stitch parallel branch findings together.\nconst merchants = $('Supabase: Get High-Risk Merchants').all().map(i => i.json);\n\nreturn merchants.map((merchant, idx) => {\n  const ofacByCompany = $('OpenSanctions: Company Screen').all()[idx]?.json    || {};\n  const ofacByOwner   = $('OpenSanctions: Owner Screen').all()[idx]?.json   || {};\n  const courtCompany  = $('CourtListener: Company Cases').all()[idx]?.json || {};\n  const courtOwner    = $('CourtListener: Owner Cases').all()[idx]?.json   || {};\n  const apifyRaw      = $('Apify: Google Reviews').all()[idx]?.json  || {};\n  const adverseRaw    = $('Tavily: Adverse Media').all()[idx]?.json                         || {};\n  const firecrawl     = $('Firecrawl: Scrape Merchant Site').all()[idx]?.json || {};\n  const classify      = $('AI Agent: Classify Website').all()[idx]?.json?.output             || {};\n\n  const allOfacResults = [\n    ...(ofacByCompany.results || []).map(r => ({ ...r, queried_for: 'company' })),\n    ...(ofacByOwner.results   || []).map(r => ({ ...r, queried_for: 'owner'   }))\n  ];\n\n  const place = apifyRaw.title\n    ? apifyRaw\n    : (Array.isArray(apifyRaw) ? apifyRaw[0] : {}) || {};\n  const allReviews = place.reviews || [];\n  const lowReviews = allReviews.filter(r => (r.stars || 5) <= 2);\n\n  return {\n    merchant_id: merchant.merchant_id,\n    name: merchant.name,\n    owner_name: merchant.owner_name,\n    mcc: merchant.mcc,\n    website: merchant.website,\n    metrics: {\n      cb_rate: merchant.cb_rate,\n      refund_rate: merchant.refund_rate,\n      exposure_score: merchant.exposure_score\n    },\n    ofac_pep_hits: allOfacResults.map(r => ({\n      name: r.caption,\n      datasets: r.datasets,\n      score: r.score,\n      queried_for: r.queried_for\n    })),\n    site_classification: classify,\n    litigation_company: {\n      count: courtCompany.count || 0,\n      cases: (courtCompany.results || []).slice(0, 5).map(r => ({\n        caseName: r.caseName, court: r.court, dateFiled: r.dateFiled\n      }))\n    },\n    litigation_owner: {\n      count: courtOwner.count || 0,\n      cases: (courtOwner.results || []).slice(0, 5).map(r => ({\n        caseName: r.caseName, court: r.court, dateFiled: r.dateFiled\n      }))\n    },\n    google_reviews: {\n      place_name: place.title,\n      address: place.address,\n      rating: place.totalScore,\n      review_count: place.reviewsCount,\n      negative_reviews: lowReviews.slice(0, 5).map(r => ({\n        stars: r.stars, text: r.text, date: r.publishedAtDate\n      }))\n    },\n    adverse_media: (adverseRaw.results || []).map(r => ({\n      title: r.title, snippet: r.snippet, url: r.url, date: r.date\n    })),\n    findings_summary:\n      `Merchant: ${merchant.name} (owner ${merchant.owner_name || 'unknown'}). ` +\n      `MCC ${merchant.mcc}. CB rate ${merchant.cb_rate}. ` +\n      `Risk score ${merchant.exposure_score}. ` +\n      `Site vertical: ${classify.primary_vertical || 'unknown'}. ` +\n      `Restricted verticals found: ${(classify.restricted_verticals_found || []).join(', ') || 'none'}. ` +\n      `OFAC/PEP hits: ${allOfacResults.length} (company query: ${(ofacByCompany.results || []).length}, owner query: ${(ofacByOwner.results || []).length}). ` +\n      `Litigation (company): ${courtCompany.count || 0}. ` +\n      `Litigation (owner): ${courtOwner.count || 0}. ` +\n      `Adverse media hits: ${(adverseRaw.results || []).length}.`\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "1ff17484-d8e6-4264-a055-33cb287953bd",
      "name": "AI Agent: Risk Recommendation",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2064,
        944
      ],
      "parameters": {
        "text": "=You are a senior risk analyst at Sentinel Payments \u2014 a mid-market US payment processor \u2014 evaluating a merchant in our portfolio for the monthly risk review. Your job is to recommend ONE action for this merchant, grounded in Sentinel policy and our history of prior Risk Committee decisions. You recommend; the Risk Committee decides.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nMERCHANT UNDER REVIEW\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nMerchant: {{ $json.name }} (ID {{ $json.merchant_id }})\nOwner: {{ $json.owner_name }}\nMCC: {{ $json.mcc }}\nCurrent month metrics:\n  - Chargeback rate: {{ $json.metrics.cb_rate }}\n  - Refund rate: {{ $json.metrics.refund_rate }}\n  - Internal risk score: {{ $json.metrics.exposure_score }} / 5\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nEVIDENCE GATHERED THIS MONTH (from external sources)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nOFAC / PEP screening (OpenSanctions):\n{{ JSON.stringify($json.ofac_pep_hits) }}\n\nWebsite content classification (Firecrawl + Claude):\n  - Primary vertical: {{ $json.site_classification.primary_vertical }}\n  - Restricted verticals found: {{ JSON.stringify($json.site_classification.restricted_verticals_found) }}\n  - Red flags: {{ JSON.stringify($json.site_classification.red_flags) }}\n  - Notes: {{ $json.site_classification.notes }}\n\nLitigation searches (CourtListener):\n  - By company name: {{ $json.litigation_company.count }} cases \u2014 {{ JSON.stringify($json.litigation_company.cases) }}\n  - By owner name: {{ $json.litigation_owner.count }} cases \u2014 {{ JSON.stringify($json.litigation_owner.cases) }}\n\nPublic reviews (Google via Apify):\n  - Rating: {{ $json.google_reviews.rating }} ({{ $json.google_reviews.review_count }} reviews)\n  - Negative review sample: {{ JSON.stringify($json.google_reviews.negative_reviews) }}\n\nAdverse media (Tavily \u2014 negative news on business + owner):\n{{ JSON.stringify($json.adverse_media) }}\n\nFindings summary: {{ $json.findings_summary }}\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSENTINEL RISK POLICY (these ARE the rules \u2014 apply them)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n\u25b8 RESERVE POLICY BY MCC TIER\n  Base rolling reserve by MCC risk tier (1-5):\n    Tier 1 (very low):  no reserve required if CB rate < 0.3%\n    Tier 2 (low):       3% rolling reserve, 30-day\n    Tier 3 (moderate):  6% rolling reserve, 60-day\n    Tier 4 (elevated): 10% rolling reserve, 90-day, monthly Risk review\n    Tier 5 (high):     15% reserve floor, case-by-case ceiling, quarterly Risk Committee review\n\n\u25b8 CHARGEBACK THRESHOLD PLAYBOOK\n  Two consecutive months at these bands trigger action:\n    < 0.3%        \u2014 no action\n    0.3%-0.5%     \u2014 informational monitoring; flag for next-month review\n    0.5%-0.7%     \u2014 formal documentation request via Risk Analyst; reserve review\n    0.7%-0.9%     \u2014 mandatory reserve increase per MCC tier; consider rolling_hold_30d\n    0.9%-1.0%     \u2014 Visa VDMP threshold reached; rolling_hold_30d + reserve at MCC tier ceiling; Risk Analyst review\n    \u2265 1.0%        \u2014 escalate to Risk Committee for offboarding decision\n\n\u25b8 REFUND RATE MONITORING STANDARDS\n  Standard bands (two consecutive months):\n    < 2%             \u2014 normal; no action\n    2%-4%            \u2014 informational monitoring\n    4%-6%            \u2014 formal documentation request via Risk Analyst\n    6%-8%            \u2014 reserve review + service-quality investigation\n    8%-12%           \u2014 escalate to Risk Analyst for service-quality / fraud investigation\n    > 12% sustained  \u2014 escalate to Risk Committee for offboarding decision\n    > 15% any single month \u2014 immediate investigation + processing hold pending Risk Committee review\n\n  Vertical-specific refund modifier:\n    For MCC 5968 (Continuity / Subscription Merchants) and MCC 5499 (Misc Food Stores\n    \u2014 supplements, wellness, specialty), refund-rate thresholds shift up by 3 percentage\n    points before triggering action.\n\n\u25b8 RESTRICTED BUSINESS TYPES POLICY (STRICT LIABILITY)\n  Sentinel will NOT process for: marijuana (THC), kratom, unlicensed GLP-1 prescribing,\n  unlicensed payday lending, FFL-noncompliant firearms, supplements making unsupported\n  FDA claims, illegal gambling, non-consent adult content. CBD is permitted ONLY under\n  MCC 5912 with proper pharmacy licensing \u2014 never under MCC 5462, 5499, 5814, or any\n  non-pharmacy MCC.\n\n  CRITICAL: Restricted product found via site classification under a non-matching MCC\n  is grounds for IMMEDIATE escalate_offboarding regardless of other metrics.\n\n\u25b8 BENEFICIAL OWNER RE-SCREENING POLICY (\u00a74.2)\n  All beneficial owners are re-screened monthly against OFAC SDN, PEP lists, and\n  Sentinel's internal offboarded-entity registry. ANY name match against a BO who\n  appears in a prior Sentinel offboarding decision triggers MANDATORY escalation.\n\n\u25b8 OFAC / PEP HIT HANDLING\n  Positive OFAC SDN match (exact or fuzzy confidence \u22650.85) = immediate processing\n  hold + escalate to Sentinel Compliance.\n\n\u25b8 WEBSITE VERTICAL DRIFT POLICY\n  Drift into restricted territory = treated as misclassification and grounds for\n  escalate_offboarding per Restricted Business Types Policy.\n\n\u25b8 LITIGATION DISCLOSURE POLICY\n  Material pending litigation involving fraud, consumer protection violations, or\n  breach of fiduciary duty triggers documentation request via Risk Analyst.\n\n\u25b8 ACTION RECOMMENDATION FRAMEWORK\n  Recommend exactly ONE action per merchant per cycle:\n    no_action            \u2014 monitor only\n    request_docs         \u2014 formal request for updated processing volumes\n    raise_reserve        \u2014 increase rolling reserve % per MCC tier ceiling\n    rolling_hold_30d     \u2014 apply 30-day rolling settlement hold\n    escalate_offboarding \u2014 refer to Risk Committee for offboarding decision\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nPRIOR DECISIONS TOOL (Pinecone)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nUse the Pinecone tool to retrieve Sentinel's prior Risk Committee decisions on\nmerchants with comparable characteristics.\n\nTOOL CALL DISCIPLINE:\n- Make at most TWO Pinecone queries. After two queries, you MUST stop calling\n  tools and produce your final JSON answer.\n- Do not output tool-call syntax as part of your text response.\n- Your final response must be valid JSON matching the schema.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nTASK\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nRecommend ONE action. Your rationale MUST cite specific evidence findings,\nspecific Sentinel policies by name, and specific prior Risk Committee decisions.\n\nTwo HARD ESCALATION triggers \u2014 these override everything else:\n  1. Restricted product found via site classification under a non-matching MCC.\n  2. Beneficial owner name appears in a prior Sentinel offboarding decision.\n\nIn all other cases, be calibrated \u2014 not reflexively conservative.\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nSLIDE OUTPUT CONSTRAINTS (HARD LIMITS - the Risk Committee deck has fixed slide real estate)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nThese constraints are NON-NEGOTIABLE. Write tight or your output gets truncated downstream.\n\n- primary_drivers:   EXACTLY 3 items, each \u2264 120 characters. Short bullet phrases. No trailing periods.\n- policy_citations:  EXACTLY 3 items, each \u2264 120 characters. Format: 'Policy name - one-line reason invoked'.\n- proposed_actions:  EXACTLY 3 items, each \u2264 120 characters. Imperative voice ('Place rolling 30-day hold').\n- prior_precedent.case_summary: 2-3 short sentences, \u2264 300 characters TOTAL. Name the prior merchant + outcome.\n- prior_precedent.outcome:      Single phrase, \u2264 140 characters.\n- rationale:         3-4 sentences, \u2264 500 characters TOTAL. End with a period. Plain English for the Risk Committee deck.\n\nPick the 3 STRONGEST drivers / policies / actions. Don't pad lists. Don't restate the same point twice. The Risk Committee will read this on a slide \u2014 make every word count.",
        "options": {
          "maxIterations": 10
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "af0084bd-f929-4e3e-944c-652f76b342f3",
      "name": "Claude: Recommendation Agent",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1936,
        1168
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.5
    },
    {
      "id": "03a3910b-62aa-497e-af52-9061efa72e6b",
      "name": "Pinecone: Prior Risk Decisions",
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "position": [
        2080,
        1216
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "options": {},
        "pineconeIndex": {
          "__rl": true,
          "mode": "list",
          "value": "n8nrisk",
          "cachedResultName": "n8nrisk"
        },
        "toolDescription": "Retrieves prior Sentinel Risk Committee decisions for analogous merchant situations.\nCall AT MOST TWICE per merchant: once with the company name + risk type, optionally\nonce with the owner name + risk type. After your second call (or first if sufficient),\nyou MUST call format_final_json_response immediately. Do not call this tool more than\ntwice under any circumstances."
      },
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "aa4a365f-6cba-44a8-b558-21140cace97d",
      "name": "OpenAI: Pinecone Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        2080,
        1392
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3fa5c986-08fd-402c-b4f7-dda5dcbb8c64",
      "name": "Parser: Recommended Action",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        2400,
        1248
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"merchant_id\": { \"type\": \"string\", \"description\": \"Sentinel merchant ID, e.g. M00042\" },\n    \"merchant_name\": { \"type\": \"string\" },\n    \"mcc\": { \"type\": \"string\" },\n    \"owner_name\": { \"type\": \"string\" },\n    \"recommendation\": {\n      \"type\": \"string\",\n      \"enum\": [\"no_action\", \"request_docs\", \"raise_reserve\", \"rolling_hold_30d\", \"escalate_offboarding\"],\n      \"description\": \"Single recommended action per Sentinel Risk policy\"\n    },\n    \"severity\": { \"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\", \"critical\"] },\n    \"primary_drivers\": {\n      \"type\": \"array\",\n      \"items\": { \"type\": \"string\", \"maxLength\": 120 },\n      \"minItems\": 3,\n      \"maxItems\": 3,\n      \"description\": \"EXACTLY 3 short bullet phrases. Each \u2264 120 characters. No trailing periods. Each must read as one clean slide bullet.\"\n    },\n    \"policy_citations\": {\n      \"type\": \"array\",\n      \"items\": { \"type\": \"string\", \"maxLength\": 120 },\n      \"minItems\": 3,\n      \"maxItems\": 3,\n      \"description\": \"EXACTLY 3 specific Sentinel policies invoked. Each \u2264 120 characters. Format: 'Policy name - one-line reason invoked'.\"\n    },\n    \"prior_precedent\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"found\": { \"type\": \"boolean\" },\n        \"case_summary\": { \"type\": \"string\", \"maxLength\": 300, \"description\": \"2-3 sentences, \u2264 300 chars. Names the prior merchant + outcome.\" },\n        \"outcome\": { \"type\": \"string\", \"maxLength\": 140, \"description\": \"Single phrase \u2264 140 chars\" }\n      },\n      \"required\": [\"found\", \"case_summary\", \"outcome\"]\n    },\n    \"proposed_actions\": {\n      \"type\": \"array\",\n      \"items\": { \"type\": \"string\", \"maxLength\": 120 },\n      \"minItems\": 3,\n      \"maxItems\": 3,\n      \"description\": \"EXACTLY 3 concrete next steps. Each \u2264 120 characters. Imperative voice ('Place rolling 30-day hold').\"\n    },\n    \"reserve_change_bps\": { \"type\": \"integer\" },\n    \"confidence\": { \"type\": \"string\", \"enum\": [\"low\", \"medium\", \"high\"] },\n    \"rationale\": {\n      \"type\": \"string\",\n      \"maxLength\": 500,\n      \"description\": \"3-4 sentence narrative explaining the recommendation. MAXIMUM 500 CHARACTERS. End with a period. Plain English for the Risk Committee deck.\"\n    }\n  },\n  \"required\": [\"merchant_id\", \"merchant_name\", \"mcc\", \"owner_name\", \"recommendation\", \"severity\", \"primary_drivers\", \"policy_citations\", \"prior_precedent\", \"proposed_actions\", \"reserve_change_bps\", \"confidence\", \"rationale\"],\n  \"additionalProperties\": false\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "7c2e5862-9775-4483-a20c-d4af8bf7b239",
      "name": "Supabase: Insert recommended_action",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2560,
        944
      ],
      "parameters": {
        "tableId": "recommended_actions",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "month",
              "fieldValue": "={{ $now.toFormat(\"yyyy-MM\") }}"
            },
            {
              "fieldId": "merchant_id",
              "fieldValue": "={{ $json.output.merchant_id }}"
            },
            {
              "fieldId": "merchant_name",
              "fieldValue": "={{ $json.output.merchant_name }}"
            },
            {
              "fieldId": "mcc",
              "fieldValue": "={{ $json.output.mcc }}"
            },
            {
              "fieldId": "owner_name",
              "fieldValue": "={{ $json.output.owner_name }}"
            },
            {
              "fieldId": "recommendation",
              "fieldValue": "={{ $json.output.recommendation }}"
            },
            {
              "fieldId": "severity",
              "fieldValue": "={{ $json.output.severity }}"
            },
            {
              "fieldId": "primary_drivers",
              "fieldValue": "={{ $json.output.primary_drivers }}"
            },
            {
              "fieldId": "policy_citations",
              "fieldValue": "={{ $json.output.policy_citations }}"
            },
            {
              "fieldId": "prior_precedent",
              "fieldValue": "={{ $json.output.prior_precedent }}"
            },
            {
              "fieldId": "proposed_actions",
              "fieldValue": "={{ $json.output.proposed_actions }}"
            },
            {
              "fieldId": "reserve_change_bps",
              "fieldValue": "={{ $json.output.reserve_change_bps }}"
            },
            {
              "fieldId": "confidence",
              "fieldValue": "={{ $json.output.confidence }}"
            },
            {
              "fieldId": "rationale",
              "fieldValue": "={{ $json.output.rationale }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7d2c1c08-7ad7-4366-bcb3-0fd24ab6d59d",
      "name": "Aggregate Account Findings",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2848,
        944
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "recommended_actions"
      },
      "typeVersion": 1
    },
    {
      "id": "ea7799e6-221d-4e4d-96a7-65ba4d582ecd",
      "name": "Supabase: Portfolio Metrics (12 mo)",
      "type": "n8n-nodes-base.supabase",
      "position": [
        576,
        2704
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "month",
              "keyValue": "={{ $now.minus({ months: 12 }).toFormat(\"yyyy-MM\") }}",
              "condition": "gte"
            }
          ]
        },
        "tableId": "monthly_metrics",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9f492136-82d0-4ac8-8a55-afc4e673f555",
      "name": "Compute Portfolio Trends",
      "type": "n8n-nodes-base.code",
      "position": [
        992,
        2704
      ],
      "parameters": {
        "jsCode": "const rows = $input.all().map(i => i.json);\nconst byMonth = {};\nfor (const r of rows) {\n  const m = r.month;\n  if (!byMonth[m]) byMonth[m] = { vol: 0, cbCount: 0, refCount: 0, revCount: 0, merchantVol: 0 };\n  byMonth[m].vol += (r.processing_vol || 0);\n  byMonth[m].cbCount += ((r.cb_rate || 0) * (r.processing_vol || 0));\n  byMonth[m].refCount += ((r.refund_rate || 0) * (r.processing_vol || 0));\n  byMonth[m].revCount += ((r.reversal_rate || 0) * (r.processing_vol || 0));\n  byMonth[m].merchantVol += (r.processing_vol || 0);\n}\nconst series = Object.entries(byMonth).sort(([a],[b]) => a.localeCompare(b)).map(([m, v]) => ({\n  month: m,\n  total_processing_vol: v.vol,\n  weighted_cb_rate: v.merchantVol > 0 ? v.cbCount / v.merchantVol : 0,\n  weighted_refund_rate: v.merchantVol > 0 ? v.refCount / v.merchantVol : 0,\n  weighted_reversal_rate: v.merchantVol > 0 ? v.revCount / v.merchantVol : 0\n}));\nconst last = series[series.length - 1] || {};\nconst prev = series[series.length - 2] || {};\nreturn [{\n  series,\n  current: last,\n  prior: prev,\n  deltas: {\n    cb_rate: (last.weighted_cb_rate || 0) - (prev.weighted_cb_rate || 0),\n    refund_rate: (last.weighted_refund_rate || 0) - (prev.weighted_refund_rate || 0),\n    reversal_rate: (last.weighted_reversal_rate || 0) - (prev.weighted_reversal_rate || 0),\n    processing_vol: (last.total_processing_vol || 0) - (prev.total_processing_vol || 0)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "dc84d833-48a7-48ba-a365-312da6c21d4f",
      "name": "AI Agent: Portfolio Narrative",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1328,
        2704
      ],
      "parameters": {
        "text": "=Write a portfolio-level risk narrative for the Sentinel Payments monthly risk review, maximum 500 characters total. 2-3 short paragraphs. 12-month series, current vs prior month, deltas: {{ JSON.stringify($json) }}. Speak in internal risk-analyst voice. Identify what is moving and why it matters. Hard limit: 500 characters.",
        "options": {
          "systemMessage": "You are a senior risk analyst at Sentinel Payments writing for the internal risk committee. Be candid, dense, operational. Plain prose. HARD LIMIT: 500 characters total."
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "42bb4660-3c01-447a-b113-0220be263f58",
      "name": "Claude: Portfolio Agent",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1328,
        2944
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.5
    },
    {
      "id": "19380699-6407-4b13-af5b-d12a006e45a3",
      "name": "Supabase: Insert portfolio_snapshot",
      "type": "n8n-nodes-base.supabase",
      "position": [
        1680,
        2704
      ],
      "parameters": {
        "tableId": "portfolio_snapshots",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "month",
              "fieldValue": "={{ $now.toFormat(\"yyyy-MM\") }}"
            },
            {
              "fieldId": "series",
              "fieldValue": "={{ JSON.stringify($('Compute Portfolio Trends').item.json.series) }}"
            },
            {
              "fieldId": "current",
              "fieldValue": "={{ JSON.stringify($('Compute Portfolio Trends').item.json.current) }}"
            },
            {
              "fieldId": "deltas",
              "fieldValue": "={{ JSON.stringify($('Compute Portfolio Trends').item.json.deltas) }}"
            },
            {
              "fieldId": "narrative",
              "fieldValue": "={{ $json.output }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e9dd409e-e879-4e38-8810-1ccb4a7dbbbc",
      "name": "Build Monthly Manifest",
      "type": "n8n-nodes-base.code",
      "position": [
        3776,
        960
      ],
      "parameters": {
        "jsCode": "const mccAgg       = $('Aggregate MCC Snapshots').first()?.json || {};\nconst accountAgg   = $('Aggregate Account Findings').first()?.json || {};\nconst portfolio    = $('Supabase: Insert portfolio_snapshot').first()?.json || {};\n\nconst mccSnapshots       = mccAgg.mcc_snapshots || [];\nconst recommendedActions = accountAgg.recommended_actions || [];\n\nreturn [{\n  run_month:                $now.toFormat(\"yyyy-MM\"),\n  run_id:                   $execution.id,\n  triggered_at:             $now.toISO(),\n  generated_at:             new Date().toISOString(),\n  status:                   'complete',\n  mcc_snapshot_count:       mccSnapshots.length,\n  recommended_action_count: recommendedActions.length,\n  portfolio_snapshot_id:    portfolio.id\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "082c9968-22f0-4fab-9b2c-61a4baa0f688",
      "name": "Supabase: Insert monthly_manifest",
      "type": "n8n-nodes-base.supabase",
      "position": [
        4000,
        960
      ],
      "parameters": {
        "tableId": "monthly_manifest",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "run_month",
              "fieldValue": "={{ $json.run_month }}"
            },
            {
              "fieldId": "run_id",
              "fieldValue": "={{ $json.run_id }}"
            },
            {
              "fieldId": "triggered_at",
              "fieldValue": "={{ $json.triggered_at }}"
            },
            {
              "fieldId": "generated_at",
              "fieldValue": "={{ $json.generated_at }}"
            },
            {
              "fieldId": "status",
              "fieldValue": "={{ $json.status }}"
            },
            {
              "fieldId": "mcc_snapshot_count",
              "fieldValue": "={{ $json.mcc_snapshot_count }}"
            },
            {
              "fieldId": "recommended_action_count",
              "fieldValue": "={{ $json.recommended_action_count }}"
            },
            {
              "fieldId": "portfolio_snapshot_id",
              "fieldValue": "={{ $json.portfolio_snapshot_id }}"
            }
          ]
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ade5dfc7-3d5a-4db9-8325-9116d1d6876e",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        128,
        -1280
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "874526e6-f789-46e5-b8bd-749e3fdbbdf2",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1488,
        592
      ],
      "parameters": {
        "width": 976,
        "height": 192,
        "content": "# Part 2 Main Workflow\n\nIn this section of the workflow, we will get the updates on industry MCC codes, updates on the high risk or watch accounts, and get the data from our portfolio. We want to format this data and save it back into the DB\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4acaa071-e471-4939-9801-ddccda0b8275",
      "name": "Pinecone: Insert Prior Decisions",
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "position": [
        608,
        -1280
      ],
      "parameters": {
        "mode": "insert",
        "options": {
          "clearNamespace": true
        },
        "pineconeIndex": {
          "__rl": true,
          "mode": "list",
          "value": "n8nrisk",
          "cachedResultName": "n8nrisk"
        },
        "embeddingBatchSize": 50
      },
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "e625f792-bd67-46ee-80df-79a1139199b7",
      "name": "OpenAI Embeddings (text-embedding-3-small)",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        528,
        -1040
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "457a7d51-991b-4d34-a24b-e998f33499d1",
      "name": "Prior Decision Document Loader",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        752,
        -1056
      ],
      "parameters": {
        "options": {
          "metadata": {
            "metadataValues": [
              {
                "name": "decision_id",
                "value": "={{ $json.id }}"
              },
              {
                "name": "decision_date",
                "value": "={{ $json.decision_date }}"
              },
              {
                "name": "merchant_name",
                "value": "={{ $json.merchant_name }}"
              },
              {
                "name": "merchant_id_internal",
                "value": "={{ $json.merchant_id_internal }}"
              },
              {
                "name": "mcc",
                "value": "={{ $json.mcc }}"
              },
              {
                "name": "action_taken",
                "value": "={{ $json.action_taken }}"
              },
              {
                "name": "bo_names",
                "value": "={{ $json.bo_names }}"
              }
            ]
          }
        },
        "jsonData": "=Date: {{ $json.decision_date }}\nMerchant: {{ $json.merchant_name }} (internal ID: {{ $json.merchant_id_internal }})\nMCC: {{ $json.mcc }} ({{ $json.mcc_industry }})\nBeneficial Owners: {{ $json.bo_names }}\nMetric Profile: {{ $json.metric_profile }}\nSignals Gathered: {{ $json.signals_gathered }}\nAction Taken: {{ $json.action_taken }}\nRationale: {{ $json.rationale }}\nOutcome: {{ $json.outcome }}",
        "jsonMode": "expressionData",
        "textSplittingMode": "custom"
      },
      "typeVersion": 1.1
    },
    {
      "id": "972fa3d2-6f5d-4d48-9333-b55c17214d5c",
      "name": "Character Text Splitter",
      "type": "@n8n/n8n-nodes-langchain.textSplitterCharacterTextSplitter",
      "position": [
        768,
        -880
      ],
      "parameters": {
        "chunkSize": 2000
      },
      "typeVersion": 1
    },
    {
      "id": "557dee26-6859-4013-9bc9-76ee8c0c5eaa",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -1408
      ],
      "parameters": {
        "height": 96,
        "content": "Fake Example Decisions based on merchant risk are stored in here"
      },
      "typeVersion": 1
    },
    {
      "id": "e4273ca9-d02c-462a-b165-a7fc72ec8343",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        -1312
      ],
      "parameters": {
        "width": 480,
        "content": "# Part 1 Simple RAG Ingestion\nEach past decision is stored as a chunk in the Vector DB\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c611457a-616a-4169-8ced-d8a58709f694",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -416,
        4096
      ],
      "parameters": {
        "width": 592,
        "content": "# Part 3 Cowork Workflow\nThis workflow will run from cowork, grab the exact data we need, and send the data back to cowork to build the slide deck"
      },
      "typeVersion": 1
    },
    {
      "id": "b9122b63-33e4-4e6f-b940-ddbb41c7e36e",
      "name": "Get Monthly Data Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        304,
        4128
      ],
      "parameters": {
        "path": "sentinel-risk-monthly-data",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "50560461-e6ee-4a19-8e92-dcf453b0ddc1",
      "name": "Resolve Month",
      "type": "n8n-nodes-base.set",
      "position": [
        560,
        4128
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "month",
              "name": "month",
              "type": "string",
              "value": "={{ ($json.query && $json.query.month) ? $json.query.month : $now.toFormat(\"yyyy-MM\") }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3ea3204a-4e4e-4680-a146-ea37e25dfc7e",
      "name": "Supabase: monthly_manifest",
      "type": "n8n-nodes-base.supabase",
      "position": [
        928,
        3728
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "run_month",
              "keyValue": "={{ $json.month }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "monthly_manifest",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "c5d55091-a13f-4bb1-8aa3-8ff8ec6f90a5",
      "name": "Merge All Branches",
      "type": "n8n-nodes-base.merge",
      "position": [
        1248,
        4080
      ],
      "parameters": {
        "numberInputs": 5
      },
      "typeVersion": 3.2
    },
    {
      "id": "07c3ad9f-ba11-4138-a7b2-abf3df38b754",
      "name": "Supabase: mcc_risk_snapshots",
      "type": "n8n-nodes-base.supabase",
      "position": [
        928,
        3936
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "month",
              "keyValue": "={{ $json.month }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "mcc_risk_snapshots",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "db17f056-6373-499e-b9f5-14219c1e0f80",
      "name": "Supabase: mcc_codes",
      "type": "n8n-nodes-base.supabase",
      "position": [
        928,
        4128
      ],
      "parameters": {
        "tableId": "mcc_codes",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "2acd584f-7905-4985-85b2-c6c9ad192db2",
      "name": "Supabase: recommended_actions",
      "type": "n8n-nodes-base.supabase",
      "position": [
        928,
        4320
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "month",
              "keyValue": "={{ $json.month }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "recommended_actions",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "29876238-4142-4dcb-bdea-f3794d3de799",
      "name": "Supabase: portfolio_snapshots",
      "type": "n8n-nodes-base.supabase",
      "position": [
        928,
        4512
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "month",
              "keyValue": "={{ $json.month }}",
              "condition": "eq"
            }
          ]
        },
        "tableId": "portfolio_snapshots",
        "matchType": "allFilters",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "af0991d6-4de9-4527-9b84-b1a42fa69c6b",
      "name": "Build Response",
      "type": "n8n-nodes-base.code",
      "position": [
        1456,
        4128
      ],
      "parameters": {
        "jsCode": "// Sentence-boundary truncation: cut at last complete sentence within the cap.\n// If no sentence boundary found, return the full string (no '\u2026' artifact).\n// Auto-shrink in the deck handles visual fitting.\nconst truncSentence = (s, cap, hardMax) => {\n  if (!s || typeof s !== 'string') return s || '';\n  if (s.length <= cap) return s;\n  // Look for sentence boundary in [0, cap]\n  const slice = s.slice(0, cap);\n  const lastDot = Math.max(slice.lastIndexOf('. '), slice.lastIndexOf('? '), slice.lastIndexOf('! '));\n  if (lastDot > cap * 0.5) return slice.slice(0, lastDot + 1).trim();\n  // No sentence boundary - return up to hardMax full string (no marker)\n  return s.slice(0, hardMax || s.length);\n};\n\n// Trim a bullet to a word boundary, no marker\nconst trimBullet = (s, n) => {\n  if (!s || typeof s !== 'string') return s || '';\n  if (s.length <= n) return s;\n  const slice = s.slice(0, n);\n  const lastSpace = slice.lastIndexOf(' ');\n  return (lastSpace > n * 0.7 ? slice.slice(0, lastSpace) : slice).trim();\n};\n\nconst safeJson = (v) => {\n  if (v == null) return v;\n  if (typeof v === 'string') { try { return JSON.parse(v); } catch { return v; } }\n  return v;\n};\n\nconst month = $('Resolve Month').first().json.month;\nconst manifests   = $('Supabase: monthly_manifest').all().map(i => i.json);\nconst mccRaw      = $('Supabase: mcc_risk_snapshots').all().map(i => i.json);\nconst mccCodesRaw = $('Supabase: mcc_codes').all().map(i => i.json);\nconst actionsRaw  = $('Supabase: recommended_actions').all().map(i => i.json);\nconst portfolios  = $('Supabase: portfolio_snapshots').all().map(i => i.json);\n\nconst industryByCode = {};\nfor (const c of mccCodesRaw) {\n  const code = String(c.code ?? c.mcc ?? '').trim();\n  if (code) industryByCode[code] = c.industry || c.name || '';\n}\n\nconst mcc_snapshots = mccRaw.map(m => {\n  const codeKey = String(m.mcc ?? '').trim();\n  return {\n    mcc: m.mcc,\n    industry: industryByCode[codeKey] || '',\n    risk_rating: m.risk_rating,\n    direction: m.direction,\n    account_count: m.account_count,\n    rec_action: m.rec_action,\n    // Prefer sentence boundary, hard cap at 1100 if no boundary found - auto-shrink handles fit\n    news_summary: truncSentence(m.news_summary || '', 700, 1100),\n    top_accounts: (safeJson(m.top_accounts) || []).slice(0, 6),\n    key_flags: (safeJson(m.key_flags) || []).slice(0, 3).map(f => ({\n      category: f.category || '',\n      headline: trimBullet(f.headline || '', 110)\n    }))\n  };\n});\nmcc_snapshots.sort((a, b) => (b.risk_rating || 0) - (a.risk_rating || 0));\n\nconst recommended_actions = actionsRaw.map(a => {\n  const pp = safeJson(a.prior_precedent) || {};\n  return {\n    merchant_id: a.merchant_id,\n    merchant_name: a.merchant_name,\n    mcc: a.mcc,\n    owner_name: a.owner_name,\n    recommendation: a.recommendation,\n    severity: a.severity,\n    primary_drivers:  (safeJson(a.primary_drivers)  || []).slice(0, 3).map(d => trimBullet(d, 130)),\n    policy_citations: (safeJson(a.policy_citations) || []).slice(0, 3).map(c => trimBullet(c, 130)),\n    proposed_actions: (safeJson(a.proposed_actions) || []).slice(0, 3).map(p => trimBullet(p, 130)),\n    prior_precedent: {\n      found: pp.found ?? false,\n      case_summary: truncSentence(pp.case_summary || '', 340, 500),\n      outcome:      trimBullet(pp.outcome || '', 140)\n    },\n    reserve_change_bps: a.reserve_change_bps ?? 0,\n    confidence: a.confidence,\n    rationale: truncSentence(a.rationale || '', 700, 1100)\n  };\n});\n\nconst sevRank = { critical: 4, high: 3, medium: 2, low: 1 };\nrecommended_actions.sort((a, b) => (sevRank[b.severity] || 0) - (sevRank[a.severity] || 0));\n\nconst portfolio = portfolios[0] || null;\nconst portfolio_snapshot = portfolio ? {\n  month: portfolio.month,\n  total_merchants: portfolio.total_merchants,\n  total_volume: portfolio.total_volume,\n  avg_cb_rate: portfolio.avg_cb_rate,\n  avg_refund_rate: portfolio.avg_refund_rate,\n  high_risk_count: portfolio.high_risk_count,\n  flagged_count: portfolio.flagged_count,\n  trend_summary: truncSentence(portfolio.trend_summary || '', 600, 900)\n} : null;\n\nconst recCounts = recommended_actions.reduce((acc, a) => {\n  acc[a.recommendation] = (acc[a.recommendation] || 0) + 1;\n  return acc;\n}, {});\n\nreturn [{\n  month,\n  fetched_at: new Date().toISOString(),\n  manifest: manifests[0] || null,\n  mcc_snapshots,\n  recommended_actions,\n  portfolio_snapshot,\n  counts: {\n    mcc_snapshots: mcc_snapshots.length,\n    recommended_actions: recommended_actions.length,\n    by_recommendation: recCounts,\n    manifest_exists: manifests.length > 0,\n    portfolio_exists: portfolios.length > 0,\n    mcc_codes_loaded: mccCodesRaw.length\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ec82b895-fa1e-4820-9aa2-31b1149f9827",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1696,
        4128
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.5
    },
    {
      "id": "1b552980-c79d-4ca8-8adc-c380ce1e4eb8",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        4016
      ],
      "parameters": {
        "height": 80,
        "content": "Webhook Call From Claude Cowork"
      },
      "typeVersion": 1
    },
    {
      "id": "e9c78adb-e430-408b-804c-aa17f353e5a7",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        3984
      ],
      "parameters": {
        "width": 304,
        "height": 80,
        "content": "Send Data Back to Claude Cowork"
      },
      "typeVersion": 1
    },
    {
      "id": "c2060b9a-1b17-441a-b192-ae31dd6bd0a2",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        848,
        3616
      ],
      "parameters": {
        "width": 272,
        "height": 80,
        "content": "Grab Saved We Stored From the Previous Workflow "
      },
      "typeVersion": 1
    },
    {
      "id": "80d8f112-d739-4dfa-8916-cac0378e6b6d",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1712,
        -1488
      ],
      "parameters": {
        "color": "#FFF700",
        "width": 784,
        "height": 1584,
        "content": "# Read Me\n\nThis template runs a monthly risk review that pulls merchant and MCC data from Supabase, researches industry changes with Perplexity, screens high-risk merchants using OpenSanctions, CourtListener, Apify, Tavily, and Firecrawl, and uses Anthropic Claude plus Pinecone to store risk snapshots and recommendations.\n\nIt consists 3 different workflows. Each one should be saved into individual workflows.\n\nThe goal of these workflows is to automate a tedious process of creating a monthly merchant and industry review deck a task that might take a risk team 20+ hours to build\n\n\n1. Runs on a monthly schedule and initializes the run metadata (month, execution ID, timestamp).\n2. Retrieves active merchants and MCC reference data from Supabase, groups merchants by MCC, and uses Perplexity plus Claude to generate an MCC risk snapshot with key flags and a recommended action.\n3. Writes each MCC snapshot back to Supabase and aggregates all MCC snapshots for the run.\n4. Pulls high-risk merchants for the current month from Supabase and gathers external signals by screening names with OpenSanctions, searching recent cases in CourtListener, fetching recent Google reviews via Apify, and collecting adverse media via Tavily.\n5. Scrapes each merchant website with Firecrawl and uses Claude to classify the business vertical and flag restricted content.\n6. Uses Claude with Pinecone retrieval of prior Risk Committee decisions (embedded with OpenAI) to produce a single recommended action per merchant and inserts those recommendations into Supabase.\n7. Calculates 12-month portfolio trends from Supabase metrics, generates a short portfolio narrative with Claude, saves it to Supabase, and records a monthly manifest summarizing the run.\n8. Exposes a webhook that fetches the stored Supabase data for a requested month, formats it for downstream slide-building, and returns the JSON response.\n\n# Setup\n\n1. Create and connect credentials for Supabase, Anthropic (Claude), Perplexity, OpenAI (embeddings), Pinecone, Apify, Tavily, Firecrawl, and the two HTTP header auth credentials used for OpenSanctions and CourtListener.\n2. In Supabase, create/confirm the required tables and fields referenced by the workflow (merchants, mcc_codes, monthly_metrics, mcc_risk_snapshots, recommended_actions, portfolio_snapshots, monthly_manifest).\n3. Populate the Pinecone index name (n8nrisk) and run the manual ingestion workflow to embed and insert the provided prior decision examples before enabling the monthly recommendation step.\n4. Update any environment-specific constants such as the webhook path usage in your slide-building tool and verify the Supabase filters match your month format (yyyy-MM) and risk thresholds.\n5. If using the webhook integration, copy the production webhook URL and configure it in your external deck builder (for example, Claude \u201ccowork\u201d) to request the month parameter as needed.\n\n\n\n@[youtube](u8-bQlMtAKE)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f55945d3-b1a6-457b-a6b7-1731b3854718",
      "name": "Risk Decisions Past Examples",
      "type": "n8n-nodes-base.code",
      "position": [
        368,
        -1280
      ],
      "parameters": {
        "jsCode": "// 50 prior Risk Committee decisions \u2014 hardcoded source of truth.\n// Edit prior_decisions.csv + re-run generate_prior_decisions.py + paste new array if updated.\n\nconst decisions = [\n  {\n    \"decision_date\": \"2025-09-18\",\n    \"merchant_name\": \"Coastal Energy Trading\",\n    \"merchant_id_internal\": \"M-prev-3214\",\n    \"mcc\": \"5172\",\n    \"mcc_industry\": \"Petroleum & Petroleum Products\",\n    \"bo_names\": \"James Ferraro (60%), Donald Smith (40%)\",\n    \"metric_profile\": \"CB rate 1.05% sustained over 3 months, refund rate 4.8%, processing volume $1.4M/mo, exposure score 5\",\n    \"signals_gathered\": \"CB rate breached 1.0% for 3 consecutive months; documentation request from August went unanswered for 30 days; OFAC/PEP clean; OpenSanctions clean; Firecrawl confirmed merchant continued operating but unresponsive to processor communications\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, sustained CB rate above 1.0% across 3 consecutive months mandates Risk Committee escalation for offboarding. Documentation request unanswered after 30 days further violates Sentinel's response-time expectations. Risk Committee voted unanimously for offboarding with 90-day wind-down.\",\n    \"outcome\": \"Offboarded 2025-12-15 after 90-day wind-down. No appeals filed. Per BO Re-screening Policy \u00a74.2, James Ferraro and Donald Smith are flagged in the internal offboarded-entity registry \u2014 any future Sentinel application listing these BOs requires mandatory Risk Committee escalation prior to activation.\",\n    \"id\": 1\n  },\n  {\n    \"decision_date\": \"2024-11-04\",\n    \"merchant_name\": \"Apex Health Direct\",\n    \"merchant_id_internal\": \"M-prev-2891\",\n    \"mcc\": \"5499\",\n    \"mcc_industry\": \"Misc Food Stores (at onboarding)\",\n    \"bo_names\": \"Howard Kessler\",\n    \"metric_profile\": \"CB rate 0.45%, refund rate 6.8%, processing volume $620K/mo, exposure score 3\",\n    \"signals_gathered\": \"Firecrawl scan of merchant website revealed merchant had pivoted from generic wellness retail (onboarding vertical) to GLP-1 weight loss prescribing via unlicensed telemedicine. No pharmacy license on file. MCC still listed as 5499 despite vertical drift.\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Restricted Business Types Policy applies strict liability for mis-classification. GLP-1 prescribing without proper pharmacy licensing is on Sentinel's restricted list and must be coded under MCC 5912 with valid licensing \u2014 never under MCC 5499. CB and refund metrics were within normal bands but are irrelevant under strict liability. Risk Committee voted for immediate offboarding.\",\n    \"outcome\": \"Offboarded 2024-11-10. Set the precedent: any merchant found selling restricted product under a non-matching MCC is referred to immediate offboarding regardless of chargeback metrics. Sentinel's standard for vertical mis-classification is strict liability \u2014 no exceptions.\",\n    \"id\": 2\n  },\n  {\n    \"decision_date\": \"2025-08-22\",\n    \"merchant_name\": \"Atlas Direct Marketing\",\n    \"merchant_id_internal\": \"M-prev-3105\",\n    \"mcc\": \"5967\",\n    \"mcc_industry\": \"Direct Marketing \u2014 Inbound Telemarketing\",\n    \"bo_names\": \"Rachel Vargas\",\n    \"metric_profile\": \"CB rate 1.6% current month, refund rate 9.4%, processing volume $890K/mo, exposure score 5\",\n    \"signals_gathered\": \"CB rate spiked from 0.9% to 1.6% in one month following promotional campaign; CourtListener returned 3 active FTC enforcement actions against the merchant for deceptive marketing practices; multiple state AG investigations open in TX and FL\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, CB rate at or above 1.5% (Mastercard ECP cliff) triggers Risk Committee escalation. Per Litigation Disclosure Policy, open state AG investigations are grounds for processing hold pending Risk Committee review. Combined fact pattern is decisive.\",\n    \"outcome\": \"Offboarded 2025-09-30. FTC settlement subsequently announced in Q4 2025. Sentinel exposure was zero by that point.\",\n    \"id\": 3\n  },\n  {\n    \"decision_date\": \"2025-06-14\",\n    \"merchant_name\": \"Northstar Botanicals\",\n    \"merchant_id_internal\": \"M-prev-2967\",\n    \"mcc\": \"5499\",\n    \"mcc_industry\": \"Misc Food Stores\",\n    \"bo_names\": \"Tyler Sandoval\",\n    \"metric_profile\": \"CB rate 0.6%, refund rate 5.1%, processing volume $410K/mo, exposure score 4\",\n    \"signals_gathered\": \"Firecrawl scan revealed merchant primarily sells kratom and mitragyna extracts. Onboarded as MCC 5499 'specialty food retailer'. OFAC clean. CB and refund within normal-for-vertical bands. Site classification clearly identified kratom as primary vertical.\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Per Restricted Business Types Policy, kratom is explicitly on Sentinel's no-process list. Strict liability \u2014 merchant onboarded under non-matching MCC with restricted primary vertical. Metrics are irrelevant. Apex Health Direct precedent (Q4 2024) governs.\",\n    \"outcome\": \"Offboarded 2025-07-20 after 30-day wind-down.\",\n    \"id\": 4\n  },\n  {\n    \"decision_date\": \"2025-04-08\",\n    \"merchant_name\": \"Beacon Lending Solutions\",\n    \"merchant_id_internal\": \"M-prev-2823\",\n    \"mcc\": \"6051\",\n    \"mcc_industry\": \"Non-Financial Institutions \u2014 Quasi-Cash\",\n    \"bo_names\": \"Anatoly Sokolov, Mariana Esposito\",\n    \"metric_profile\": \"CB rate 0.7%, refund rate 3.2%, processing volume $2.1M/mo, exposure score 4\",\n    \"signals_gathered\": \"OpenSanctions screening returned fuzzy match (confidence 0.91) on BO Anatoly Sokolov to OFAC SDN list \u2014 different middle initial but same DOB and last known address. Compliance review confirmed match was the same individual.\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Per OFAC / PEP Hit Handling Policy, fuzzy SDN match at confidence \u22650.85 triggers immediate processing hold and escalation to Sentinel Compliance. Sentinel does not process for sanctioned entities under any circumstance. Risk Committee + Compliance + Legal aligned on immediate offboarding.\",\n    \"outcome\": \"Offboarded 2025-04-09 \u2014 same day as decision. Reported to FinCEN per SAR requirements.\",\n    \"id\": 5\n  },\n  {\n    \"decision_date\": \"2024-08-19\",\n    \"merchant_name\": \"Tradewind Logistics LLC\",\n    \"merchant_id_internal\": \"M-prev-2645\",\n    \"mcc\": \"4814\",\n    \"mcc_industry\": \"Telecom Services\",\n    \"bo_names\": \"Donald Smith, Marcus Greene\",\n    \"metric_profile\": \"CB rate 0.7%, refund rate 4.2%, processing volume $760K/mo, exposure score 3\",\n    \"signals_gathered\": \"Routine BO re-screening returned name match: Donald Smith was 40% BO of Coastal Energy Trading, offboarded 2024 Q2 for excessive CB. Same individual now listed as 50% BO of Tradewind Logistics. Current metrics within normal bands.\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Per Beneficial Owner Re-screening Policy \u00a74.2, name match to previously offboarded BO triggers MANDATORY escalation regardless of current metrics. Current Tradewind metrics are clean but the BO history pattern is the deciding factor. Risk Committee determined the prior offboarding rationale (excessive CB + unresponsiveness) reflected operational behavior that follows the BO, not the entity.\",\n    \"outcome\": \"Offboarded 2024-09-05. Donald Smith's name escalation flag carried forward \u2014 Coastal Energy Trading offboarding Q3 2025 (separate decision) also triggered partly by this re-encounter.\",\n    \"id\": 6\n  },\n  {\n    \"decision_date\": \"2024-05-12\",\n    \"merchant_name\": \"Silver Hollow Casino Online\",\n    \"merchant_id_internal\": \"M-prev-2502\",\n    \"mcc\": \"7995\",\n    \"mcc_industry\": \"Betting / Casino Gambling\",\n    \"bo_names\": \"Vincent Marquesa\",\n    \"metric_profile\": \"CB rate 1.8% current month, refund rate 14%, processing volume $3.4M/mo, exposure score 5\",\n    \"signals_gathered\": \"CB rate breached Mastercard ECP threshold (1.5%) for the first time. Negative Google reviews surge (avg rating 1.9 across 340 reviews in 90 days) with consistent complaints of unauthorized charges and rigged play. CourtListener returned 7 pending small-claims actions.\",\n    \"action_taken\": \"escalate_offboarding\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, CB rate above 1.5% breaches Mastercard ECP and is automatic escalation. Per Negative Google Reviews Signal Policy, sustained rating below 2.5 with patterns indicating unauthorized charges corroborates fraud signal. Combined with litigation exposure, fact pattern was decisive.\",\n    \"outcome\": \"Offboarded 2024-06-30. Subsequent state regulatory action confirmed unlicensed operation.\",\n    \"id\": 7\n  },\n  {\n    \"decision_date\": \"2025-11-10\",\n    \"merchant_name\": \"Lighthouse Vape Wholesale\",\n    \"merchant_id_internal\": \"M-prev-3287\",\n    \"mcc\": \"5993\",\n    \"mcc_industry\": \"Cigar Stores & Stands\",\n    \"bo_names\": \"Brett Holloway\",\n    \"metric_profile\": \"CB rate 0.95% current month (up from 0.6% prior), refund rate 4.1%, processing volume $580K/mo, exposure score 4\",\n    \"signals_gathered\": \"CB rate trending toward Visa VDMP threshold. Firecrawl confirmed legitimate vape retail with proper age verification. Site classification clean. No restricted product. Adverse media surfaced one news article about FDA inquiry into the vape industry broadly (not specific to this merchant).\",\n    \"action_taken\": \"rolling_hold_30d\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, CB rate in 0.9%-1.0% band triggers Visa VDMP risk. 30-day rolling hold applied while documentation request goes out. Vertical and licensing are clean; merchant deserves a chance to address operational issue before escalation.\",\n    \"outcome\": \"CB rate returned to 0.55% within 60 days after merchant implemented stricter age-gate at checkout. Rolling hold released 2026-01-10. Reserve increased from 5% to 8% as precaution.\",\n    \"id\": 8\n  },\n  {\n    \"decision_date\": \"2025-07-29\",\n    \"merchant_name\": \"Aurora Skin Co\",\n    \"merchant_id_internal\": \"M-prev-3047\",\n    \"mcc\": \"5499\",\n    \"mcc_industry\": \"Misc Food Stores (supplements/wellness)\",\n    \"bo_names\": \"Nicole Trang\",\n    \"metric_profile\": \"CB rate 0.55%, refund rate 11.2%, processing volume $340K/mo, exposure score 4\",\n    \"signals_gathered\": \"Refund rate elevated in 8-12% band per standard playbook; however merchant operates in supplements vertical where MCC 5499 modifier applies (threshold shifts +3 percentage points). Effective threshold for action: 11% \u2014 barely tripped. Documentation request from prior month answered: customers cited slow shipping during fulfillment-center transition.\",\n    \"action_taken\": \"rolling_hold_30d\",\n    \"rationale\": \"Per Refund Rate Monitoring Standards, sustained refund above 11% (effective threshold for MCC 5499) warrants service-quality investigation. Rolling hold imposed while merchant transitions fulfillment center; documentation request confirmed root cause was operational not fraudulent.\",\n    \"outcome\": \"Fulfillment-center transition completed mid-August. Refund rate dropped to 7.5% by September. Rolling hold released 2025-08-29.\",\n    \"id\": 9\n  },\n  {\n    \"decision_date\": \"2025-03-04\",\n    \"merchant_name\": \"Stagecoach BNPL\",\n    \"merchant_id_internal\": \"M-prev-2812\",\n    \"mcc\": \"6012\",\n    \"mcc_industry\": \"Financial Institutions \u2014 Merchandise & Services\",\n    \"bo_names\": \"Marcus Whitfield\",\n    \"metric_profile\": \"CB rate 0.6%, refund rate 2.8%, processing volume $4.2M/mo, exposure score 4\",\n    \"signals_gathered\": \"CourtListener returned 1 newly-filed class action alleging deceptive disclosures in BNPL terms. CFPB rulemaking on BNPL pending. Firecrawl scan showed merchant updated its disclosures within the past 30 days. No OFAC or PEP hits.\",\n    \"action_taken\": \"rolling_hold_30d\",\n    \"rationale\": \"Per Litigation Disclosure Policy, pending class action with material consumer protection allegations warrants processing hold pending Risk Committee review. 30-day rolling hold imposed while legal review evaluates merits and discovery posture.\",\n    \"outcome\": \"Class action dismissed at motion to dismiss stage in May 2025. Rolling hold released. CFPB rule finalized in Q3 2025 \u2014 merchant complied.\",\n    \"id\": 10\n  },\n  {\n    \"decision_date\": \"2024-12-17\",\n    \"merchant_name\": \"Crescent Bay Subscription Box\",\n    \"merchant_id_internal\": \"M-prev-2734\",\n    \"mcc\": \"5968\",\n    \"mcc_industry\": \"Direct Marketing \u2014 Continuity / Subscription\",\n    \"bo_names\": \"Heather Sims\",\n    \"metric_profile\": \"CB rate 0.45%, refund rate 14.5%, processing volume $880K/mo, exposure score 3\",\n    \"signals_gathered\": \"Refund rate near threshold of MCC 5968 effective band (15% \u2014 applies vertical modifier). Customer reviews complained of difficulty canceling subscriptions. FTC published 'click-to-cancel' rulemaking guidance during the month.\",\n    \"action_taken\": \"rolling_hold_30d\",\n    \"rationale\": \"Refund rate approaching MCC 5968 modified threshold combined with cancellation-difficulty complaints raises FTC negative-option compliance risk. Hold imposed while merchant remediates checkout flow. Vertical modifier applied per refund rate monitoring policy.\",\n    \"outcome\": \"Merchant overhauled cancellation UX. Refund rate dropped to 10% by Feb 2025. Hold released 2025-01-17.\",\n    \"id\": 11\n  },\n  {\n    \"decision_date\": \"2024-09-21\",\n    \"merchant_name\": \"Argo Sports Books\",\n    \"merchant_id_internal\": \"M-prev-2701\",\n    \"mcc\": \"7995\",\n    \"mcc_industry\": \"Betting / Casino Gambling\",\n    \"bo_names\": \"Robert Pemberton\",\n    \"metric_profile\": \"CB rate 0.85% current month, refund rate 6.7%, processing volume $1.9M/mo, exposure score 4\",\n    \"signals_gathered\": \"CB rate approaching VDMP threshold. State legalization news in two new jurisdictions during month. Merchant added new bet types in those states \u2014 Firecrawl confirmed compliance language present on site.\",\n    \"action_taken\": \"rolling_hold_30d\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, CB rate in 0.7%-0.9% band combined with volume change warrants rolling hold while reserve review and documentation request proceed. Gambling MCC is Tier 5 and warrants conservative posture.\",\n    \"outcome\": \"CB rate stabilized at 0.65% after merchant tightened user verification. Hold released 2024-10-21. Reserve increased to 12% from 10%.\",\n    \"id\": 12\n  },\n  {\n    \"decision_date\": \"2026-03-22\",\n    \"merchant_name\": \"Verdant Wellness Co\",\n    \"merchant_id_internal\": \"M00038\",\n    \"mcc\": \"5912\",\n    \"mcc_industry\": \"Drug Stores & Pharmacies\",\n    \"bo_names\": \"Olivia Marchetti\",\n    \"metric_profile\": \"CB rate 0.68%, refund rate 5.8%, processing volume $290K/mo, exposure score 3\",\n    \"signals_gathered\": \"Sustained CB rate in 0.5%-0.7% band over 3 months. Properly licensed pharmacy operation per state board records. Site classification clean \u2014 CBD products sold under proper licensing on MCC 5912. No OFAC, no litigation, normal Google reviews.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Per Reserve Policy by MCC Tier (Tier 3: moderate), elevated CB rate sustained in 0.5%-0.7% band warrants reserve increase. Reserve raised from 5% to 7%. Vertical and licensing are clean; merchant operating responsibly.\",\n    \"outcome\": \"Active monitoring continues. CB rate stable. As of this writing no further escalation required.\",\n    \"id\": 13\n  },\n  {\n    \"decision_date\": \"2025-10-08\",\n    \"merchant_name\": \"Pacific Crest Software\",\n    \"merchant_id_internal\": \"M-prev-3201\",\n    \"mcc\": \"7372\",\n    \"mcc_industry\": \"Computer Programming & Data Processing\",\n    \"bo_names\": \"Anjali Mehta\",\n    \"metric_profile\": \"CB rate 0.45%, refund rate 7.2%, processing volume $1.6M/mo, exposure score 3\",\n    \"signals_gathered\": \"Refund rate sustained in 6-8% band over 3 months. Documentation request confirmed: customer churn from a deprecated product line accounted for elevated refunds. Site classification clean; no other red flags.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Per Refund Rate Monitoring Standards, sustained refund 6-8% warrants reserve review. Risk Analyst confirmed root cause via documentation. Reserve increased from 3% to 5% as precaution while merchant migrates legacy customers.\",\n    \"outcome\": \"Refund rate normalized to 4.5% after Q4 2025 migration completed. Reserve held at 5%.\",\n    \"id\": 14\n  },\n  {\n    \"decision_date\": \"2025-05-30\",\n    \"merchant_name\": \"Brightline Telemedicine\",\n    \"merchant_id_internal\": \"M-prev-2941\",\n    \"mcc\": \"8099\",\n    \"mcc_industry\": \"Medical Services & Health Practitioners NEC\",\n    \"bo_names\": \"Dr. Vincent Hashimoto\",\n    \"metric_profile\": \"CB rate 0.62%, refund rate 4.4%, processing volume $1.2M/mo, exposure score 3\",\n    \"signals_gathered\": \"CB rate elevated in 0.5%-0.7% band over 2 months. Firecrawl confirmed properly licensed telemedicine practice across 18 states. No restricted prescribing detected. Adverse media surfaced general industry coverage of GLP-1 telehealth scrutiny \u2014 not merchant-specific.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Per Reserve Policy by MCC Tier (Tier 3), elevated CB rate warrants reserve adjustment. Reserve increased from 6% to 9%. Industry-level GLP-1 regulatory pressure noted but no merchant-specific exposure identified.\",\n    \"outcome\": \"CB rate stable. Reserve held. Continued monthly monitoring.\",\n    \"id\": 15\n  },\n  {\n    \"decision_date\": \"2025-02-18\",\n    \"merchant_name\": \"Granite Outdoor Gear\",\n    \"merchant_id_internal\": \"M-prev-2787\",\n    \"mcc\": \"5941\",\n    \"mcc_industry\": \"Sporting Goods Stores\",\n    \"bo_names\": \"Catherine Wells\",\n    \"metric_profile\": \"CB rate 0.58%, refund rate 5.4%, processing volume $420K/mo, exposure score 3\",\n    \"signals_gathered\": \"CB rate sustained 0.5%-0.7% over 3 months. Refund rate sustained 4-6%. No restricted content, no litigation, clean OFAC. Customer reviews trended slightly negative on shipping speed.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, sustained CB in 0.5%-0.7% band over 2+ months warrants reserve review and documentation request. Reserve raised from 3% to 5%. Documentation request sent in parallel.\",\n    \"outcome\": \"Merchant addressed shipping bottleneck. CB rate dropped to 0.4% by Q3 2025. Reserve held at 5%.\",\n    \"id\": 16\n  },\n  {\n    \"decision_date\": \"2024-10-22\",\n    \"merchant_name\": \"Sentinel BNPL Partners\",\n    \"merchant_id_internal\": \"M-prev-2712\",\n    \"mcc\": \"6012\",\n    \"mcc_industry\": \"Financial Institutions \u2014 BNPL\",\n    \"bo_names\": \"Devan Krishna\",\n    \"metric_profile\": \"CB rate 0.55%, refund rate 3.1%, processing volume $5.8M/mo, exposure score 4\",\n    \"signals_gathered\": \"Elevated processing volume across BNPL vertical. CB rate sustained 0.5%-0.7% over 2 months. No litigation, no restricted content. CFPB regulatory activity on BNPL ongoing.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Tier 5 MCC with elevated volume requires conservative reserve posture per Reserve Policy by MCC Tier. CB rate elevation in band 0.5%-0.7% triggered review. Reserve raised from 10% to 12%.\",\n    \"outcome\": \"Stable subsequent months. Reserve held.\",\n    \"id\": 17\n  },\n  {\n    \"decision_date\": \"2024-07-14\",\n    \"merchant_name\": \"Magnolia Bakery Express\",\n    \"merchant_id_internal\": \"M-prev-2614\",\n    \"mcc\": \"5462\",\n    \"mcc_industry\": \"Bakeries\",\n    \"bo_names\": \"Sandra McGinnis\",\n    \"metric_profile\": \"CB rate 0.62%, refund rate 3.8%, processing volume $180K/mo, exposure score 2\",\n    \"signals_gathered\": \"Unusual CB rate for low-risk MCC (Tier 1). Documentation request returned: merchant had launched online ordering with weak fraud controls. No restricted content. Clean OFAC and litigation.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, CB rate in 0.5%-0.7% band triggered formal documentation request and reserve review. Root cause identified as fraud-control gap on new online channel. Reserve raised from 0% to 3% as precaution while merchant implements fraud screening.\",\n    \"outcome\": \"Merchant added 3D Secure and address verification. CB rate fell to 0.25% within 2 months. Reserve held at 3%.\",\n    \"id\": 18\n  },\n  {\n    \"decision_date\": \"2024-04-08\",\n    \"merchant_name\": \"Hometown Tackle Outfitters\",\n    \"merchant_id_internal\": \"M-prev-2532\",\n    \"mcc\": \"5941\",\n    \"mcc_industry\": \"Sporting Goods Stores\",\n    \"bo_names\": \"Edward Olson\",\n    \"metric_profile\": \"CB rate 0.51%, refund rate 5.9%, processing volume $310K/mo, exposure score 3\",\n    \"signals_gathered\": \"Both CB and refund rates entering monitoring bands simultaneously. Site classification clean. No litigation. Owner check clean.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Combined elevation of CB and refund rates warrants conservative posture. Reserve raised from 2% to 5%. Documentation request issued in parallel.\",\n    \"outcome\": \"Documentation showed slow product return processing. Merchant streamlined returns. Both rates normalized within 90 days.\",\n    \"id\": 19\n  },\n  {\n    \"decision_date\": \"2024-02-26\",\n    \"merchant_name\": \"Sandstone Auto Detail\",\n    \"merchant_id_internal\": \"M-prev-2451\",\n    \"mcc\": \"7549\",\n    \"mcc_industry\": \"Motor Vehicle Towing & Detailing\",\n    \"bo_names\": \"Miguel Castellanos\",\n    \"metric_profile\": \"CB rate 0.66%, refund rate 4.2%, processing volume $95K/mo, exposure score 3\",\n    \"signals_gathered\": \"Small merchant with elevated CB rate. Documentation request confirmed: dispute over a single high-ticket detailing job. No systemic issue. Clean checks across other signals.\",\n    \"action_taken\": \"raise_reserve\",\n    \"rationale\": \"Reserve precaution for small merchant with concentrated dispute risk. Raised from 0% to 2%.\",\n    \"outcome\": \"Single dispute resolved. CB rate normalized. Reserve held at 2% as ongoing precaution given concentration risk.\",\n    \"id\": 20\n  },\n  {\n    \"decision_date\": \"2026-02-14\",\n    \"merchant_name\": \"Trinity Pharmacy\",\n    \"merchant_id_internal\": \"M00044\",\n    \"mcc\": \"5912\",\n    \"mcc_industry\": \"Drug Stores & Pharmacies\",\n    \"bo_names\": \"Dr. Felicia Monroe\",\n    \"metric_profile\": \"CB rate 0.52%, refund rate 4.6%, processing volume $480K/mo, exposure score 3\",\n    \"signals_gathered\": \"CB rate entered 0.5%-0.7% band. Refund rate entered 4%-6% band. Site classification confirmed proper pharmacy operation. No restricted prescribing detected.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Per Chargeback Threshold Playbook, 0.5%-0.7% CB band triggers formal documentation request via Risk Analyst. Per Refund Rate Monitoring Standards, 4%-6% band triggers documentation request. Combined elevation warrants Risk Analyst follow-up.\",\n    \"outcome\": \"Documentation showed seasonal claim-denial uptick from a major insurer. Issue normalized in Q2.\",\n    \"id\": 21\n  },\n  {\n    \"decision_date\": \"2025-12-03\",\n    \"merchant_name\": \"Westmoreland Books & More\",\n    \"merchant_id_internal\": \"M-prev-3312\",\n    \"mcc\": \"5942\",\n    \"mcc_industry\": \"Bookstores\",\n    \"bo_names\": \"Theresa Kavanagh\",\n    \"metric_profile\": \"CB rate 0.42%, refund rate 4.8%, processing volume $145K/mo, exposure score 2\",\n    \"signals_gathered\": \"Refund rate in 4%-6% band for 2 consecutive months. CB rate elevated for low-risk MCC but below action threshold. Site classification clean. Customer reviews trending normal.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Refund rate trigger only. Documentation request issued to understand return pattern.\",\n    \"outcome\": \"Returns concentrated in a single product line; merchant updated product descriptions to set expectations. Refund rate dropped to 3% in 60 days.\",\n    \"id\": 22\n  },\n  {\n    \"decision_date\": \"2025-09-26\",\n    \"merchant_name\": \"Iron Horse Forge\",\n    \"merchant_id_internal\": \"M-prev-3155\",\n    \"mcc\": \"5712\",\n    \"mcc_industry\": \"Furniture & Home Furnishings\",\n    \"bo_names\": \"Daniel Crawford\",\n    \"metric_profile\": \"CB rate 0.36%, refund rate 5.1%, processing volume $620K/mo, exposure score 2\",\n    \"signals_gathered\": \"Refund rate at 4%-6% band. CB rate normal. Site clean. CourtListener returned 1 closed civil dispute (resolved 2024).\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Single-signal trigger on refund rate per playbook. Risk Analyst documentation request to understand pattern.\",\n    \"outcome\": \"Merchant explained extended return window for custom furniture pieces. Risk Analyst accepted explanation. No further action.\",\n    \"id\": 23\n  },\n  {\n    \"decision_date\": \"2025-06-19\",\n    \"merchant_name\": \"Cascadia Telecom Resellers\",\n    \"merchant_id_internal\": \"M-prev-3001\",\n    \"mcc\": \"4814\",\n    \"mcc_industry\": \"Telecom Services\",\n    \"bo_names\": \"Justin Tahir\",\n    \"metric_profile\": \"CB rate 0.55%, refund rate 3.1%, processing volume $440K/mo, exposure score 3\",\n    \"signals_gathered\": \"CB rate in 0.5%-0.7% band. Refund rate normal. Site clean. Owner check clean.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"CB rate trigger per playbook. Risk Analyst follow-up to understand customer-service patterns.\",\n    \"outcome\": \"Documentation revealed a CRM rollout that confused billing for 60 days. Merchant resolved. CB rate fell to 0.3%.\",\n    \"id\": 24\n  },\n  {\n    \"decision_date\": \"2025-04-30\",\n    \"merchant_name\": \"Skyline Construction Supply\",\n    \"merchant_id_internal\": \"M-prev-2912\",\n    \"mcc\": \"5211\",\n    \"mcc_industry\": \"Lumber & Building Materials\",\n    \"bo_names\": \"Anthony Petrov\",\n    \"metric_profile\": \"CB rate 0.58%, refund rate 3.4%, processing volume $890K/mo, exposure score 3\",\n    \"signals_gathered\": \"Elevated CB rate. Documentation request returned: large B2B disputes over delivery damage drove rate up. Merchant has freight insurance and dispute-resolution protocol.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Single trigger on CB rate. Risk Analyst confirmed root cause non-fraudulent.\",\n    \"outcome\": \"Merchant tightened delivery photo-documentation. CB rate normalized.\",\n    \"id\": 25\n  },\n  {\n    \"decision_date\": \"2025-01-21\",\n    \"merchant_name\": \"Hollow Tree Press\",\n    \"merchant_id_internal\": \"M-prev-2778\",\n    \"mcc\": \"5942\",\n    \"mcc_industry\": \"Bookstores\",\n    \"bo_names\": \"Linda Ferguson\",\n    \"metric_profile\": \"CB rate 0.31%, refund rate 5.6%, processing volume $87K/mo, exposure score 2\",\n    \"signals_gathered\": \"Refund rate elevated. Documentation request returned: holiday-season fulfillment issues. Vendor partner changed in Q1.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Refund rate band trigger. Risk Analyst follow-up.\",\n    \"outcome\": \"Issue resolved with new vendor. No further action.\",\n    \"id\": 26\n  },\n  {\n    \"decision_date\": \"2024-12-04\",\n    \"merchant_name\": \"Beacon Tax Group\",\n    \"merchant_id_internal\": \"M-prev-2721\",\n    \"mcc\": \"8931\",\n    \"mcc_industry\": \"Accounting, Auditing & Bookkeeping\",\n    \"bo_names\": \"Patrick Mehler\",\n    \"metric_profile\": \"CB rate 0.52%, refund rate 6.3%, processing volume $230K/mo, exposure score 2\",\n    \"signals_gathered\": \"Refund rate in 6-8% band coincides with tax-season cancellations. Documentation request confirmed cyclical pattern.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Refund rate trigger per playbook. Risk Analyst documentation request to confirm cyclical nature.\",\n    \"outcome\": \"Pattern confirmed seasonal. Risk Analyst notated for future cycle awareness.\",\n    \"id\": 27\n  },\n  {\n    \"decision_date\": \"2024-08-30\",\n    \"merchant_name\": \"Cardinal Veterinary Group\",\n    \"merchant_id_internal\": \"M-prev-2667\",\n    \"mcc\": \"0742\",\n    \"mcc_industry\": \"Veterinary Services\",\n    \"bo_names\": \"Dr. Margot Lin\",\n    \"metric_profile\": \"CB rate 0.41%, refund rate 4.7%, processing volume $215K/mo, exposure score 2\",\n    \"signals_gathered\": \"Refund rate elevated. Documentation: refund pattern tied to a specific procedure with high client dissatisfaction. Merchant updated informed-consent protocol.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Refund rate trigger.\",\n    \"outcome\": \"Refund rate normalized.\",\n    \"id\": 28\n  },\n  {\n    \"decision_date\": \"2024-05-17\",\n    \"merchant_name\": \"Polaris Adventure Tours\",\n    \"merchant_id_internal\": \"M-prev-2548\",\n    \"mcc\": \"4722\",\n    \"mcc_industry\": \"Travel Agencies & Tour Operators\",\n    \"bo_names\": \"Henrik Sorensen\",\n    \"metric_profile\": \"CB rate 0.49%, refund rate 5.8%, processing volume $510K/mo, exposure score 3\",\n    \"signals_gathered\": \"Refund rate in band. Documentation returned: weather-related cancellation refunds drove rate during peak season.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Travel vertical naturally has refund cyclicality. Documentation request to confirm.\",\n    \"outcome\": \"Cyclical pattern confirmed. Notated for future review.\",\n    \"id\": 29\n  },\n  {\n    \"decision_date\": \"2024-03-12\",\n    \"merchant_name\": \"Tessera Software Group\",\n    \"merchant_id_internal\": \"M-prev-2482\",\n    \"mcc\": \"7372\",\n    \"mcc_industry\": \"Computer Programming\",\n    \"bo_names\": \"Ryan Wozniak\",\n    \"metric_profile\": \"CB rate 0.38%, refund rate 5.2%, processing volume $710K/mo, exposure score 3\",\n    \"signals_gathered\": \"Refund rate in 4-6% band. Documentation: SaaS auto-renewal disputes during Q1.\",\n    \"action_taken\": \"request_docs\",\n    \"rationale\": \"Refund rate trigger; documentation to understand auto-renewal disclosure practices.\",\n    \"outcome\": \"Merchant updated renewal disclosures and reminder emails. Refund rate dropped to 3.1%.\",\n    \"id\": 30\n  },\n  {\n    \"decision_date\": \"2026-04-05\",\n    \"merchant_name\": \"Brick Lane Coffee Roasters\",\n    \"merchant_id_internal\": \"M00001\",\n    \"mcc\": \"5814\",\n    \"mcc_industry\": \"Eating Places & Restaurants\",\n    \"bo_names\": \"Sarah Mitchell\",\n    \"metric_profile\": \"CB rate 0.18%, refund rate 1.4%, processing volume $145K/mo, exposure score 1\",\n    \"signals_gathered\": \"All metrics in normal-low bands. Site classification clean. No litigation, no OFAC hits, normal Google reviews (4.7 avg).\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"All signals well within normal bands. Routine monthly review confirmed no issues.\",\n    \"outcome\": \"Continued normal operation.\",\n    \"id\": 31\n  },\n  {\n    \"decision_date\": \"2026-01-15\",\n    \"merchant_name\": \"Sycamore & Oak Bistro\",\n    \"merchant_id_internal\": \"M00003\",\n    \"mcc\": \"5814\",\n    \"mcc_industry\": \"Eating Places & Restaurants\",\n    \"bo_names\": \"Elena Park\",\n    \"metric_profile\": \"CB rate 0.21%, refund rate 1.8%, processing volume $98K/mo, exposure score 1\",\n    \"signals_gathered\": \"All clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine review; no triggers.\",\n    \"outcome\": \"Continued normal operation.\",\n    \"id\": 32\n  },\n  {\n    \"decision_date\": \"2025-11-29\",\n    \"merchant_name\": \"Aurora Vape Supply\",\n    \"merchant_id_internal\": \"M00039\",\n    \"mcc\": \"5993\",\n    \"mcc_industry\": \"Cigar Stores & Stands (vape)\",\n    \"bo_names\": \"Devin Holcomb\",\n    \"metric_profile\": \"CB rate 0.42%, refund rate 4.8%, processing volume $310K/mo, exposure score 4\",\n    \"signals_gathered\": \"Elevated metrics for vertical but stable. Firecrawl confirmed legitimate licensed retail. No restricted product. FDA inquiry into industry broadly but not merchant-specific.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Metrics stable in elevated-but-not-actionable bands. Merchant has legitimate licensing. Industry-level news does not warrant individual action. Continue monitoring.\",\n    \"outcome\": \"Continued monthly monitoring.\",\n    \"id\": 33\n  },\n  {\n    \"decision_date\": \"2025-10-15\",\n    \"merchant_name\": \"Northbridge Gear Shop\",\n    \"merchant_id_internal\": \"M00028\",\n    \"mcc\": \"5941\",\n    \"mcc_industry\": \"Sporting Goods Stores\",\n    \"bo_names\": \"Ethan Caldwell\",\n    \"metric_profile\": \"CB rate 0.28%, refund rate 3.2%, processing volume $475K/mo, exposure score 2\",\n    \"signals_gathered\": \"All normal.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine review.\",\n    \"outcome\": \"No change.\",\n    \"id\": 34\n  },\n  {\n    \"decision_date\": \"2025-09-04\",\n    \"merchant_name\": \"Polaris Software\",\n    \"merchant_id_internal\": \"M00026\",\n    \"mcc\": \"7372\",\n    \"mcc_industry\": \"Computer Programming\",\n    \"bo_names\": \"Daniel Foster\",\n    \"metric_profile\": \"CB rate 0.22%, refund rate 3.6%, processing volume $820K/mo, exposure score 2\",\n    \"signals_gathered\": \"Clean across the board.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"No triggers.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 35\n  },\n  {\n    \"decision_date\": \"2025-08-11\",\n    \"merchant_name\": \"Meadowlark Books\",\n    \"merchant_id_internal\": \"M00008\",\n    \"mcc\": \"5942\",\n    \"mcc_industry\": \"Bookstores\",\n    \"bo_names\": \"Henrik Olson\",\n    \"metric_profile\": \"CB rate 0.12%, refund rate 1.1%, processing volume $58K/mo, exposure score 1\",\n    \"signals_gathered\": \"All clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 36\n  },\n  {\n    \"decision_date\": \"2025-07-25\",\n    \"merchant_name\": \"Beacon Telecom\",\n    \"merchant_id_internal\": \"M00032\",\n    \"mcc\": \"4814\",\n    \"mcc_industry\": \"Telecom Services\",\n    \"bo_names\": \"Joshua Patel\",\n    \"metric_profile\": \"CB rate 0.31%, refund rate 2.8%, processing volume $590K/mo, exposure score 2\",\n    \"signals_gathered\": \"Normal.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 37\n  },\n  {\n    \"decision_date\": \"2025-06-30\",\n    \"merchant_name\": \"Smokehouse Cigars\",\n    \"merchant_id_internal\": \"M00049\",\n    \"mcc\": \"5993\",\n    \"mcc_industry\": \"Cigar Stores\",\n    \"bo_names\": \"Andre Pollard\",\n    \"metric_profile\": \"CB rate 0.38%, refund rate 3.2%, processing volume $215K/mo, exposure score 4\",\n    \"signals_gathered\": \"Elevated tier but metrics stable. Licensed. Clean checks across other signals.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Tier 4 with stable metrics; conservative reserve already in place. No new signal to trigger action.\",\n    \"outcome\": \"Continued monitoring.\",\n    \"id\": 38\n  },\n  {\n    \"decision_date\": \"2025-05-22\",\n    \"merchant_name\": \"Harborfront Veterinary\",\n    \"merchant_id_internal\": \"M00010\",\n    \"mcc\": \"0742\",\n    \"mcc_industry\": \"Veterinary Services\",\n    \"bo_names\": \"Dr. Anna Whitfield\",\n    \"metric_profile\": \"CB rate 0.09%, refund rate 1.6%, processing volume $135K/mo, exposure score 1\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 39\n  },\n  {\n    \"decision_date\": \"2025-04-18\",\n    \"merchant_name\": \"Argonaut Logistics\",\n    \"merchant_id_internal\": \"M00020\",\n    \"mcc\": \"4814\",\n    \"mcc_industry\": \"Telecom Services\",\n    \"bo_names\": \"Sofia Demir\",\n    \"metric_profile\": \"CB rate 0.18%, refund rate 2.1%, processing volume $325K/mo, exposure score 2\",\n    \"signals_gathered\": \"Normal.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine review.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 40\n  },\n  {\n    \"decision_date\": \"2025-03-15\",\n    \"merchant_name\": \"Saffron Table\",\n    \"merchant_id_internal\": \"M00016\",\n    \"mcc\": \"5814\",\n    \"mcc_industry\": \"Eating Places & Restaurants\",\n    \"bo_names\": \"Reza Soltani\",\n    \"metric_profile\": \"CB rate 0.16%, refund rate 1.9%, processing volume $112K/mo, exposure score 1\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 41\n  },\n  {\n    \"decision_date\": \"2025-02-08\",\n    \"merchant_name\": \"Iron Mesa Software\",\n    \"merchant_id_internal\": \"M00031\",\n    \"mcc\": \"7372\",\n    \"mcc_industry\": \"Computer Programming\",\n    \"bo_names\": \"Brett Aldridge\",\n    \"metric_profile\": \"CB rate 0.28%, refund rate 4.1%, processing volume $610K/mo, exposure score 3\",\n    \"signals_gathered\": \"Refund rate touching 4% threshold but not sustained. Documentation request not warranted per single-month data.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Single-month elevation; will trigger documentation request if sustained next month per playbook.\",\n    \"outcome\": \"Refund rate normalized to 3.2% next month.\",\n    \"id\": 42\n  },\n  {\n    \"decision_date\": \"2025-01-08\",\n    \"merchant_name\": \"Anchor Tax Advisors\",\n    \"merchant_id_internal\": \"M00002\",\n    \"mcc\": \"8931\",\n    \"mcc_industry\": \"Accounting\",\n    \"bo_names\": \"David Reyes\",\n    \"metric_profile\": \"CB rate 0.08%, refund rate 2.4%, processing volume $89K/mo, exposure score 1\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 43\n  },\n  {\n    \"decision_date\": \"2024-12-21\",\n    \"merchant_name\": \"Crescent Moon Bakery\",\n    \"merchant_id_internal\": \"M00005\",\n    \"mcc\": \"5462\",\n    \"mcc_industry\": \"Bakeries\",\n    \"bo_names\": \"Aisha Pham\",\n    \"metric_profile\": \"CB rate 0.12%, refund rate 1.5%, processing volume $43K/mo, exposure score 1\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 44\n  },\n  {\n    \"decision_date\": \"2024-11-19\",\n    \"merchant_name\": \"Bayfront Ad Agency\",\n    \"merchant_id_internal\": \"M00030\",\n    \"mcc\": \"7311\",\n    \"mcc_industry\": \"Advertising Services\",\n    \"bo_names\": \"Christine Halloway\",\n    \"metric_profile\": \"CB rate 0.21%, refund rate 3.6%, processing volume $440K/mo, exposure score 2\",\n    \"signals_gathered\": \"Normal.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 45\n  },\n  {\n    \"decision_date\": \"2024-09-26\",\n    \"merchant_name\": \"Driftwood Goods\",\n    \"merchant_id_internal\": \"M00007\",\n    \"mcc\": \"5712\",\n    \"mcc_industry\": \"Furniture & Home Furnishings\",\n    \"bo_names\": \"Linnea Berg\",\n    \"metric_profile\": \"CB rate 0.19%, refund rate 3.8%, processing volume $228K/mo, exposure score 1\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 46\n  },\n  {\n    \"decision_date\": \"2024-08-04\",\n    \"merchant_name\": \"Heritage Plumbing Co\",\n    \"merchant_id_internal\": \"M00006\",\n    \"mcc\": \"7311\",\n    \"mcc_industry\": \"Advertising Services (mis-coded \u2014 actually plumbing)\",\n    \"bo_names\": \"Thomas Riley\",\n    \"metric_profile\": \"CB rate 0.14%, refund rate 0.9%, processing volume $87K/mo, exposure score 1\",\n    \"signals_gathered\": \"MCC mismatch flagged for review \u2014 merchant is plumbing, MCC says advertising. Re-classification requested but no risk impact (both Tier 1-2 MCCs).\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"MCC mis-coding flagged for re-classification. No restricted product, no risk implications. Mis-coding does not trigger Restricted Business Types Policy because the actual vertical is not on the restricted list.\",\n    \"outcome\": \"MCC corrected to 1711 (Plumbing) in Q4 2024. No risk action needed.\",\n    \"id\": 47\n  },\n  {\n    \"decision_date\": \"2024-07-09\",\n    \"merchant_name\": \"Sunrise Wellness Center\",\n    \"merchant_id_internal\": \"M-prev-2628\",\n    \"mcc\": \"8099\",\n    \"mcc_industry\": \"Medical Services NEC\",\n    \"bo_names\": \"Dr. Naomi Brennan\",\n    \"metric_profile\": \"CB rate 0.34%, refund rate 4.2%, processing volume $295K/mo, exposure score 3\",\n    \"signals_gathered\": \"Refund rate just over 4% threshold. Single-month elevation. No restricted prescribing detected. Properly licensed.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Single-month elevation does not sustain 2-month rule. Continue monitoring.\",\n    \"outcome\": \"Refund rate fell to 3.4% next month.\",\n    \"id\": 48\n  },\n  {\n    \"decision_date\": \"2024-06-18\",\n    \"merchant_name\": \"Three Sisters Tavern\",\n    \"merchant_id_internal\": \"M00009\",\n    \"mcc\": \"5814\",\n    \"mcc_industry\": \"Eating Places & Restaurants\",\n    \"bo_names\": \"Maeve O'Connor, Catherine O'Connor\",\n    \"metric_profile\": \"CB rate 0.22%, refund rate 1.8%, processing volume $148K/mo, exposure score 1\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 49\n  },\n  {\n    \"decision_date\": \"2024-05-04\",\n    \"merchant_name\": \"Lighthouse Analytics\",\n    \"merchant_id_internal\": \"M00027\",\n    \"mcc\": \"7372\",\n    \"mcc_industry\": \"Computer Programming\",\n    \"bo_names\": \"Vikram Anand\",\n    \"metric_profile\": \"CB rate 0.17%, refund rate 2.9%, processing volume $560K/mo, exposure score 2\",\n    \"signals_gathered\": \"Clean.\",\n    \"action_taken\": \"no_action\",\n    \"rationale\": \"Routine.\",\n    \"outcome\": \"Normal.\",\n    \"id\": 50\n  }\n];\n\nreturn decisions.map(d => ({ json: d }));"
      },
      "typeVersion": 2
    },
    {
      "id": "9abf2798-e1d5-4235-95e2-d7973e6a6599",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        576
      ],
      "parameters": {
        "content": "Common Risk APIs, feel free to switch these, add remove as needed"
      },
      "typeVersion": 1
    },
    {
      "id": "bc16c0d6-f9ab-451e-8bd1-9b19f04d0b4f",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -352
      ],
      "parameters": {
        "color": 7,
        "width": 2256,
        "height": 640,
        "content": "## MCC/Industry\n\nResearches the industries the Portfolio has"
      },
      "typeVersion": 1
    },
    {
      "id": "01d796f0-e1d5-46d3-be79-689e3b1c8440",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 2576,
        "height": 1520,
        "content": "## High Risk (Account or MCC) or Watch Accounts\n\nResearches the industries the Portfolio has"
      },
      "typeVersion": 1
    },
    {
      "id": "d88e2099-75b2-403c-a60c-40993330369b",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        528,
        2544
      ],
      "parameters": {
        "color": 7,
        "width": 1616,
        "height": 640,
        "content": "## Portfolio Metrics\n\nData across all processing merchants"
      },
      "typeVersion": 1
    },
    {
      "id": "d3b3dd11-4935-4486-8e3a-f55a4f8e4923",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3520,
        768
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 448,
        "content": "## Workflow Logging\n\nLog showing all the actions taken across the MCC codes and merchants"
      },
      "typeVersion": 1
    },
    {
      "id": "ae180ca6-d7ca-439e-b21b-c583211b4d8a",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        832
      ],
      "parameters": {
        "width": 256,
        "height": 80,
        "content": "Need to setup Workflow 1 before running this"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "53948878-5787-4c1a-ad90-7c7995a526dc",
  "nodeGroups": [],
  "connections": {
    "Resolve Month": {
      "main": [
        [
          {
            "node": "Supabase: monthly_manifest",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: mcc_risk_snapshots",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: mcc_codes",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: recommended_actions",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: portfolio_snapshots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initialize Run": {
      "main": [
        [
          {
            "node": "Supabase: Get Active Merchants",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: Get MCC Codes",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: Get High-Risk Merchants",
            "type": "main",
            "index": 0
          },
          {
            "node": "Supabase: Portfolio Metrics (12 mo)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Risk Decisions Past Examples",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude: MCC Agent": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: MCC Risk Rating",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Merge All Branches": {
      "main": [
        [
          {
            "node": "Build Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monthly on the 1st": {
      "main": [
        [
          {
            "node": "Initialize Run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge: All Branches": {
      "main": [
        [
          {
            "node": "Build Monthly Manifest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: mcc_codes": {
      "main": [
        [
          {
            "node": "Merge All Branches",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Parser: MCC Snapshot": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent: MCC Risk Rating",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Apify: Google Reviews": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 4
          }
        ]
      ]
    },
    "Tavily: Adverse Media": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 5
          }
        ]
      ]
    },
    "Build Monthly Manifest": {
      "main": [
        [
          {
            "node": "Supabase: Insert monthly_manifest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate MCC Snapshots": {
      "main": [
        [
          {
            "node": "Merge: All Branches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Character Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Prior Decision Document Loader",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    },
    "Claude: Portfolio Agent": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Portfolio Narrative",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Get MCC Codes": {
      "main": [
        [
          {
            "node": "Merge: Merchants + MCC Codes",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Compute Portfolio Trends": {
      "main": [
        [
          {
            "node": "AI Agent: Portfolio Narrative",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Monthly Data Webhook": {
      "main": [
        [
          {
            "node": "Resolve Month",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge: Merchant Findings": {
      "main": [
        [
          {
            "node": "Aggregate Merchant Findings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: MCC Risk Rating": {
      "main": [
        [
          {
            "node": "Supabase: Upsert MCC Snapshot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: Classify Website": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 6
          }
        ]
      ]
    },
    "Aggregate Account Findings": {
      "main": [
        [
          {
            "node": "Merge: All Branches",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Claude: Website Classifier": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Classify Website",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "CourtListener: Owner Cases": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Parser: Recommended Action": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent: Risk Recommendation",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Perplexity: MCC News (30d)": {
      "main": [
        [
          {
            "node": "AI Agent: MCC Risk Rating",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: monthly_manifest": {
      "main": [
        [
          {
            "node": "Merge All Branches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Merchant Findings": {
      "main": [
        [
          {
            "node": "AI Agent: Risk Recommendation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI: Pinecone Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "Pinecone: Prior Risk Decisions",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "OpenSanctions: Owner Screen": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Claude: Recommendation Agent": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Risk Recommendation",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "CourtListener: Company Cases": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Merge: Merchants + MCC Codes": {
      "main": [
        [
          {
            "node": "Perplexity: MCC News (30d)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Risk Decisions Past Examples": {
      "main": [
        [
          {
            "node": "Pinecone: Insert Prior Decisions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: mcc_risk_snapshots": {
      "main": [
        [
          {
            "node": "Merge All Branches",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "AI Agent: Portfolio Narrative": {
      "main": [
        [
          {
            "node": "Supabase: Insert portfolio_snapshot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: Risk Recommendation": {
      "main": [
        [
          {
            "node": "Supabase: Insert recommended_action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenSanctions: Company Screen": {
      "main": [
        [
          {
            "node": "Merge: Merchant Findings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Upsert MCC Snapshot": {
      "main": [
        [
          {
            "node": "Aggregate MCC Snapshots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: portfolio_snapshots": {
      "main": [
        [
          {
            "node": "Merge All Branches",
            "type": "main",
            "index": 4
          }
        ]
      ]
    },
    "Supabase: recommended_actions": {
      "main": [
        [
          {
            "node": "Merge All Branches",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Pinecone: Prior Risk Decisions": {
      "ai_tool": [
        [
          {
            "node": "AI Agent: Risk Recommendation",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Prior Decision Document Loader": {
      "ai_document": [
        [
          {
            "node": "Pinecone: Insert Prior Decisions",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Get Active Merchants": {
      "main": [
        [
          {
            "node": "Code: Distinct MCCs + Top Accounts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Firecrawl: Scrape Merchant Site": {
      "main": [
        [
          {
            "node": "AI Agent: Classify Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Get High-Risk Merchants": {
      "main": [
        [
          {
            "node": "OpenSanctions: Company Screen",
            "type": "main",
            "index": 0
          },
          {
            "node": "OpenSanctions: Owner Screen",
            "type": "main",
            "index": 0
          },
          {
            "node": "CourtListener: Company Cases",
            "type": "main",
            "index": 0
          },
          {
            "node": "CourtListener: Owner Cases",
            "type": "main",
            "index": 0
          },
          {
            "node": "Apify: Google Reviews",
            "type": "main",
            "index": 0
          },
          {
            "node": "Tavily: Adverse Media",
            "type": "main",
            "index": 0
          },
          {
            "node": "Firecrawl: Scrape Merchant Site",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Distinct MCCs + Top Accounts": {
      "main": [
        [
          {
            "node": "Merge: Merchants + MCC Codes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Insert portfolio_snapshot": {
      "main": [
        [
          {
            "node": "Merge: All Branches",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Supabase: Insert recommended_action": {
      "main": [
        [
          {
            "node": "Aggregate Account Findings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Portfolio Metrics (12 mo)": {
      "main": [
        [
          {
            "node": "Compute Portfolio Trends",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Embeddings (text-embedding-3-small)": {
      "ai_embedding": [
        [
          {
            "node": "Pinecone: Insert Prior Decisions",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    }
  }
}