Sertifier + Salesforce Integration
This guide will walk you through the setup process for integrating Sertifier with Salesforce.
How to Set Up the Salesforce Integration with Sertifier
With the Sertifier and Salesforce integration, you can automatically issue digital credentials to your contacts whenever they meet the criteria you define in Salesforce. For example, once a contact's status changes to "Certified" or a custom checkbox like Issue_Credential__c is set to True. Every time a qualifying contact is updated, Salesforce calls Sertifier and issues a credential to that person using the contact's data.
This guide walks you through the complete setup: creating the integrated campaign inside Sertifier, preparing your Salesforce org to securely call the Sertifier API, building the Flow that triggers credential issuance, and optionally writing the verification link back onto the contact record.
Important: The Salesforce setup below uses Salesforce Flow with an HTTP Callout and a Named Credential. You will need a Salesforce user with permissions to create Named Credentials, External Credentials, and Flows (typically a System Administrator). Please make sure the person performing the setup has those permissions before you begin.
Step 1: Create the Integrated Campaign in Sertifier
The first step happens inside Sertifier. You will create the credential campaign that Salesforce will issue from, and then copy its Campaign ID to use later in the Flow.
To begin, log into your Sertifier account and navigate to the Advanced > Integrations tab from the left sidebar. Click Create a New Integration. A list will open up of available integration options. From this list, select Salesforce.
Once selected, you will be guided through the credential campaign creation process. This includes setting up the Design, Details, and Campaign Options for your credential. If you need assistance with these steps, you can check our full credential setup guide.
When you complete all three steps, switch the Active toggle on from the top-right corner and click Copy ID to copy your Campaign ID. You will need this ID for the Salesforce Flow.
Keep this Campaign ID handy. You will paste it into the HTTP Callout configuration in Step 5.
Step 2: Get Your Sertifier API Key
The Salesforce Flow authenticates to Sertifier using your organization's private API key.
In your Sertifier account, go to Settings > API & Integrations and copy your Private API Key. Store it somewhere safe for now. You will paste it into Salesforce in the next step. Treat this key like a password. Anyone with it can issue credentials on behalf of your organization.
Step 3: Configure Authentication in Salesforce
Salesforce stores external API credentials in a combination of an External Credential (which holds the secret) and a Named Credential (which points to Sertifier's API and injects the required headers on every call). Setting this up once means your Flow never needs to handle the raw API key directly.
3.1 Create the External Credential
- In Salesforce, go to Setup and search for Named Credentials.
- Open the External Credentials tab and click New.
- Fill in the details as follows:
- Label: Sertifier External Credential
- Name: Sertifier_External_Credential
- Authentication Protocol: Custom
- Click Save.
- In the Principals related list, click New and configure the principal:
- Parameter Name: Sertifier_Principal
- Identity Type: Named Principal
- Sequence Number: 1
- Under Authentication Parameters, click New and add:
- Name: secretKey
- Value: paste your Sertifier Private API Key here
- Click Save.
3.2 Create the Named Credential
- Back on the Named Credentials page, open the Named Credentials tab and click New.
- Fill in the details as follows:
- Label: Sertifier API
- Name: Sertifier_API
- URL: https://b2b.sertifier.com
- Enabled for Callouts: checked
- External Credential: select the Sertifier External Credential you just created
- Allowed Namespaces: leave blank unless your org uses managed namespaces that need access
- Generate Authorization Header: unchecked (Sertifier does not use the standard Authorization header)
- Under Custom Headers, click New and add the two headers Sertifier requires on every request:
- Name: secretKey | Value:
{!$Credential.Sertifier_External_Credential.secretKey} - Name: api-version | Value: 3.3
- Name: secretKey | Value:
- Click Save.
3.3 Grant Access via a Permission Set
Principals on External Credentials are accessed through Permission Sets, so the user that runs the Flow needs to be granted access.
- In Setup, go to Permission Sets and create a new one called Sertifier Integration Access (or reuse an existing one).
- Open the permission set and select External Credential Principal Access.
- Add the Sertifier_Principal principal from your Sertifier External Credential and save.
- Assign the permission set to the user under which the Flow will run.
Important, the running user is not always you. In a record-triggered flow, the HTTP Callout runs on an asynchronous or scheduled path (see Step 4.5), which executes in the context of the user who updated the record, for example whoever sets the Opportunity to Closed Won. Assign this permission set to every user who can trigger issuance, not only to the admin who builds the Flow. If you prefer a single identity, designate a dedicated running user and assign the permission set there. If you assign it only to yourself, Debug can pass while live issuance fails with a 403.
Step 4: Build the Record-Triggered Flow
Now you will build the Flow that watches for record updates in Salesforce and issues a Sertifier credential whenever the criteria are met. The trigger, object, and conditions below are the most common configuration, but you can adjust them to match any automation you already have in place.
- In Setup, search for Flows and click New Flow.
- Select Record-Triggered Flow and click Create.
- Configure the start:
- Object: Contact (or whichever object you want to issue credentials from, such as Lead, Account, Opportunity, or a custom object)
- Trigger the Flow When: A record is updated
- Set Entry Conditions: choose the condition that should trigger issuance. A common pattern is a checkbox field such as
Issue_Credential__cEquals True, but this can be any combination of field values you like. - When to Run the Flow for Updated Records: select Only when a record is updated to meet the condition requirements. This ensures a record only triggers issuance once, when it first meets your criteria, instead of on every subsequent update. It is your main protection against duplicate credentials.
- Optimize the Flow for: Actions and Related Records
- Click Done.
Note: Any combination of objects, triggers, and conditions is supported. If you would rather issue on record creation, on a scheduled basis, or from a different object, configure the start accordingly, and the rest of the steps apply the same way.
Step 4.5: Add an Asynchronous Path for the Callout
A record-triggered flow cannot call an external API in the same transaction that triggered it. If you put the HTTP Callout on the immediate path, the Flow fails at runtime with "You have uncommitted work pending. Please commit or rollback before calling out." The callout has to run after the triggering record is committed, on an asynchronous path.
When you set Optimize the Flow for to Actions and Related Records in Step 4, also check Include a Run Asynchronously path to access an external system after the original transaction for the triggering record is successfully committed.
After the Start element you will now have two paths:
- Run Immediately: leave this empty, or use it only for in-transaction work such as field updates.
- Run Asynchronously: build the credential issuance here. The HTTP Callout in Step 5, and the Assignment that builds the body in Step 6 if your action needs one, all go on this path.
A scheduled path (for example Run 1 minute after the record is updated) also satisfies this requirement and can be used instead if you want a short delay. Either way, the callout must not sit on the immediate path.
Step 5: Add the HTTP Callout to Sertifier
Salesforce Flow can call external APIs directly using an HTTP Callout action. You will configure this action once, and from then on the Flow will send each qualifying record to Sertifier.
- In your Flow, click the + button on the Run Asynchronously path (or your scheduled path) from Step 4.5 and choose Action.
- In the Action panel, select Create HTTP Callout.
- Fill in the API specification:
- Name: Sertifier Add Credentials
- Description: Sends a credential issuance request to Sertifier
- Named Credential: select Sertifier API
- Click Next and configure the invocable action:
- Label: Add Credentials to Campaign
- Method: POST
- URL Path: /campaign/addCredentials
- Provide Sample Request: click Provide and paste the sample below. Flow Builder uses this sample to generate the input fields you can map record data to.
{ "credentials":
[
{
"campaignId": "YOUR_CAMPAIGN_ID",
"name": "Sample Name",
"email": "sample@example.com",
"externalId": "sample-external-id",
"quickPublish": true
}
]
} - Provide Sample Response: paste the sample below and select 200 as the sample response code. This lets Flow parse the response and expose verificationLink as an output you can use later.Important: Sertifier returns successfully-issued credentials keyed by your Campaign ID inside the data object. Replace YOUR_CAMPAIGN_ID in the sample below with the actual Campaign ID you copied from Sertifier in Step 1, otherwise Flow cannot match the key at runtime and the verificationLink output will be empty.
{
"message": "Credentials added successfully to campaigns.",
"hasError": false,
"validationErrors": [],
"data": {
"YOUR_CAMPAIGN_ID": [
{
"id": "sample-id",
"name": "Sample Name",
"email": "sample@example.com",
"status": 1,
"certificateNo": "sample-cert-no",
"issueDate": "2025-01-01T00:00:00",
"externalId": "sample-external-id",
"certificateImageLink": "https://sertifier.com/...",
"badgeImageLink": "https://sertifier.com/...",
"verificationLink": "https://sertifier.com/cd/sample"
}
]
},
"content": null
} - Click Done to save the HTTP Callout definition.
Why a Named Credential? Because the secretKey and api-version headers are defined on the Named Credential in Step 3.2, they are attached to every callout automatically. The Flow only needs to send the JSON body. The authentication is handled for you.
Step 6: Build the Request Body
How you populate the request depends on what the action shows under Set Input Values. Open the Sertifier Add Credentials action you just created and look at the inputs it exposes.
Case A: the action exposes individual fields
If you see separate inputs for campaignId, name, email, externalId, and quickPublish, map each one as below. Flow wraps them into the credentials array for you.
| Input field | Value | Notes |
|---|---|---|
| campaignId | YOUR_CAMPAIGN_ID from Step 1 | Set this as a static text value. It identifies the credential campaign in Sertifier. |
| name | full name, see note below | Sertifier uses a single name field for the recipient. A formula resource or a text template works well here. |
| the recipient's email address | The address the credential notification email is sent to. It must be populated for the triggering record. | |
| externalId | {!$Record.Id} |
Optional but recommended. Storing the Salesforce Record ID makes it easy to match the credential back to the record later. |
| quickPublish | true | Set to true to publish and email the credential immediately. Set to false if you want to publish later through the Sertifier dashboard. |
Map the full name, not just the first name. Sertifier prints the name value exactly as sent, so mapping only {!$Record.FirstName} produces a one-word name such as "George". Use a formula or text template that combines first and last name:
{!$Record.FirstName} & " " & {!$Record.LastName}
Case B: the action shows a single "Set Request Body" panel
Sometimes Flow generates the action from the array sample and exposes the whole payload as one Apex-defined body object (often shown as a "Set Request Body" panel) instead of individual fields. The object starts empty, and nothing fills it unless you do. An Apex-defined variable that is never assigned stays null at runtime, which produces the error "Missing required input parameter: body". Build the body like this, on the asynchronous or scheduled path from Step 4.5:
- Create the credential item. In the Toolbox, click New Resource. Resource Type: Variable. API Name:
credentialItem. Data Type: Apex-Defined. Apex Class: the auto-generated class for one credentials array item. Its name contains "credentials" and comes from the same family as the body class. - Add an Assignment element named "Build Credential" with these rows:
{!credentialItem.campaignId}Equals your Campaign ID, pasted as text{!credentialItem.name}Equals your full-name formula{!credentialItem.email}Equals the recipient's email field{!credentialItem.externalId}Equals{!$Record.Id}{!credentialItem.quickPublish}Equals{!$GlobalConstant.True}
- Add this row in the same Assignment or a second one:
{!Body.credentials}Add{!credentialItem}
Bodyhere is whatever your Apex-defined body variable is named.) - Open the callout action and set body =
{!Body}. Leave the other inputs empty.
A single Transform element that maps your record fields into the body object works too, if you prefer it to an Assignment.
If you edited the sample request after creating the action. Salesforce keeps the old input mappings on the element, and they will display values that never reach our API. If your inputs look correct but the request behaves as if they are missing, delete the action element on the canvas and re-add it so no stale mappings remain. Do not delete the HTTP Callout definition, only the action element.
Issuing from an object other than Contact
The name and email you send must come from a person record. When your trigger object already holds them (Contact or Lead), map them directly as above. When you trigger from an object that does not, and Opportunity is the most common, you have to reach the related person record first.
- Person Accounts: if the Opportunity's Account is a Person Account, map email from
{!$Record.Account.PersonEmail}and the name from the Account's first and last name fields. PersonEmail is only populated on Person Accounts. On a standard business account it is null, and the recipient will not be emailed. - Business Accounts or Contacts: identify the recipient through the Opportunity's primary Contact Role, or a lookup to the Contact. Use a Get Records element to load that Contact, then map
{!Contact.Email}and the Contact's name fields.
Always confirm the email field you map is actually populated for the records that will trigger the Flow. A null or empty email is the most common reason a credential shows on the dashboard but no email is received.
Building the credentials array for multiple recipients
The Sertifier API expects an array of credential objects, even when you are only sending one. For a single recipient, Case A and Case B above already produce a one-item array. If you would like to group multiple records into a single call, use a Transform element or a collection variable to build the array, then pass it into the credentials input.
Optional fields you can send
The campaign/addCredentials endpoint accepts several additional fields that you can map from your record or leave out entirely:
- issueDate (string, YYYY-MM-DD): the credential's issue date. Defaults to the time of the request if omitted.
- expireDate (string, YYYY-MM-DD): the credential's expiration date. Omit or set to null for credentials that never expire.
- dontSendEmail (boolean): set to true if you want to issue the credential silently without notifying the recipient by email. Defaults to false.
- attributes (array): custom attribute values when your campaign's Design or Email Template uses custom Attributes. Each entry has an id (the Attribute's ID) and a value.
If you want to use any of these, add them to the sample request body in Step 5 before mapping them here.
Step 7: (Optional) Write the Verification Link Back to the Contact
If you would like to store the issued credential's verification link on the Salesforce record (for example, to display it on the contact page, include it in emails, or report on issuance), add an Update Records element after the HTTP Callout.
Note: If you do not wish to update the record with the URL of the issued credential, this step is not required. The Flow will still successfully issue the credential.
Before starting, create a custom field on the Contact object, for example a URL or Text(255) field named Sertifier_Verification_Link__c. This is where the link will be written.
- In the Flow, click + below the HTTP Callout action and add an Update Records element.
- How to Find Records to Update and Set Their Values: select Specify conditions to identify records, and set fields individually.
- Update Records of This Object Type:
- Object: Contact (match the object of your Flow start)
- Filter Contact Records:
- Condition Requirements: All Conditions Are Met (AND)
- Field: Id | Operator: Equals | Value:
{!$Record.Id}
- Set Field Values for the Contact Records:
- Field: Sertifier_Verification_Link__c | Value: the verificationLink output from the Sertifier Add Credentials action. In the resource picker, drill into the action's output under data → your Campaign ID → select the first element of the array → verificationLink. (The exact merge path will reflect the Campaign ID you used in your sample response.)
- Click Done.
How long until the link works? The verificationLink is returned in the response immediately, but if quickPublish is set to true the credential briefly sits in a publishing queue. The link becomes live within a few seconds of the call completing.
Step 8: Test, Then Save and Activate the Flow
Debug issues real credentials. An HTTP Callout runs for real during Debug, even in rollback mode. Rollback only undoes record changes inside Salesforce, not the external call. So every debug run that reaches Sertifier issues a live credential and, if quickPublish is true, sends a real email. While testing, use a recipient address you control, or set quickPublish to false (publish later from the dashboard) or dontSendEmail to true. Switch to your live settings before you activate.
Before you activate
- The HTTP Callout is on a Run Asynchronously or scheduled path, not the immediate path.
- The request body is populated: individual field mapping (Case A) or an Assignment that Adds the credential to the credentials array (Case B).
- The Sertifier Integration Access permission set is assigned to the users who will trigger the Flow, not only to the admin who built it.
- name maps to a full name. email maps to an address that is actually populated for the triggering records.
- Entry conditions plus "Only when a record is updated to meet the condition requirements" are set, to avoid duplicate issuance.
- You tested with a recipient you control, and quickPublish or dontSendEmail are set the way you want for go live.
Save and activate
- Click Save at the top-right of Flow Builder.
- Give the Flow a clear label such as Sertifier - Issue Credential on Contact Update.
- Run the Flow once using Debug to confirm the callout succeeds and a credential is created in your Sertifier dashboard.
- When you are ready, click Activate to turn the Flow on.
That's it. Your Salesforce records will now automatically issue Sertifier credentials as soon as they meet the criteria you defined.
Troubleshooting
The Flow fails with "You have uncommitted work pending." The HTTP Callout is on the immediate path. Move it to a Run Asynchronously or scheduled path. See Step 4.5.
The Flow fails with "Missing required input parameter: body". The request body is an empty Apex-defined object that nothing filled. Build it with an Assignment and the Add operator, or a Transform element. See Step 6, Case B.
The callout fails with a 403 (Forbidden). The secretKey reaching Sertifier is empty or invalid. Check in this order:
- Permission set and running user. Salesforce only injects the secretKey if the user running the Flow has External Credential Principal Access to Sertifier_Principal. On an asynchronous or scheduled path, the Flow runs as the user who updated the record, for example whoever set the Opportunity to Closed Won, not the admin who built it. Debug runs as you, so it can pass while live issuance fails. Assign the Sertifier Integration Access permission set to every user who can trigger the Flow, or designate a dedicated running user and assign it there.
- The key value. Re-paste your Private API Key on the External Credential principal. Watch for a trailing space or a partial copy, and make sure it belongs to the same Sertifier organization that owns the campaign.
- The headers. Confirm secretKey =
{!$Credential.Sertifier_External_Credential.secretKey}and api-version = 3.3 on the Named Credential, with Generate Authorization Header unchecked.
Hardcoding the raw key directly into the header instead of the {!$Credential...} reference will make the call work, but it stores your key in plain text on the Flow. Use it only to confirm the cause, then switch back to the credential reference.
The callout succeeds but no credential appears in Sertifier. Check the response hasError field and the validationErrors array in the HTTP Callout output. The most common cause is an incorrect campaignId. Make sure the ID you pasted in Step 6 matches a campaign that is Active in your account.
The credential appears in Sertifier but no email arrives. Issuance and email delivery are separate steps. First confirm the email you mapped is valid and populated for that record (see "Issuing from an object other than Contact"). If quickPublish is true the email sends right after issuance, so allow a short time for delivery. If your recipients are on a managed domain such as a university, their IT may need to whitelist Sertifier's sending domain.
The verificationLink field is empty in the Update Records step. Confirm the sample response you provided in Step 5 uses your real Campaign ID as the key inside data, not the placeholder. If the structure does not match Sertifier's response, Flow may not expose verificationLink as a selectable resource.
Need a hand?
If anything is not working as expected, reach out to us at support@sertifier.com and our team will be happy to help you get the integration running.