Skip to article

LinkedIn Marketo integration: connect one form, prove the handoff and fix the first break

Connect one form, prove every handoff and repair the first broken state before you send another test.

A green connection badge does not tell you whether a LinkedIn lead reached the right Marketo person, entered the right program or reached the person who should follow up.

Treat those as separate checks.

This guide walks through one LinkedIn Lead Gen Form from setup to routing. The finished record gives another operator the scope, evidence and next action without giving them access to your accounts.

If you are still deciding what to ask on the form, start with the LinkedIn Lead Gen Forms guide. This page begins with an approved form and a chosen Marketo destination.

The short version

  1. Name the exact LinkedIn account and form plus the exact Marketo subscription, LaunchPoint service and destination.
  2. Record the field map before you authorize a test.
  3. Send one permitted test lead and save the LinkedIn-side evidence before sending another.
  4. Check the Marketo person and Fills Out LinkedIn Lead Gen Form activity.
  5. Check list or program membership.
  6. Check the downstream routing event and owner.
  7. Reconcile every population at one cutoff.

Stop at the first missing or contradictory receipt. Sending another test lead usually creates more timestamps to sort out. It does not explain the first failure.

The LinkedIn-to-Marketo evidence chain, from exact scope through routing

Decide what this integration is supposed to do

The native connection can bring LinkedIn Lead Gen Form submissions into Marketo. Your Marketo setup still decides what happens next.

Write down these three decisions before opening LaunchPoint:

  • Which LinkedIn ad account and Lead Gen Form are in scope?
  • Which Marketo list, program or both should contain the person?
  • Which workflow routes the person after that, and who owns the response?

A list can be a simple operational destination. A program can carry membership, statuses and campaign logic. Some teams need both. Record the intended result because the native connection does not choose it for you.

Your integration record should also name the match rule. Email address is a common identifier, but your Marketo subscription may have other deduplication or CRM rules. Keep that rule Unknown until the Marketo owner confirms it or supplies a native read-back.

Record the account and form scope

Use exact identities. “LinkedIn lead form” and “main Marketo instance” will not help when someone has to diagnose the connection two months later.

Record:

  • LinkedIn Business Account name and stable ID, if shown;
  • Campaign Manager ad account name and ID;
  • LinkedIn Page;
  • Lead Gen Form name and ID;
  • form status or revision evidence;
  • Marketo subscription or workspace name;
  • LaunchPoint service display name;
  • authorized LinkedIn user reference, without a password, token or credential value;
  • authorization status and date;
  • destination list, program and routing destination.

Adobe says one LinkedIn user account can be authorized for the service. That user needs access to all intended Business Accounts. If an expected Business Account is missing, Adobe directs you to check whether the user has Lead Gen Form Manager permission for that Business Account. The service also expires one year after authorization, so an old setup can fail because its authorization is stale. Read Adobe's current setup instructions.

LinkedIn separates ad-account access from Page and Lead Gen Form permissions. A connection record should keep those roles separate. Read LinkedIn's Lead Gen Form permission table.

The identities that must agree on the LinkedIn and Marketo sides

Wrong-account check

Compare the approved account and form record with the accounts shown inside the LaunchPoint service. If the ID differs, stop there. Field mapping and routing checks belong to a different form and will send you in the wrong direction.

Use this evidence request:

Capture the current LaunchPoint service status, the authorized LinkedIn user reference, the selected Business Account and ad account IDs, and the exact Lead Gen Form name and ID. Do not include a password, token, cookie or authorization code.

Create the LaunchPoint service

Adobe's current sequence is:

  1. In Marketo, open Admin.
  2. Open LaunchPoint.
  3. Choose New, then New Service.
  4. Enter a display name and choose LinkedIn Lead Gen.
  5. Sign in to the LinkedIn account that has access to the intended Business Accounts.
  6. Return to Marketo, choose Authorize, then allow the Marketo app in LinkedIn.
  7. Select the Business Accounts whose leads should enter Marketo.
  8. Review the LinkedIn-to-Marketo field mappings before you create the service.

These labels were checked against Adobe Experience League on 7 October 2026. If your screen uses different labels, record the labels you saw and keep that observation separate from the planned path.

Do not paste credentials into the integration record. Record the operator, time, account scope and resulting status. Credentials stay in the platforms that issue and store them.

Build the field map before the test

For every required form field, record:

LinkedIn sourceMarketo destinationTypeNormalizationAllowed valuesConsent or permission actionRequired proof
Work emailEmailemaillowercase and trimvalid addressoperational test onlyMarketo person field read-back
Company nameCompanytexttrimsupplied valuenoneMarketo person field read-back
Job titleTitletexttrimsupplied valuenoneMarketo person field read-back
Lead sourceLead Source Detailtextfixed approved valueLinkedIn Lead Genpreserve sourceMarketo activity/person read-back
Consent checkboxNamed consent fieldboolean or approved valueexplicit mapapproved values onlyretain consent text/version evidencefield plus form/version evidence

Replace the example destinations with your real Marketo fields. A public guide cannot prove that those fields exist in your subscription.

Adobe documents two mapping constraints that deserve a preflight check:

  • Only LinkedIn fields already saved to a form template in Campaign Manager appear for mapping.
  • Two LinkedIn fields may map to one Marketo field only when the fields are on different forms. Mapping two fields from the same form to one Marketo field can stop people from entering the database.

Adobe also says a numeric-only form name is unsupported. Check the name before blaming routing.

LinkedIn warns that some partner integrations do not support member profile links, hidden fields or custom checkboxes. That is a partner-level warning, not proof that your current Marketo connection supports or rejects a specific field. Keep the field state Unknown until you inspect the actual map. Read LinkedIn's integration guidance.

Treat form edits like a new scope check

LinkedIn says that edits to a draft Lead Gen Form may require matching account, form and field changes in the marketing automation platform before new test leads sync. If a connection used to work, compare the current form and field map with the reviewed version before reauthorizing or rebuilding anything. Read LinkedIn's troubleshooting note.

Send one test lead and save the source evidence

Run the test only after the account, form and field map are reviewable.

LinkedIn's current path is Campaign Manager → Content & Assets → Lead generation forms → More → Send Test Lead. Fill the required fields and send the test. A test submitted from the Ads tab can include ad_id and ad set_id in the downloaded lead data, which helps when the same form appears in several campaigns. Read the current test-lead instructions.

Before sending another test, save:

  • test timestamp and timezone;
  • ad account and form ID;
  • test email or safe test-person reference;
  • Test Lead = TRUE from the LinkedIn download;
  • ad and ad-set IDs when available;
  • the downloaded source row or a reference to its controlled location.

LinkedIn says a new test lead overwrites the existing test lead. Capture the source evidence first.

Do not put real personal data in a public handoff. Use a permitted internal test identity and store any sensitive source row in the system approved by your team. The public record needs an evidence reference, not the private row itself.

Prove the Marketo person and activity

Finding a person with the same email address is not enough. The person may have existed before the LinkedIn test.

For the exact test identity and timestamp, capture:

  1. the Marketo person ID or controlled reference;
  2. the mapped field values;
  3. the Fills Out LinkedIn Lead Gen Form activity;
  4. the activity timestamp and form identity;
  5. any deduplication or merge event that changed the record.

Adobe documents Fills Out LinkedIn Lead Gen Form as the Smart Campaign trigger and Filled Out LinkedIn Lead Gen Form as the filter. It also says a form name appears in the relevant Marketo choice after at least one person has submitted the form. Read Adobe's trigger and filter documentation.

An Adobe Community thread shows why this distinction matters. New people entered the program, while some existing people did not. The missing existing people also lacked the LinkedIn form-fill activity. The thread does not establish a universal cause, and another contributor questioned the suggested Company-field explanation. It supports checking activity before membership. It does not support renaming a field as a general fix. Read the complete thread.

Adobe documents one narrower existing-person condition: a LinkedIn lead may fail to enter Marketo when it matches an existing person associated with a company record created through Company APIs and the Marketo subscription is not connected to a CRM. Check whether that exact condition applies before treating it as the cause.

Prove list or program membership

Once the form-fill activity exists, check the action that should add the person to a list or program.

Record:

  • Smart Campaign name and ID;
  • trigger or filter used;
  • form and account constraints;
  • qualification rule and whether the person qualified;
  • flow action;
  • intended list/program and membership status;
  • observed membership timestamp;
  • program status, if the process uses one.

If the activity exists and membership does not, the connection has already delivered the activity. Start with the Smart Campaign and membership logic. Reauthorizing LinkedIn is unlikely to explain that later break.

Prove routing and ownership

Membership is still not the last step if the promise is follow-up.

Name the routing destination, event and owner. The destination might be a CRM sync, queue, alert, webhook or task. Record its stable name or ID and a dated receipt. “Sales notified” is a plan until you can point to the event that notified sales.

Also record the response target separately from the observed response. A two-hour target does not prove someone responded in two hours.

Reconcile the populations at one cutoff

Use one start time, end time and timezone. Then record these populations:

PopulationWhat it countsEvidence
SubmittedTest or live submissions in the declared LinkedIn source cohortLinkedIn download or source report
Connector-observedSubmissions the integration says it received, when that state is exposedNative service receipt or Unknown
Person/activityDistinct Marketo people represented at least once in this cohort with the expected form-fill activityMarketo activity query/read-back
MembershipPeople in the intended list or programMarketo membership read-back
RoutedPeople with the downstream routing eventDestination event/read-back
DuplicateAdditional source submissions after the first submission for a person already represented in this same cohortMarketo/CRM match evidence tied to the source rows
UnresolvedSource submissions that are not represented by a person/activity record and are not an additional in-cohort submissionReconciliation output

Blank means nobody supplied the count. Unknown means the count cannot be established from the current evidence. Zero means a dated source proved that the population contains zero records.

Do not convert a blank to zero so the arithmetic looks complete.

The numbers also need the same cohort. LinkedIn says Test Lead = TRUE identifies a test lead in the downloaded report. Keep test and live populations separate. A source count from one form cannot be compared with a Marketo query that covers every LinkedIn form.

For a complete cohort, the checker should explain how submitted records became distinct person/activity records, additional in-cohort submissions or unresolved records. A person who existed in Marketo before this cohort is still counted once in person/activity when the new form-fill activity appears. That existing-person match is not a duplicate by itself. Count a duplicate only when the cohort contains another submission for a person already represented in the same cohort. With those mutually exclusive definitions and one cutoff, submitted = person/activity + duplicate + unresolved. Check later gaps separately: membership cannot exceed person/activity, and routed cannot exceed membership for the same unit and cohort.

An unresolved count above zero means the handoff is still broken. The checker returns REPAIR_REQUIRED at reconciliation and asks the operator to account for those source rows before treating the record as verified.

Diagnose the first broken state

A first-broken-state tree for LinkedIn and Marketo

Work from left to right:

  1. Authorization: Is the LaunchPoint service currently authorized, and is the authorization date known?
  2. Account and form scope: Do the observed account and form IDs match the approved record?
  3. Field and value map: Is every required field, type and allowed value mapped without a same-form collision?
  4. Source test: Does LinkedIn show the test in the intended form's download with Test Lead = TRUE?
  5. Person and activity: Does Marketo show the exact person plus the LinkedIn form-fill activity at the test time?
  6. Membership: Did the person qualify for and enter the intended list/program?
  7. Routing: Did the downstream event reach the named destination and owner?
  8. Reconciliation: Can every source record be explained for the same cutoff?

The first failed check determines the next evidence request. Later states stay Unknown until the earlier state is repaired and retested.

Worked example: Copperline Systems

Copperline Systems is fictional. The example shows how the record works without presenting invented client results.

The approved scope names ad account LI-ACCT-4821, form FORM-DEMO-Q4, Marketo service LinkedIn Lead Gen - NA, program PRG-LI-DEMO-Q4 and routing destination CRM-QUEUE-ENTERPRISE.

The operator sends one permitted test at 2026-10-08 14:05 UTC. The LinkedIn download shows one row with Test Lead = TRUE, the expected form, ad and ad-set IDs. Marketo shows person MK-P-10482 and a Fills Out LinkedIn Lead Gen Form activity at 14:06 UTC. The person enters the intended program at 14:06 UTC and the routing destination records the event at 14:07 UTC.

For the one-record test cohort:

  • submitted: 1;
  • connector-observed: Unknown because the native service did not expose a separate receipt in this example;
  • person/activity: 1;
  • membership: 1;
  • routed: 1;
  • duplicate: 0, supported by the fictional example's match read-back;
  • unresolved: 0.

The status is VERIFIED for that one fictional test cohort. It does not prove the next live lead will route, and it does not prove your account works.

Failure example: activity exists, membership does not

Now change one fact. The person and form-fill activity exist, but the person is absent from PRG-LI-DEMO-Q4.

The status becomes REPAIR_REQUIRED. The first broken state is membership. The next request is:

Read back the Smart Campaign trigger or filter, form constraints, qualification result and membership flow action for person MK-P-10482 at the test timestamp.

The page does not tell the operator to reconnect LinkedIn because the activity already proves that the submission reached Marketo.

Download the integration toolkit

Portable toolkit

Copy the complete record-builder package
{
  "prompt": {
    "title": "Integration record builder",
    "text": "LINKEDIN–MARKETO INTEGRATION RECORD BUILDER — portable v1\n\nCreate or repair one `maestro.linkedin-marketo-integration.v1` JSON record using only the facts attached by the user. Do not assume access to this webpage, private accounts, external files, or earlier conversation. When a fact is missing, leave its value as the empty string and list the exact evidence needed next. Never invent account state, IDs, timestamps, permission, receipts, outcomes or owner opinions. Never include secrets or personal lead data.\n\nKeep these states distinct:\n- `\"\"` means not supplied;\n- literal `\"Unknown\"` means the fact cannot currently be established;\n- integer `0` means a dated evidence source proved zero. Zero requires an evidence reference, evidence type and capture time.\n- `planned` describes intended configuration. It cannot prove an `observed` connection, submission, activity, membership or routing event.\n\nUse exact account, ad account, Page, form, Marketo subscription, LaunchPoint service, field, program/list and routing identity. Preserve long IDs byte-for-byte. Each observed state needs a typed dated evidence reference in the evidence register: `native_readback`, `native_receipt`, `source_report`, `operator_note`, or (only for the clearly marked fixture) `fictional_example_receipt`. Public documentation is `documented_source` and can support setup steps only. Do not treat it as native evidence.\n\nReturn the complete JSON record and a readable Markdown rendering of the same facts. Then return the decision (`DRAFT_READY`, `LAUNCH_HOLD`, `VERIFIED`, or `REPAIR_REQUIRED`), first broken state, exact next evidence request and one same-cohort, same-cutoff reconciliation with these seven populations: submitted, connector_observed, person_activity, membership, routed, duplicate, unresolved. A connector count may remain `Unknown` when the native service exposes no separate receipt.\n\nEvaluate in this order: authorization; account/form scope; field/value map; LinkedIn source test; Marketo person/activity; list/program membership; downstream routing; reconciliation. Stop at the first failed or contradictory state and keep later states unknown. Use `DRAFT_READY` when the plan is complete enough for operator review and no execution claim is being made. Use `LAUNCH_HOLD` when execution is expected but required authorization or test proof is missing. Use `REPAIR_REQUIRED` for malformed input, contradictory evidence or a proven failed step. Use `VERIFIED` only for the exact tested cohort after all required observed proof and reconciliation pass.\n\nFixture requirements: reason through each fixture and state what output/first break is expected. Do not blend fixture facts into the user's record.\n1. COMPLETE: use only the supplied complete fictional Copperline Systems record. It has one test submission at 2026-10-08 14:05 UTC, person MK-P-10482/activity at 14:06, membership at 14:06, routing at 14:07; submitted/person_activity/membership/routed = 1, duplicate/unresolved = 0 with fictional dated receipts, connector_observed = literal Unknown because no separate receipt was exposed. Expected fixture disposition: VERIFIED, explicitly fictional.\n2. MISSING: remove observed authorization, source test and activity receipts but leave the plan/mappings. Expected: LAUNCH_HOLD; name the earliest missing state and request current LaunchPoint status/authorization evidence. Do not turn blank into false or zero.\n3. WRONG SCOPE: observed Business Account or form ID differs from approved scope, even if the connection status says active. Expected: REPAIR_REQUIRED at account_form_scope; ask for the exact native account/form read-back. Do not continue to mapping/routing.\n4. STALE AUTH: authorization date is blank or outside the documented one-year service window. Expected: LAUNCH_HOLD at authorization; request current service status and authorization date. Do not reauthorize without an authorized operator.\n5. KNOWN ZERO: submitted=0 with dated source evidence; routed count is blank; unresolved is literal Unknown. Expected: preserve 0, blank, and Unknown separately; LAUNCH_HOLD at population_evidence and request same-cutoff routed/unresolved counts.\n6. MALFORMED: change `populations` to a scalar and remove `scope.form_id`. Expected: do not throw or coerce; return `REPAIR_REQUIRED` at import_contract with original supplied input preserved byte-for-byte or an exact escaped source copy, plus path/kind/value diagnostics. Do not overwrite the last accepted record.\n\nDo not use `VERIFIED` for a real-world record based on a prompt fixture, plan, public page, screenshot without native context, or unsupported narrative.\n\nPhase contract: an incomplete plan returns LAUNCH_HOLD at planning; a complete plan with no execution claim returns DRAFT_READY; launch requires current authorization, exact scope and a valid map; post_test requires the source receipt and checks each downstream state. Missing evidence holds at that state. Observed contradictions or failed outcomes return REPAIR_REQUIRED at the first affected state. A complete no-execution plan is DRAFT_READY in both builder and reviewer; the completely blank template is LAUNCH_HOLD at planning in both. Never imply launch authorization from DRAFT_READY.\n\nFresh fixture set: COMPLETE (VERIFIED only as fictional), PLAN_ONLY (DRAFT_READY), WRONG_SCOPE (REPAIR_REQUIRED/account_form_scope), STALE_AUTH (LAUNCH_HOLD/authorization), KNOWN_ZERO_MISSING (LAUNCH_HOLD/population_evidence while preserving 0/blank/Unknown), MALFORMED (REPAIR_REQUIRED/import_contract with exact bytes), EMPTY_ENUM (REPAIR_REQUIRED/field_value_map), MISSING_MATCHING_RECEIPT (REPAIR_REQUIRED/matching), WRONG_ACTIVITY (REPAIR_REQUIRED/person_activity), REJECTED_ROUTE (REPAIR_REQUIRED/routing), OUT_OF_CUTOFF (LAUNCH_HOLD/population_evidence). Explicit regression fixtures: NEW_PERSON_SUCCESS, EXISTING_PERSON_SUCCESS, TWO_SUBMISSIONS_ONE_PERSON, MISSING_ACTIVITY, ABSENT_MEMBERSHIP, REJECTED_ROUTING and UNRESOLVED_SOURCE_ROW.\n\nComplete field-by-field schema and allowed literals are in the attached `schema` object in this prompt package. Source links and exact evaluator commands are in `source_links` and `invocations`. When those files are available, run the evaluator on the unchanged input and report its first broken state; do not substitute prose judgment for executable evaluation.\n\nPopulation-unit rule: `person_activity` counts distinct Marketo people represented at least once in this cohort with the exact form-fill activity. `duplicate` counts only additional source submissions after the first submission for a person already represented in this same cohort. A source submission that matches a person who existed before the cohort still belongs in `person_activity`; that pre-existing identity does not make the submission a duplicate. `unresolved` counts source submissions in neither category. These categories must be mutually exclusive before applying `submitted = person_activity + duplicate + unresolved`. A known `unresolved` count above zero returns REPAIR_REQUIRED at reconciliation."
  },
  "schema": {
    "schema_version": "maestro.linkedin-marketo-integration.v1",
    "record": {
      "record_id": "string",
      "example_only": "boolean",
      "evaluation_phase": [
        "draft",
        "launch",
        "post_test"
      ],
      "scope": [
        "organization",
        "linkedin_user_ref",
        "business_account_id",
        "ad_account_id",
        "page_id",
        "form_name",
        "form_id",
        "marketo_subscription_ref",
        "launchpoint_service_name",
        "launchpoint_service_id",
        "approved_by",
        "approved_at"
      ],
      "connection": {
        "planned": [
          "status",
          "steps_or_reference",
          "owner"
        ],
        "observed": [
          "status",
          "authorized_at",
          "checked_at",
          "evidence_ref",
          "business_account_id",
          "ad_account_id",
          "page_id",
          "form_id"
        ]
      },
      "field_mappings": {
        "type": "array of objects",
        "fields": [
          "linkedin_field",
          "marketo_field",
          "data_type",
          "normalization",
          "allowed_values",
          "consent_action",
          "required",
          "state",
          "evidence_ref",
          "observed_values"
        ],
        "data_type": [
          "email",
          "text",
          "enum",
          "boolean",
          "number",
          "date",
          "phone",
          "url",
          "integer",
          "decimal"
        ]
      },
      "destination": [
        "type",
        "name",
        "id",
        "smart_campaign_name",
        "smart_campaign_id",
        "trigger_or_filter",
        "qualification_rule",
        "flow_action",
        "membership_status_expected",
        "observed_membership_status",
        "observed_at",
        "evidence_ref",
        "membership_outcome"
      ],
      "matching": [
        "match_rule",
        "dedupe_behavior",
        "collision_or_merge",
        "observed_at",
        "evidence_ref",
        "observed_outcome"
      ],
      "routing": [
        "destination",
        "event",
        "owner",
        "response_target",
        "observed_event",
        "observed_at",
        "evidence_ref",
        "outcome"
      ],
      "test": [
        "authorized_by",
        "submitted_at",
        "timezone",
        "test_person_ref",
        "test_lead_flag",
        "linkedin_evidence_ref",
        "marketo_person_id",
        "activity_name",
        "activity_at",
        "person_activity_evidence_ref",
        "activity_outcome"
      ],
      "cutoff": [
        "start",
        "end",
        "timezone",
        "cohort",
        "form_id",
        "ad_account_id"
      ],
      "populations": {
        "exact_keys": [
          "submitted",
          "connector_observed",
          "person_activity",
          "membership",
          "routed",
          "duplicate",
          "unresolved"
        ],
        "fields": [
          "state",
          "value",
          "evidence_ref",
          "evidence_type",
          "captured_at",
          "definition",
          "evidence_scope"
        ],
        "state": [
          "KNOWN",
          "UNKNOWN",
          "BLANK"
        ],
        "evidence_scope": [
          "form_id",
          "ad_account_id",
          "cohort",
          "cutoff_start",
          "cutoff_end",
          "timezone"
        ]
      },
      "evidence": {
        "type": "array of objects",
        "fields": [
          "evidence_ref",
          "evidence_type",
          "captured_at",
          "supports",
          "note"
        ],
        "evidence_type": [
          "native_readback",
          "native_receipt",
          "source_report",
          "operator_note",
          "documented_source",
          "fictional_example_receipt only when example_only=true"
        ]
      },
      "operator_notes": "string"
    },
    "dispositions": [
      "DRAFT_READY",
      "LAUNCH_HOLD",
      "VERIFIED",
      "REPAIR_REQUIRED"
    ],
    "first_broken_states": [
      "planning",
      "authorization",
      "account_form_scope",
      "field_value_map",
      "source_test",
      "matching",
      "person_activity",
      "membership",
      "routing",
      "population_evidence",
      "reconciliation",
      "import_contract"
    ],
    "outcomes": {
      "matching": [
        "NO_COLLISION",
        "MATCHED_EXISTING",
        "MERGED",
        "UNRESOLVED_COLLISION",
        "UNKNOWN"
      ],
      "activity": [
        "OBSERVED",
        "MISSING",
        "WRONG_ACTIVITY",
        "UNKNOWN"
      ],
      "membership": [
        "PRESENT",
        "ABSENT",
        "NOT_REQUIRED",
        "UNKNOWN"
      ],
      "routing": [
        "ACCEPTED",
        "REJECTED",
        "NOT_REQUIRED",
        "UNKNOWN"
      ]
    },
    "population_rules": [
      "Known values are nonnegative integers with matching dated evidence.",
      "Unknown and blank have null value.",
      "Every known population has exact form/account/cohort/cutoff/timezone scope.",
      "person_activity counts distinct Marketo people represented at least once in the cohort with the exact form-fill activity.",
      "duplicate counts only additional source submissions after the first for a person already represented in the same cohort; a pre-existing person is not a duplicate by itself.",
      "person_activity, duplicate and unresolved are mutually exclusive before reconciliation.",
      "submitted = person_activity + duplicate + unresolved.",
      "membership <= person_activity and routed <= membership.",
      "A known unresolved count above zero returns REPAIR_REQUIRED at reconciliation."
    ]
  },
  "source_links": [
    {
      "name": "LinkedIn Lead Gen Forms and CRM integration",
      "url": "https://www.linkedin.com/help/lms/answer/a423205"
    },
    {
      "name": "Marketo LaunchPoint services",
      "url": "https://experienceleague.adobe.com/en/docs/marketo/using/product-docs/administration/additional-integrations/launchpoint/launchpoint-services"
    },
    {
      "name": "Marketo Add to List flow action",
      "url": "https://experienceleague.adobe.com/en/docs/marketo/using/product-docs/core-marketo-concepts/smart-campaigns/flow-actions/add-to-list"
    }
  ],
  "invocations": {
    "python": "python3 marketo-integration-checker.py RECORD.json",
    "python_phase": "python3 marketo-integration-checker.py --phase draft|launch|post_test RECORD.json",
    "node": "node marketo-integration-checker.mjs RECORD.json",
    "node_phase": "node marketo-integration-checker.mjs --phase draft|launch|post_test RECORD.json"
  },
  "fixture_ids": [
    "COMPLETE",
    "PLAN_ONLY",
    "WRONG_SCOPE",
    "STALE_AUTH",
    "KNOWN_ZERO_MISSING",
    "MALFORMED",
    "EMPTY_ENUM",
    "MISSING_MATCHING_RECEIPT",
    "WRONG_ACTIVITY",
    "REJECTED_ROUTE",
    "OUT_OF_CUTOFF",
    "NEW_PERSON_SUCCESS",
    "EXISTING_PERSON_SUCCESS",
    "TWO_SUBMISSIONS_ONE_PERSON",
    "MISSING_ACTIVITY",
    "ABSENT_MEMBERSHIP",
    "REJECTED_ROUTING",
    "UNRESOLVED_SOURCE_ROW"
  ],
  "fixtures": [
    {
      "id": "COMPLETE",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "PLAN_ONLY",
      "expected": "DRAFT_READY",
      "first_broken_state": null
    },
    {
      "id": "WRONG_SCOPE",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "account_form_scope"
    },
    {
      "id": "STALE_AUTH",
      "expected": "LAUNCH_HOLD",
      "first_broken_state": "authorization"
    },
    {
      "id": "KNOWN_ZERO_MISSING",
      "expected": "LAUNCH_HOLD",
      "first_broken_state": "population_evidence"
    },
    {
      "id": "MALFORMED",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "import_contract"
    },
    {
      "id": "EMPTY_ENUM",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "field_value_map"
    },
    {
      "id": "MISSING_MATCHING_RECEIPT",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "matching"
    },
    {
      "id": "WRONG_ACTIVITY",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "person_activity"
    },
    {
      "id": "REJECTED_ROUTE",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "routing"
    },
    {
      "id": "OUT_OF_CUTOFF",
      "expected": "LAUNCH_HOLD",
      "first_broken_state": "population_evidence"
    },
    {
      "id": "NEW_PERSON_SUCCESS",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "EXISTING_PERSON_SUCCESS",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "TWO_SUBMISSIONS_ONE_PERSON",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "MISSING_ACTIVITY",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "person_activity"
    },
    {
      "id": "ABSENT_MEMBERSHIP",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "membership"
    },
    {
      "id": "REJECTED_ROUTING",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "routing"
    },
    {
      "id": "UNRESOLVED_SOURCE_ROW",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "reconciliation"
    }
  ]
}
Copy the independent review package
{
  "prompt": {
    "title": "Independent integration record reviewer",
    "text": "LINKEDIN–MARKETO INTEGRATION RECORD REVIEWER — portable v1\n\nIndependently review the attached record and any attached evidence. This prompt is self-contained; do not assume access to this webpage, private accounts, code, other files, or prior conversation. Do not repair the source record silently. Return a read-only evaluation with disposition `DRAFT_READY`, `LAUNCH_HOLD`, `VERIFIED`, or `REPAIR_REQUIRED`, first broken state, exact evidence request, validation findings by JSON path, and population arithmetic only when definitions/cutoffs match.\n\nEvidence contract: distinguish planned from observed. Require exact evidence types and capture times. `documented_source` supports instructions, not native account state. Positive native claims require `native_readback`, `native_receipt`, or `source_report` as appropriate. `operator_note` is not a native receipt. Permit `fictional_example_receipt` only when `example_only:true`, and label the entire outcome fictional. Never treat a nonempty evidence string, public setup page, connection label, or generic screenshot as sufficient proof.\n\nCount contract: evaluate exactly these seven population keys: `submitted`, `connector_observed`, `person_activity`, `membership`, `routed`, `duplicate`, and `unresolved`. Empty string = blank; literal `Unknown` = unknown; nonnegative integer including `0` = known count. A zero is valid only with a dated compatible evidence item. Never coerce missing/Unknown to zero. Check one cohort, form/account scope, cutoff and timezone. Verify submitted = person/activity + duplicate + unresolved only when the populations share compatible record-level definitions and evidence. Check membership <= person/activity and routed <= membership only when the same unit and cohort are established. Do not force totals across incompatible populations.\n\nRequired nested validation: scope identity strings; connection planned and observed objects; every field mapping and allowed-values array; destination and matching objects; test submission and activity fields; cutoff; each of all seven population objects; every evidence register item and evidence type. Detect null/scalar/wrong-kind/missing members. Preserve malformed source bytes and last accepted state; return nonthrowing `REPAIR_REQUIRED` with exact path, expected kind, received kind and original value. Do not normalize malformed input into a valid default.\n\nEvaluate first broken state in this order: authorization, account_form_scope, field_value_map, source_test, person_activity, membership, routing, reconciliation. Use `DRAFT_READY` for a structurally complete plan that makes no execution claim. Use `LAUNCH_HOLD` when execution is expected but proof is absent. Use `REPAIR_REQUIRED` for malformed input, contradictory evidence or a proven failed step. Full typed, dated evidence for the exact cohort may be `VERIFIED`. Unknown connector receipt is acceptable only when explicitly unavailable and cannot be counted as zero.\n\nRun these independent cases and report exact outcomes: (1) COMPLETE fictional Copperline: IDs LI-ACCT-4821, FORM-DEMO-Q4, service LinkedIn Lead Gen - NA, program PRG-LI-DEMO-Q4, route CRM-QUEUE-ENTERPRISE; test 14:05 UTC, activity/person 14:06, membership 14:06, route 14:07 on 2026-10-08; counts 1/Unknown/1/1/1/0/0. Expected VERIFIED as fictional example only. (2) MISSING receipts with plan retained: LAUNCH_HOLD at first required missing observed state. (3) WRONG SCOPE: different observed form or Business Account: REPAIR_REQUIRED at account_form_scope. (4) STALE AUTH: missing or > one-year-old authorization date: LAUNCH_HOLD at authorization. (5) KNOWN ZERO: submitted=0 with evidence, routed blank, unresolved=\"Unknown\": preserve all three; LAUNCH_HOLD at population_evidence, request both missing populations. (6) MALFORMED: populations scalar, missing scope.form_id, nested evidence item with numeric `captured_at`, and/or evidence type `\"planned to verify later\"`: REPAIR_REQUIRED, path-specific diagnostics, exact input preservation; no exception and no commit.\n\nReturn concise evaluation JSON plus a plain-language handoff. Keep the attached source record unchanged. Never infer a cause from timing, blame a person, authorize a test/reconnect, or claim a real-world result.\n\nPhase contract: an incomplete plan returns LAUNCH_HOLD at planning; a complete plan with no execution claim returns DRAFT_READY; launch requires current authorization, exact scope and a valid map; post_test requires the source receipt and checks each downstream state. Missing evidence holds at that state. Observed contradictions or failed outcomes return REPAIR_REQUIRED at the first affected state. A complete no-execution plan is DRAFT_READY in both builder and reviewer; the completely blank template is LAUNCH_HOLD at planning in both. Never imply launch authorization from DRAFT_READY.\n\nFresh fixture set: COMPLETE (VERIFIED only as fictional), PLAN_ONLY (DRAFT_READY), WRONG_SCOPE (REPAIR_REQUIRED/account_form_scope), STALE_AUTH (LAUNCH_HOLD/authorization), KNOWN_ZERO_MISSING (LAUNCH_HOLD/population_evidence while preserving 0/blank/Unknown), MALFORMED (REPAIR_REQUIRED/import_contract with exact bytes), EMPTY_ENUM (REPAIR_REQUIRED/field_value_map), MISSING_MATCHING_RECEIPT (REPAIR_REQUIRED/matching), WRONG_ACTIVITY (REPAIR_REQUIRED/person_activity), REJECTED_ROUTE (REPAIR_REQUIRED/routing), OUT_OF_CUTOFF (LAUNCH_HOLD/population_evidence). Explicit regression fixtures: NEW_PERSON_SUCCESS, EXISTING_PERSON_SUCCESS, TWO_SUBMISSIONS_ONE_PERSON, MISSING_ACTIVITY, ABSENT_MEMBERSHIP, REJECTED_ROUTING and UNRESOLVED_SOURCE_ROW.\n\nComplete field-by-field schema and allowed literals are in the attached `schema` object in this prompt package. Source links and exact evaluator commands are in `source_links` and `invocations`. When those files are available, run the evaluator on the unchanged input and report its first broken state; do not substitute prose judgment for executable evaluation.\n\nPopulation-unit rule: `person_activity` counts distinct Marketo people represented at least once in this cohort with the exact form-fill activity. `duplicate` counts only additional source submissions after the first submission for a person already represented in this same cohort. A source submission that matches a person who existed before the cohort still belongs in `person_activity`; that pre-existing identity does not make the submission a duplicate. `unresolved` counts source submissions in neither category. These categories must be mutually exclusive before applying `submitted = person_activity + duplicate + unresolved`. A known `unresolved` count above zero returns REPAIR_REQUIRED at reconciliation."
  },
  "schema": {
    "schema_version": "maestro.linkedin-marketo-integration.v1",
    "record": {
      "record_id": "string",
      "example_only": "boolean",
      "evaluation_phase": [
        "draft",
        "launch",
        "post_test"
      ],
      "scope": [
        "organization",
        "linkedin_user_ref",
        "business_account_id",
        "ad_account_id",
        "page_id",
        "form_name",
        "form_id",
        "marketo_subscription_ref",
        "launchpoint_service_name",
        "launchpoint_service_id",
        "approved_by",
        "approved_at"
      ],
      "connection": {
        "planned": [
          "status",
          "steps_or_reference",
          "owner"
        ],
        "observed": [
          "status",
          "authorized_at",
          "checked_at",
          "evidence_ref",
          "business_account_id",
          "ad_account_id",
          "page_id",
          "form_id"
        ]
      },
      "field_mappings": {
        "type": "array of objects",
        "fields": [
          "linkedin_field",
          "marketo_field",
          "data_type",
          "normalization",
          "allowed_values",
          "consent_action",
          "required",
          "state",
          "evidence_ref",
          "observed_values"
        ],
        "data_type": [
          "email",
          "text",
          "enum",
          "boolean",
          "number",
          "date",
          "phone",
          "url",
          "integer",
          "decimal"
        ]
      },
      "destination": [
        "type",
        "name",
        "id",
        "smart_campaign_name",
        "smart_campaign_id",
        "trigger_or_filter",
        "qualification_rule",
        "flow_action",
        "membership_status_expected",
        "observed_membership_status",
        "observed_at",
        "evidence_ref",
        "membership_outcome"
      ],
      "matching": [
        "match_rule",
        "dedupe_behavior",
        "collision_or_merge",
        "observed_at",
        "evidence_ref",
        "observed_outcome"
      ],
      "routing": [
        "destination",
        "event",
        "owner",
        "response_target",
        "observed_event",
        "observed_at",
        "evidence_ref",
        "outcome"
      ],
      "test": [
        "authorized_by",
        "submitted_at",
        "timezone",
        "test_person_ref",
        "test_lead_flag",
        "linkedin_evidence_ref",
        "marketo_person_id",
        "activity_name",
        "activity_at",
        "person_activity_evidence_ref",
        "activity_outcome"
      ],
      "cutoff": [
        "start",
        "end",
        "timezone",
        "cohort",
        "form_id",
        "ad_account_id"
      ],
      "populations": {
        "exact_keys": [
          "submitted",
          "connector_observed",
          "person_activity",
          "membership",
          "routed",
          "duplicate",
          "unresolved"
        ],
        "fields": [
          "state",
          "value",
          "evidence_ref",
          "evidence_type",
          "captured_at",
          "definition",
          "evidence_scope"
        ],
        "state": [
          "KNOWN",
          "UNKNOWN",
          "BLANK"
        ],
        "evidence_scope": [
          "form_id",
          "ad_account_id",
          "cohort",
          "cutoff_start",
          "cutoff_end",
          "timezone"
        ]
      },
      "evidence": {
        "type": "array of objects",
        "fields": [
          "evidence_ref",
          "evidence_type",
          "captured_at",
          "supports",
          "note"
        ],
        "evidence_type": [
          "native_readback",
          "native_receipt",
          "source_report",
          "operator_note",
          "documented_source",
          "fictional_example_receipt only when example_only=true"
        ]
      },
      "operator_notes": "string"
    },
    "dispositions": [
      "DRAFT_READY",
      "LAUNCH_HOLD",
      "VERIFIED",
      "REPAIR_REQUIRED"
    ],
    "first_broken_states": [
      "planning",
      "authorization",
      "account_form_scope",
      "field_value_map",
      "source_test",
      "matching",
      "person_activity",
      "membership",
      "routing",
      "population_evidence",
      "reconciliation",
      "import_contract"
    ],
    "outcomes": {
      "matching": [
        "NO_COLLISION",
        "MATCHED_EXISTING",
        "MERGED",
        "UNRESOLVED_COLLISION",
        "UNKNOWN"
      ],
      "activity": [
        "OBSERVED",
        "MISSING",
        "WRONG_ACTIVITY",
        "UNKNOWN"
      ],
      "membership": [
        "PRESENT",
        "ABSENT",
        "NOT_REQUIRED",
        "UNKNOWN"
      ],
      "routing": [
        "ACCEPTED",
        "REJECTED",
        "NOT_REQUIRED",
        "UNKNOWN"
      ]
    },
    "population_rules": [
      "Known values are nonnegative integers with matching dated evidence.",
      "Unknown and blank have null value.",
      "Every known population has exact form/account/cohort/cutoff/timezone scope.",
      "person_activity counts distinct Marketo people represented at least once in the cohort with the exact form-fill activity.",
      "duplicate counts only additional source submissions after the first for a person already represented in the same cohort; a pre-existing person is not a duplicate by itself.",
      "person_activity, duplicate and unresolved are mutually exclusive before reconciliation.",
      "submitted = person_activity + duplicate + unresolved.",
      "membership <= person_activity and routed <= membership.",
      "A known unresolved count above zero returns REPAIR_REQUIRED at reconciliation."
    ]
  },
  "source_links": [
    {
      "name": "LinkedIn Lead Gen Forms and CRM integration",
      "url": "https://www.linkedin.com/help/lms/answer/a423205"
    },
    {
      "name": "Marketo LaunchPoint services",
      "url": "https://experienceleague.adobe.com/en/docs/marketo/using/product-docs/administration/additional-integrations/launchpoint/launchpoint-services"
    },
    {
      "name": "Marketo Add to List flow action",
      "url": "https://experienceleague.adobe.com/en/docs/marketo/using/product-docs/core-marketo-concepts/smart-campaigns/flow-actions/add-to-list"
    }
  ],
  "invocations": {
    "python": "python3 marketo-integration-checker.py RECORD.json",
    "python_phase": "python3 marketo-integration-checker.py --phase draft|launch|post_test RECORD.json",
    "node": "node marketo-integration-checker.mjs RECORD.json",
    "node_phase": "node marketo-integration-checker.mjs --phase draft|launch|post_test RECORD.json"
  },
  "fixture_ids": [
    "COMPLETE",
    "PLAN_ONLY",
    "WRONG_SCOPE",
    "STALE_AUTH",
    "KNOWN_ZERO_MISSING",
    "MALFORMED",
    "EMPTY_ENUM",
    "MISSING_MATCHING_RECEIPT",
    "WRONG_ACTIVITY",
    "REJECTED_ROUTE",
    "OUT_OF_CUTOFF",
    "NEW_PERSON_SUCCESS",
    "EXISTING_PERSON_SUCCESS",
    "TWO_SUBMISSIONS_ONE_PERSON",
    "MISSING_ACTIVITY",
    "ABSENT_MEMBERSHIP",
    "REJECTED_ROUTING",
    "UNRESOLVED_SOURCE_ROW"
  ],
  "fixtures": [
    {
      "id": "COMPLETE",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "PLAN_ONLY",
      "expected": "DRAFT_READY",
      "first_broken_state": null
    },
    {
      "id": "WRONG_SCOPE",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "account_form_scope"
    },
    {
      "id": "STALE_AUTH",
      "expected": "LAUNCH_HOLD",
      "first_broken_state": "authorization"
    },
    {
      "id": "KNOWN_ZERO_MISSING",
      "expected": "LAUNCH_HOLD",
      "first_broken_state": "population_evidence"
    },
    {
      "id": "MALFORMED",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "import_contract"
    },
    {
      "id": "EMPTY_ENUM",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "field_value_map"
    },
    {
      "id": "MISSING_MATCHING_RECEIPT",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "matching"
    },
    {
      "id": "WRONG_ACTIVITY",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "person_activity"
    },
    {
      "id": "REJECTED_ROUTE",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "routing"
    },
    {
      "id": "OUT_OF_CUTOFF",
      "expected": "LAUNCH_HOLD",
      "first_broken_state": "population_evidence"
    },
    {
      "id": "NEW_PERSON_SUCCESS",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "EXISTING_PERSON_SUCCESS",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "TWO_SUBMISSIONS_ONE_PERSON",
      "expected": "VERIFIED",
      "first_broken_state": null
    },
    {
      "id": "MISSING_ACTIVITY",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "person_activity"
    },
    {
      "id": "ABSENT_MEMBERSHIP",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "membership"
    },
    {
      "id": "REJECTED_ROUTING",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "routing"
    },
    {
      "id": "UNRESOLVED_SOURCE_ROW",
      "expected": "REPAIR_REQUIRED",
      "first_broken_state": "reconciliation"
    }
  ]
}

Use the files in this order:

  1. Open the blank integration record and fill in the account, form, field, destination, owner and evidence fields. The JSON version is the canonical machine-readable record.
  2. Compare your work with the completed fictional example and its canonical JSON.
  3. Set evaluation_phase to draft, launch or post_test, then run python3 marketo-integration-checker.py your-record.json. You can also override the record with --phase draft|launch|post_test. The checker returns the phase, DRAFT_READY, LAUNCH_HOLD, VERIFIED or REPAIR_REQUIRED, the first broken state and the exact next evidence request.
  4. Give the operator the reconciliation and evidence request, or import the JSON version into your workflow.
  5. Copy the build or review prompt from the page when you need a fresh agent to prepare or check the record. The prompts do not authorize a test submission, reauthorization or launch.

The JSON record is the source. The Markdown files make the same facts readable. The browser checker can download both its JSON result and the complete readable Markdown evaluation. It keeps a separate last-accepted record in the open tab. If a later edit is malformed, the supplied text stays in the editor and the accepted record does not change.

The phase controls what the status claims. draft checks whether the plan is complete without claiming execution. launch checks the approved scope and native preflight, then holds for an authorized test. post_test checks the test, person match, activity, membership, routing and seven-population reconciliation.

What each status means

DRAFT_READY

In draft phase, the planned account, form, fields, destination, match rule, owner, cutoff and test authorization are complete enough for an operator to review. This status does not claim that the connection was opened, a test was sent or any native result was observed.

LAUNCH_HOLD

A required plan, authorization, identity, permission or dated proof is missing. In launch or post_test, it can also mean the next authorized observation has not happened yet. The next request names the missing evidence. A contradictory observed result uses REPAIR_REQUIRED instead.

VERIFIED

In post_test phase, the declared test cohort has dated source, matching, person/activity, membership, accepted routing and reconciliation evidence. This status is limited to that exact form, ad account, cohort, cutoff and timezone.

REPAIR_REQUIRED

The supplied record is malformed, contradicts itself or proves that an observed step failed. The output names the first broken state and the next evidence request. Missing proof without a contradiction stays on LAUNCH_HOLD.

Hand the work to the next operator

A clean handoff contains:

  • the exact scope record;
  • the field map;
  • the authorized test plan;
  • source and Marketo evidence references;
  • the seven population values and one cutoff;
  • the checker output;
  • the first broken state;
  • one named owner and next action.

It does not contain a password, access token, cookie, authorization code or raw private lead data.

If you want another operator to check the account, form, routing and evidence before launch, request a Demand Gen Roast and bring the completed record. We will review the evidence in the record and ask for the first missing native receipt.

Sources

Open full-size image