{
  "apiVersion": 63,
  "status": "Active",
  "label": "Standard Convert Lead",
  "description": "Salesforce-compatible Lead Convert: validates the Lead, creates or reuses Account/Contact/Opportunity, and marks the Lead converted. Runs atomically; a failure at any step rolls back all record changes.",
  "runAtomically": true,
  "atomicParentPrelocks": [
    {
      "name": "ExistingAccount",
      "parentObject": "Account",
      "sourceObject": "Account",
      "parentReferenceField": "Id",
      "filters": [
        { "field": "Id", "operator": "EqualTo", "value": { "elementReference": "accountId" } }
      ]
    },
    {
      "name": "LeadCampaignMemberships",
      "parentObject": "Campaign",
      "sourceObject": "CampaignMember",
      "parentReferenceField": "CampaignId",
      "filters": [
        { "field": "LeadId", "operator": "EqualTo", "value": { "elementReference": "leadId" } }
      ]
    }
  ],
  "start": {
    "locationX": 40,
    "locationY": 0,
    "connector": { "targetReference": "GetLead" }
  },
  "variables": [
    { "name": "leadId", "dataType": "String", "isInput": true, "isOutput": true },
    { "name": "convertedStatus", "dataType": "String", "isInput": true },
    { "name": "accountId", "dataType": "String", "isInput": true, "isOutput": true },
    { "name": "contactId", "dataType": "String", "isInput": true, "isOutput": true },
    { "name": "contactFirstName", "dataType": "String", "isInput": true },
    { "name": "contactLastName", "dataType": "String", "isInput": true },
    { "name": "contactTitle", "dataType": "String", "isInput": true },
    { "name": "contactEmail", "dataType": "String", "isInput": true },
    { "name": "opportunityId", "dataType": "String", "isInput": true, "isOutput": true },
    { "name": "opportunityName", "dataType": "String", "isInput": true },
    { "name": "doNotCreateOpportunity", "dataType": "Boolean", "isInput": true },
    { "name": "ownerId", "dataType": "String", "isInput": true },
    { "name": "overwriteLeadSource", "dataType": "Boolean", "isInput": true }
  ],
  "recordLookups": [
    {
      "name": "GetLead",
      "label": "Get Lead",
      "locationX": 40,
      "locationY": 120,
      "object": "Lead",
      "filters": [
        { "field": "Id", "operator": "EqualTo", "value": { "elementReference": "leadId" } }
      ],
      "outputReference": "$lead",
      "getFirstRecordOnly": true,
      "connector": { "targetReference": "ValidateLeadExists" }
    },
    {
      "name": "GetAccountById",
      "label": "Get Account by Id",
      "locationX": 220,
      "locationY": 360,
      "object": "Account",
      "filters": [
        { "field": "Id", "operator": "EqualTo", "value": { "elementReference": "accountId" } }
      ],
      "outputReference": "$account",
      "getFirstRecordOnly": true,
      "connector": { "targetReference": "ValidateAccountReuse" }
    },
    {
      "name": "GetContactById",
      "label": "Get Contact by Id",
      "locationX": 220,
      "locationY": 600,
      "object": "Contact",
      "filters": [
        { "field": "Id", "operator": "EqualTo", "value": { "elementReference": "contactId" } }
      ],
      "outputReference": "$contact",
      "getFirstRecordOnly": true,
      "connector": { "targetReference": "ValidateContactReuse" }
    },
    {
      "name": "GetOpportunityById",
      "label": "Get Opportunity by Id",
      "locationX": 220,
      "locationY": 840,
      "object": "Opportunity",
      "filters": [
        { "field": "Id", "operator": "EqualTo", "value": { "elementReference": "opportunityId" } }
      ],
      "outputReference": "$opportunity",
      "getFirstRecordOnly": true,
      "connector": { "targetReference": "ValidateOpportunityReuse" }
    },
    {
      "name": "GetPrimaryCampaignMember",
      "label": "Get newest CampaignMember for primary campaign source",
      "locationX": 220,
      "locationY": 1140,
      "object": "CampaignMember",
      "filters": [
        { "field": "LeadId", "operator": "EqualTo", "value": { "elementReference": "leadId" } }
      ],
      "outputReference": "$primaryCM",
      "getFirstRecordOnly": true,
      "sortField": "CreatedDate",
      "sortOrder": "DESC",
      "connector": { "targetReference": "CreateOpportunity" }
    }
  ],
  "decisions": [
    {
      "name": "ValidateLeadExists",
      "label": "Reject if leadId does not resolve",
      "description": "GetLead stores nil on the $lead reference when the id misses (record doesn't exist or RLS/sharing hides it). Without this gate, the next decision evaluates $lead.IsConverted against nil, falls through, and the first downstream recordCreate with fieldMapping.sourceReference=$lead raises a misleading 'source is not an SObject' internal error. Fail loudly here with SF-native MALFORMED_ID.",
      "locationX": 220,
      "locationY": 180,
      "rules": [
        {
          "name": "LeadNotFound",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$lead.Id", "operator": "IsBlank" }
          ],
          "connector": { "targetReference": "FailInvalidLeadId" }
        }
      ],
      "defaultConnector": { "targetReference": "CheckAlreadyConverted" }
    },
    {
      "name": "CheckAlreadyConverted",
      "label": "Reject if already converted",
      "locationX": 40,
      "locationY": 240,
      "rules": [
        {
          "name": "AlreadyConverted",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$lead.IsConverted", "operator": "EqualTo", "rightValue": true }
          ],
          "connector": { "targetReference": "FailAlreadyConverted" }
        }
      ],
      "defaultConnector": { "targetReference": "ResolveAccount" }
    },
    {
      "name": "ResolveAccount",
      "label": "Resolve Account",
      "locationX": 40,
      "locationY": 360,
      "rules": [
        {
          "name": "ExistingAccount",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "accountId", "operator": "IsNotBlank" }
          ],
          "connector": { "targetReference": "GetAccountById" }
        }
      ],
      "defaultConnector": { "targetReference": "CreateAccount" }
    },
    {
      "name": "ResolveContact",
      "label": "Resolve Contact",
      "locationX": 40,
      "locationY": 600,
      "rules": [
        {
          "name": "ExistingContact",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "contactId", "operator": "IsNotBlank" }
          ],
          "connector": { "targetReference": "GetContactById" }
        }
      ],
      "defaultConnector": { "targetReference": "CreateContact" }
    },
    {
      "name": "ResolveOpportunity",
      "label": "Resolve Opportunity",
      "locationX": 40,
      "locationY": 840,
      "rules": [
        {
          "name": "SkipOpportunity",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "doNotCreateOpportunity", "operator": "EqualTo", "rightValue": true }
          ],
          "connector": { "targetReference": "SyncOpportunityContactRole" }
        },
        {
          "name": "ReuseOpportunity",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "opportunityId", "operator": "IsNotBlank" }
          ],
          "connector": { "targetReference": "GetOpportunityById" }
        }
      ],
      "defaultConnector": { "targetReference": "ResolveOpportunityName" }
    },
    {
      "name": "ResolveOpportunityName",
      "label": "Default Opportunity Name if blank",
      "locationX": 40,
      "locationY": 960,
      "rules": [
        {
          "name": "OpportunityNameBlank",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "opportunityName", "operator": "IsBlank" }
          ],
          "connector": { "targetReference": "SetDefaultOpportunityName" }
        }
      ],
      "defaultConnector": { "targetReference": "GetPrimaryCampaignMember" }
    },
    {
      "name": "ValidateAccountReuse",
      "label": "Reject caller-supplied accountId that does not resolve",
      "locationX": 400,
      "locationY": 360,
      "rules": [
        {
          "name": "AccountNotFound",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$account.Id", "operator": "IsBlank" }
          ],
          "connector": { "targetReference": "FailInvalidAccountId" }
        }
      ],
      "defaultConnector": { "targetReference": "MergeAccountFields" }
    },
    {
      "name": "ValidateContactReuse",
      "label": "Reject caller-supplied contactId that does not resolve",
      "locationX": 400,
      "locationY": 600,
      "rules": [
        {
          "name": "ContactNotFound",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$contact.Id", "operator": "IsBlank" }
          ],
          "connector": { "targetReference": "FailInvalidContactId" }
        }
      ],
      "defaultConnector": { "targetReference": "ValidateContactAccountConsistency" }
    },
    {
      "name": "ValidateContactAccountConsistency",
      "label": "Reject reused Contact whose AccountId differs from the converted Account",
      "description": "The Lead's ConvertedAccountId and ConvertedContactId must refer to records in the same Account tree. The reuse contract is: caller asserts `contactId` already belongs to `accountId`. The conversion update changes ONLY the Lead — it does NOT reparent the reused Contact — so any slack here produces an inconsistent (ConvertedAccountId=A, ConvertedContactId=<C tied to B>) stamp. Strict equality: blank Contact.AccountId is still a mismatch against a concrete accountId, so we do NOT add an `IsNotBlank` escape hatch here (earlier revisions had one — see commit history).",
      "locationX": 580,
      "locationY": 600,
      "rules": [
        {
          "name": "ContactAccountMismatch",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$contact.AccountId", "operator": "NotEqualTo", "rightValue": { "elementReference": "accountId" } }
          ],
          "connector": { "targetReference": "FailContactAccountMismatch" }
        }
      ],
      "defaultConnector": { "targetReference": "MergeContactFields" }
    },
    {
      "name": "MaybeUpdateContactOwner",
      "label": "Update reused Contact owner when ownerId is supplied",
      "locationX": 580,
      "locationY": 660,
      "rules": [
        {
          "name": "OwnerSuppliedForContact",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "ownerId", "operator": "IsNotBlank" }
          ],
          "connector": { "targetReference": "UpdateContactOwner" }
        }
      ],
      "defaultConnector": { "targetReference": "MaybeOverwriteContactLeadSource" }
    },
    {
      "name": "MaybeOverwriteContactLeadSource",
      "label": "Overwrite reused Contact LeadSource when requested",
      "locationX": 580,
      "locationY": 720,
      "rules": [
        {
          "name": "OverwriteLeadSourceRequested",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "overwriteLeadSource", "operator": "EqualTo", "rightValue": true }
          ],
          "connector": { "targetReference": "UpdateContactLeadSource" }
        }
      ],
      "defaultConnector": { "targetReference": "ResolveOpportunity" }
    },
    {
      "name": "ValidateOpportunityReuse",
      "label": "Reject caller-supplied opportunityId that does not resolve",
      "locationX": 400,
      "locationY": 840,
      "rules": [
        {
          "name": "OpportunityNotFound",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$opportunity.Id", "operator": "IsBlank" }
          ],
          "connector": { "targetReference": "FailInvalidOpportunityId" }
        }
      ],
      "defaultConnector": { "targetReference": "ValidateOpportunityAccountConsistency" }
    },
    {
      "name": "ValidateOpportunityAccountConsistency",
      "label": "Reject reused Opportunity whose AccountId differs from the converted Account",
      "description": "Same strict-equality invariant as ValidateContactAccountConsistency applied to the opportunity reuse path. A reused Opportunity with blank AccountId is still a mismatch against a concrete accountId — the conversion update does not reparent the Opportunity, so a silent pass here leaves an inconsistent Lead.ConvertedOpportunityId.",
      "locationX": 580,
      "locationY": 840,
      "rules": [
        {
          "name": "OpportunityAccountMismatch",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "$opportunity.AccountId", "operator": "NotEqualTo", "rightValue": { "elementReference": "accountId" } }
          ],
          "connector": { "targetReference": "FailOpportunityAccountMismatch" }
        }
      ],
      "defaultConnector": { "targetReference": "MaybeUpdateOpportunityOwner" }
    },
    {
      "name": "MaybeUpdateOpportunityOwner",
      "label": "Update reused Opportunity owner when ownerId is supplied",
      "locationX": 580,
      "locationY": 900,
      "rules": [
        {
          "name": "OwnerSuppliedForOpportunity",
          "conditionLogic": "and",
          "conditions": [
            { "leftValueReference": "ownerId", "operator": "IsNotBlank" }
          ],
          "connector": { "targetReference": "UpdateOpportunityOwner" }
        }
      ],
      "defaultConnector": { "targetReference": "SyncOpportunityContactRole" }
    }
  ],
  "assignments": [
    {
      "name": "SetDefaultOpportunityName",
      "label": "Default Opportunity.Name = Lead.Company",
      "locationX": 220,
      "locationY": 1080,
      "assignmentItems": [
        {
          "assignToReference": "opportunityName",
          "operator": "Assign",
          "value": { "elementReference": "$lead.Company" }
        }
      ],
      "connector": { "targetReference": "GetPrimaryCampaignMember" }
    }
  ],
  "customErrors": [
    {
      "name": "FailInvalidLeadId",
      "label": "Invalid leadId supplied",
      "locationX": 400,
      "locationY": 180,
      "customErrorMessages": [
        { "errorMessage": "leadId does not refer to a Lead the current user can access", "statusCode": "MALFORMED_ID" }
      ]
    },
    {
      "name": "FailAlreadyConverted",
      "label": "Lead is already converted",
      "locationX": 220,
      "locationY": 240,
      "customErrorMessages": [
        { "errorMessage": "Lead is already converted", "statusCode": "ALREADY_CONVERTED" }
      ]
    },
    {
      "name": "FailInvalidAccountId",
      "label": "Invalid accountId supplied for reuse",
      "locationX": 580,
      "locationY": 360,
      "customErrorMessages": [
        { "errorMessage": "accountId does not refer to an Account the current user can access", "statusCode": "MALFORMED_ID" }
      ]
    },
    {
      "name": "FailInvalidContactId",
      "label": "Invalid contactId supplied for reuse",
      "locationX": 580,
      "locationY": 600,
      "customErrorMessages": [
        { "errorMessage": "contactId does not refer to a Contact the current user can access", "statusCode": "MALFORMED_ID" }
      ]
    },
    {
      "name": "FailInvalidOpportunityId",
      "label": "Invalid opportunityId supplied for reuse",
      "locationX": 580,
      "locationY": 840,
      "customErrorMessages": [
        { "errorMessage": "opportunityId does not refer to an Opportunity the current user can access", "statusCode": "MALFORMED_ID" }
      ]
    },
    {
      "name": "FailContactAccountMismatch",
      "label": "Reused Contact belongs to a different Account",
      "locationX": 760,
      "locationY": 600,
      "customErrorMessages": [
        { "errorMessage": "Reused contactId belongs to a different Account than the one selected for this Lead Convert. Contact.AccountId must equal the resolved accountId.", "statusCode": "INVALID_CROSS_REFERENCE_KEY" }
      ]
    },
    {
      "name": "FailOpportunityAccountMismatch",
      "label": "Reused Opportunity belongs to a different Account",
      "locationX": 760,
      "locationY": 840,
      "customErrorMessages": [
        { "errorMessage": "Reused opportunityId belongs to a different Account than the one selected for this Lead Convert. Opportunity.AccountId must equal the resolved accountId.", "statusCode": "INVALID_CROSS_REFERENCE_KEY" }
      ]
    }
  ],
  "recordCreates": [
    {
      "name": "CreateAccount",
      "label": "Create Account from Lead",
      "locationX": 40,
      "locationY": 480,
      "object": "Account",
      "fieldMapping": {
        "sourceObject": "Lead",
        "sourceReference": "$lead",
        "targetObject": "Account",
        "actionType": "convert"
      },
      "inputAssignments": [
        { "field": "Name", "value": { "elementReference": "$lead.Company" } }
      ],
      "assignRecordIdToReference": "accountId",
      "connector": { "targetReference": "ResolveContact" }
    },
    {
      "name": "CreateContact",
      "label": "Create Contact from Lead",
      "locationX": 40,
      "locationY": 720,
      "object": "Contact",
      "fieldMapping": {
        "sourceObject": "Lead",
        "sourceReference": "$lead",
        "targetObject": "Contact",
        "actionType": "convert"
      },
      "inputAssignments": [
        { "field": "FirstName", "value": { "elementReference": "contactFirstName" } },
        { "field": "LastName", "value": { "elementReference": "contactLastName" } },
        { "field": "Title", "value": { "elementReference": "contactTitle" } },
        { "field": "Email", "value": { "elementReference": "contactEmail" } },
        { "field": "AccountId", "value": { "elementReference": "accountId" } },
        { "field": "OwnerId", "value": { "elementReference": "ownerId" } }
      ],
      "assignRecordIdToReference": "contactId",
      "connector": { "targetReference": "ResolveOpportunity" }
    },
    {
      "name": "CreateOpportunity",
      "label": "Create Opportunity from Lead",
      "locationX": 40,
      "locationY": 1200,
      "object": "Opportunity",
      "fieldMapping": {
        "sourceObject": "Lead",
        "sourceReference": "$lead",
        "targetObject": "Opportunity",
        "actionType": "convert"
      },
      "inputAssignments": [
        { "field": "Name", "value": { "elementReference": "opportunityName" } },
        { "field": "AccountId", "value": { "elementReference": "accountId" } },
        { "field": "OwnerId", "value": { "elementReference": "ownerId" } },
        { "field": "CampaignId", "value": { "elementReference": "$primaryCM.CampaignId" } }
      ],
      "assignRecordIdToReference": "opportunityId",
      "connector": { "targetReference": "SyncOpportunityContactRole" }
    }
  ],
  "recordUpdates": [
    {
      "name": "MergeAccountFields",
      "label": "Fill blank reused Account fields from Lead mapping",
      "locationX": 580,
      "locationY": 420,
      "object": "Account",
      "inputReference": "accountId",
      "fieldMapping": {
        "sourceObject": "Lead",
        "sourceReference": "$lead",
        "targetObject": "Account",
        "targetReference": "$account",
        "actionType": "convert",
        "mergeMode": "fillBlankOnly"
      },
      "connector": { "targetReference": "ResolveContact" }
    },
    {
      "name": "MergeContactFields",
      "label": "Fill blank reused Contact fields from Lead mapping",
      "locationX": 760,
      "locationY": 630,
      "object": "Contact",
      "inputReference": "contactId",
      "fieldMapping": {
        "sourceObject": "Lead",
        "sourceReference": "$lead",
        "targetObject": "Contact",
        "targetReference": "$contact",
        "actionType": "convert",
        "mergeMode": "fillBlankOnly"
      },
      "connector": { "targetReference": "MaybeUpdateContactOwner" }
    },
    {
      "name": "UpdateContactOwner",
      "label": "Set reused Contact owner",
      "locationX": 760,
      "locationY": 660,
      "object": "Contact",
      "inputReference": "contactId",
      "inputAssignments": [
        { "field": "OwnerId", "value": { "elementReference": "ownerId" } }
      ],
      "connector": { "targetReference": "MaybeOverwriteContactLeadSource" }
    },
    {
      "name": "UpdateContactLeadSource",
      "label": "Overwrite reused Contact LeadSource from Lead",
      "locationX": 760,
      "locationY": 720,
      "object": "Contact",
      "inputReference": "contactId",
      "inputAssignments": [
        { "field": "LeadSource", "value": { "elementReference": "$lead.LeadSource" } }
      ],
      "connector": { "targetReference": "ResolveOpportunity" }
    },
    {
      "name": "UpdateOpportunityOwner",
      "label": "Set reused Opportunity owner",
      "locationX": 760,
      "locationY": 900,
      "object": "Opportunity",
      "inputReference": "opportunityId",
      "inputAssignments": [
        { "field": "OwnerId", "value": { "elementReference": "ownerId" } }
      ],
      "connector": { "targetReference": "SyncOpportunityContactRole" }
    }
  ],
  "subflows": [
    {
      "name": "SyncOpportunityContactRole",
      "label": "Sync OpportunityContactRole for converted Contact",
      "locationX": 40,
      "locationY": 1320,
      "flowName": "Std_SyncOpportunityContactRole",
      "inputAssignments": [
        { "name": "opportunityId", "value": { "elementReference": "opportunityId" } },
        { "name": "contactId", "value": { "elementReference": "contactId" } }
      ],
      "connector": { "targetReference": "RelinkLeadChildren" }
    },
    {
      "name": "RelinkLeadChildren",
      "label": "Re-point CampaignMember/Task children at converted records",
      "locationX": 40,
      "locationY": 1440,
      "flowName": "Std_RelinkLeadChildren",
      "inputAssignments": [
        { "name": "leadId", "value": { "elementReference": "leadId" } },
        { "name": "contactId", "value": { "elementReference": "contactId" } },
        { "name": "opportunityId", "value": { "elementReference": "opportunityId" } },
        { "name": "accountId", "value": { "elementReference": "accountId" } }
      ],
      "connector": { "targetReference": "PreviewLeadBeforeSaveUpdate" }
    }
  ],
  "actionCalls": [
    {
      "name": "PreviewLeadBeforeSaveUpdate",
      "label": "Run source Lead BeforeSave-Update before downstream writes",
      "locationX": 220,
      "locationY": 300,
      "actionName": "previewRecordUpdate",
      "actionType": "previewRecordUpdate",
      "inputParameters": [
        { "name": "object", "value": "Lead" },
        { "name": "recordId", "value": { "elementReference": "leadId" } },
        { "name": "outputReference", "value": { "stringValue": "$lead" } },
        {
          "name": "updates",
          "value": {
            "IsConverted": true,
            "Status": { "elementReference": "convertedStatus" }
          }
        },
        {
          "name": "internalUpdates",
          "value": {
            "ConvertedAccountId":     { "elementReference": "accountId" },
            "ConvertedContactId":     { "elementReference": "contactId" },
            "ConvertedOpportunityId": { "elementReference": "opportunityId" }
          }
        }
      ],
      "connector": { "targetReference": "MarkLeadConverted" }
    },
    {
      "name": "MarkLeadConverted",
      "label": "Stamp Lead Converted anchors and flags",
      "locationX": 40,
      "locationY": 1320,
      "actionName": "commitPreparedRecordUpdate",
      "actionType": "commitPreparedRecordUpdate",
      "inputParameters": [
        { "name": "object", "value": "Lead" },
        { "name": "recordId", "value": { "elementReference": "leadId" } },
        {
          "name": "extraFields",
          "value": {
            "ConvertedDate": { "elementReference": "$Flow.CurrentDate" }
          }
        }
      ]
    }
  ]
}
