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,unchangedorfailedwith 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; |
Status | status |
|
Featured | featured |
|
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 |
|
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
Install the package and configure it (README: API key on the External Credential principal, directory id in the custom metadata record,
PartnerPage_Integration_Userpermission set for the users whose Account edits should trigger the sync).Open Setup › Flows ›
PartnerPage_Sync_Partner_Listing. It ships inactive as a template.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 = Partneris a placeholder (a checkbox or record type works too), and theISCHANGEDterms 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 allowISCHANGEDon long text areas such as Description, so an edit to the description alone is synced with the next Name or Website change).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__con the custom metadata record to the same field, so the editor components resolve the same value.Nothing else to wire for alerts: the action answers
queuedfor 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 asfailedwith the reason in the action's result, if you want to branch on it.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,failedwith 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 asPartnerPageSyncListingJob.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 thePartnerPage_Integration_Userpermission set (named credential refused).The action's own result (
queued, orfailedfor 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.
