Skip to main content

Sync Salesforce records to PartnerPage listings with a Flow

Create and update PartnerPage listings from Salesforce Account records with a record-triggered Flow from the PartnerPage for Salesforce package.

M
Written by Mario Tarabbia

Keep partner listings in step with the partner data you already hold in Salesforce. A record-triggered Flow on Account calls the Sync partner listing to PartnerPage action from the PartnerPage for Salesforce package; the action queues an Apex job that writes the mapped fields to PartnerPage through the bulk partner API. Changes land on the directory within a minute of the record being saved, with no code on your side.

What the sync does

  • Matches each Account to a listing by External ID (the Account Id by default; any text field works).

  • Creates a listing when none matches. New listings start hidden, so you review them in the Vendor Dashboard before they go public. The first partner user who opens the embedded editor or the native component for that listing is added as its owner.

  • Updates the mapped fields on existing listings. Fields the Flow does not send keep their value.

  • Hides a listing when you send status = hidden (for example from a Flow path for Accounts that stop qualifying). Listings are never deleted by the sync.

  • Reports one result per record: created, updated, unchanged or failed with a plain reason (an unknown tier id, a filter option that does not exist, a missing External ID). Failed records are emailed to the user who saved the record, in one message per sync run.

Every change made this way is a change by you, the directory owner: it goes live directly and does not pass through the partner approval flow. If partners edit the same fields in your portal, mark those fields as managed by the directory in PartnerPage so the listing editor locks them.

Fields you can map

Action input

Listing field

Notes

External ID

matches the listing

Required.

Title

title

Headline

headline

Description

description

Website

website

Tier

tier

The tier id (UUID, Vendor Dashboard › Tiers), not its name. Empty keeps the current tier; none removes it.

Status

status

public, hidden, inactive or searchable (active is accepted and sent as public). hidden takes the listing off the public directory. Empty keeps the current status.

Featured

featured

true / false.

Filter option ids

assigned filter options

Comma-separated option ids from your directory's filters. Replaces every user-assigned option of the listing.

Filter option ids by filter

assigned filter options, per filter

filterId=optionId|optionId;filterId=optionId. Replaces the options of those filters only and keeps the partner's other choices; filterId= clears one filter. Use this or Filter option ids, not both.

Certification ids

certifications

Comma-separated certification ids.

Logos are not synced by the Flow (the API takes images as base64 and Flows cannot encode them); partners upload logos in the editor.

Set it up

  1. Install the package and configure it (README: API key on the External Credential principal, directory id in the custom metadata record, PartnerPage_Integration_User permission set for the users whose Account edits should trigger the sync).

  2. Open Setup › Flows › PartnerPage_Sync_Partner_Listing. It ships inactive as a template.

  3. Adjust the entry formula to the Accounts that count as partners. The template uses AND(ISPICKVAL({!$Record.Type}, "Partner"), OR(ISNEW(), ISCHANGED({!$Record.Name}), ISCHANGED({!$Record.Website}))): Type = Partner is a placeholder (a checkbox or record type works too), and the ISCHANGED terms list the mapped fields so that edits to unrelated fields do not call PartnerPage. Add a term for every field you map (Salesforce does not allow ISCHANGED on long text areas such as Description, so an edit to the description alone is synced with the next Name or Website change).

  4. Map your fields to the action inputs (the template maps Name, Website and Description and sends the Account Id as External ID). To use another field as External ID, change the mapping here and set External_Id_Field__c on the custom metadata record to the same field, so the editor components resolve the same value.

  5. Nothing else to wire for alerts: the action answers queued for every valid record, and the queued job emails the user who saved the Account when PartnerPage rejects a record or the callout cannot be made (one message per run, listing each External ID and reason). Records refused before queueing (blank External ID, package not configured) come back as failed with the reason in the action's result, if you want to branch on it.

  6. Activate the Flow. From then on every create of a qualifying Account, and every update that changes a mapped field, syncs.

The action runs on the Flow's synchronous after-save path and makes no callout itself: it queues an Apex job (PartnerPageSyncListingJob) that calls PartnerPage right after the record is committed, so the listing updates a few seconds after the save. The job runs as the user who saved the Account, and the callout is made on their behalf: every user and integration that edits partner Accounts needs the PartnerPage_Integration_User permission set, or their saves end in the failure email.

First full sync

To push the records you already have, run a one-off Flow (schedule-triggered or a screen Flow with a Get Records element) that calls the same action for every qualifying Account. The action sends up to 100 records per request; the PartnerPage API allows 1,000 requests per hour per endpoint for API-key callers, so a first sync of up to 100,000 records fits in one hour.

Checking sync health

  • The queued job writes every result (created, updated, unchanged, failed with the reason and the listing id) to the Apex debug log under "PartnerPage sync", and emails the user who saved the record whenever a row fails: subject "PartnerPage listing sync: N of M record(s) failed", one line per External ID. Jobs are listed under Setup › Apex Jobs as PartnerPageSyncListingJob.

  • Failed records say why in plain words. Typical causes: the tier id or a filter option id does not exist in the directory, the status is not one of public / hidden / inactive / searchable, the External ID is blank, the API key was rotated (then every record fails with "You do not have permission"), or the saving user lacks the PartnerPage_Integration_User permission set (named credential refused).

  • The action's own result (queued, or failed for records refused before queueing) is available in the Flow if you want to store it on the record or in a custom log object.

  • In the PartnerPage Vendor Dashboard the listing shows the new values and the "last modified" time.

Without the package

Any system can do the same with one HTTP call. Send rows keyed by externalId to POST https://api.partnerpage.io/api/directory/private/v1alpha/external/directories/{directoryId}/entries/partners/bulk/ with Authorization: Token YOUR_ORGANIZATION_API_KEY and {"entries": [{"externalId": "...", "title": "..."}]}. The response is a plain JSON list with one object per row, in the order sent: [{"entryId": "...", "externalId": "...", "action": "created" | "updated" | "unchanged" | "failed", "message": null, "errors": null, "entry": {...}}]; errors holds the field errors of a failed row.

Did this answer your question?