@@ -18,10 +18,12 @@ const (
1818 // tokenPath is the path to the Salesforce OAuth2 token endpoint.
1919 tokenPath = "/services/oauth2/token"
2020
21- // contactsPath is the path to the Pardot v5 Prospects endpoint. This
22- // endpoint will create a new Prospect if one does not already exist with
23- // the same email address.
24- contactsPath = "/api/v5/objects/prospects"
21+ // contactsPath is the path to the Pardot v5 Prospect upsert-by-email
22+ // endpoint. This endpoint will create a new Prospect if one does not
23+ // already exist with the same email address.
24+ //
25+ // https://developer.salesforce.com/docs/marketing/pardot/guide/prospect-v5.html#prospect-upsert-by-email
26+ contactsPath = "/api/v5/objects/prospects/do/upsertLatestByEmail"
2527
2628 // maxAttempts is the maximum number of attempts to retry a request.
2729 maxAttempts = 3
@@ -60,7 +62,7 @@ type PardotClientImpl struct {
6062 businessUnit string
6163 clientId string
6264 clientSecret string
63- contactsURL string
65+ endpointURL string
6466 tokenURL string
6567 token * oAuthToken
6668 clk clock.Clock
@@ -70,7 +72,7 @@ var _ PardotClient = &PardotClientImpl{}
7072
7173// NewPardotClientImpl creates a new PardotClientImpl.
7274func NewPardotClientImpl (clk clock.Clock , businessUnit , clientId , clientSecret , oauthbaseURL , pardotBaseURL string ) (* PardotClientImpl , error ) {
73- contactsURL , err := url .JoinPath (pardotBaseURL , contactsPath )
75+ endpointURL , err := url .JoinPath (pardotBaseURL , contactsPath )
7476 if err != nil {
7577 return nil , fmt .Errorf ("failed to join contacts path: %w" , err )
7678 }
@@ -83,7 +85,7 @@ func NewPardotClientImpl(clk clock.Clock, businessUnit, clientId, clientSecret,
8385 businessUnit : businessUnit ,
8486 clientId : clientId ,
8587 clientSecret : clientSecret ,
86- contactsURL : contactsURL ,
88+ endpointURL : endpointURL ,
8789 tokenURL : tokenURL ,
8890 token : & oAuthToken {},
8991 clk : clk ,
@@ -140,6 +142,19 @@ func redactEmail(body []byte, email string) string {
140142 return string (bytes .ReplaceAll (body , []byte (email ), []byte ("[REDACTED]" )))
141143}
142144
145+ type prospect struct {
146+ // Email is the email address of the prospect.
147+ Email string `json:"email"`
148+ }
149+
150+ type upsertPayload struct {
151+ // MatchEmail is the email address to match against existing prospects to
152+ // avoid adding duplicates.
153+ MatchEmail string `json:"matchEmail"`
154+ // Prospect is the prospect data to be upserted.
155+ Prospect prospect `json:"prospect"`
156+ }
157+
143158// SendContact submits an email to the Pardot Contacts endpoint, retrying up
144159// to 3 times with exponential backoff.
145160func (pc * PardotClientImpl ) SendContact (email string ) error {
@@ -156,7 +171,10 @@ func (pc *PardotClientImpl) SendContact(email string) error {
156171 return fmt .Errorf ("failed to update token: %w" , err )
157172 }
158173
159- payload , err := json .Marshal (map [string ]string {"email" : email })
174+ payload , err := json .Marshal (upsertPayload {
175+ MatchEmail : email ,
176+ Prospect : prospect {Email : email },
177+ })
160178 if err != nil {
161179 return fmt .Errorf ("failed to marshal payload: %w" , err )
162180 }
@@ -165,7 +183,7 @@ func (pc *PardotClientImpl) SendContact(email string) error {
165183 for attempt := range maxAttempts {
166184 time .Sleep (core .RetryBackoff (attempt , retryBackoffMin , retryBackoffMax , retryBackoffBase ))
167185
168- req , err := http .NewRequest ("POST" , pc .contactsURL , bytes .NewReader (payload ))
186+ req , err := http .NewRequest ("POST" , pc .endpointURL , bytes .NewReader (payload ))
169187 if err != nil {
170188 finalErr = fmt .Errorf ("failed to create new contact request: %w" , err )
171189 continue
0 commit comments