A Practical Salesforce + Persona Integration Pattern for High-Risk ID Verification

Posted on

During a new sales process, not every customer needs to complete identity verification. Many organizations first make a risk decision: if the customer appears low risk, the sale can continue through the standard path; if the customer is considered high risk, the business may require an additional identity verification step before the downstream sales process can move forward.

That is where a Salesforce and Persona integration becomes useful.

In this pattern, Salesforce does not perform the identity verification itself. Salesforce owns the sales process, customer record, verification request, and downstream automation. Persona owns the identity verification experience through a Persona Inquiry, including the customer-facing flow for ID upload, selfie or liveness checks, matching, and decisioning.

The challenge is not just verifying identity; it is doing it without breaking the sales process or losing visibility inside Salesforce. The integration goal is straightforward: when a high-risk customer is identified, Salesforce creates a controlled verification request, sends the customer to Persona, and lets Persona update Salesforce when the verification result is ready.

Integration Pattern Overview

This article uses three main concepts:

ConceptRole
Salesforce AccountRepresents the customer
Salesforce Persona ActionRepresents one ID verification request or attempt
Persona InquiryRepresents one Persona verification flow instance

The core relationship is:

  • One Salesforce Account can have many Persona Actions over time.
  • One Persona Action maps to one Persona Inquiry.
  • One Persona Inquiry maps back to one Persona Action.

This 1-to-1 mapping between Persona Action and Persona Inquiry keeps each verification attempt auditable. It also makes retries and expirations easier to manage because Salesforce can always identify the exact verification request associated with a Persona Inquiry.

The following diagram shows the hosted-flow version of this integration pattern.

Figure 1: Salesforce creates a Persona Action, requests a Persona Inquiry, sends the verification link to the customer, and Persona updates the Persona Action status after verification.

Persona Inquiry Template Configuration

The focus of this article is the Salesforce-Persona integration, so the Persona background can stay concise. The key Persona configuration concept is the Persona Inquiry Template.

Persona Inquiry Template is the reusable configuration, or blueprint, for a verification flow. A Persona Inquiry is a specific instance of that template created for one customer verification request. In this pattern, Salesforce creates a new Persona Inquiry from the selected template whenever a Persona Action needs ID verification.

For a high-risk sales flow, the template may include:

  • Government ID upload
  • Selfie or liveness capture
  • ID-to-selfie matching
  • Decision outcomes such as approved, declined, or needs review
  • Branding and customer-facing instructions

Persona supports template versioning. If Salesforce uses an Inquiry Template ID beginning with itmpl_, new Persona inquiries use the latest published version of that template. If Salesforce uses an Inquiry Template Version ID beginning with itmplv_, Salesforce is pinned to a specific version snapshot.

That decision is architectural. Use the template ID when Persona configuration changes should take effect without a Salesforce deployment. Use the template version ID when Salesforce should stay locked to a tested version of the verification flow.

In many organizations, template ownership sits with the identity, risk, or compliance team, while Salesforce owns when the template is invoked and how the result affects the sales process.

Identifier Mapping

A common design mistake is using only the Salesforce Account ID to map Persona results back to Salesforce. That works only if a customer can have one verification request. In practice, the same customer may retry verification, re-verify later, abandon a previous attempt, or have an old request expire.

A stronger pattern is to send two Salesforce identifiers to Persona:

Salesforce ValuePersona UsagePurpose
Salesforce Account IDPersona reference-idCustomer-level grouping
Salesforce Persona Action IDPersona custom field, such as actionIdExact verification request mapping

The Persona reference-id links multiple Persona inquiries to the same customer, while the custom actionId identifies the exact Salesforce Persona Action record to update when Persona sends the verification result.

This gives the integration two levels of correlation:

  • Customer-level correlation through the Salesforce Account ID
  • Verification-request correlation through the Salesforce Persona Action ID

When Persona updates Salesforce directly through a Salesforce connection, the Persona Workflow can use actionId to find and update the correct Persona Action record. If the implementation uses a webhook instead, the same actionId should be included in the webhook payload and used by Salesforce or middleware to locate the correct record.

Updating Salesforce from Persona

There are two common ways to update Salesforce after Persona completes the verification.

PatternHow It WorksWhen to Use It
Persona Workflow with Salesforce connectionPersona directly updates the Persona Action record in SalesforceUse when Persona can connect to Salesforce and update the target record directly
Webhook or middlewarePersona sends an event to a Salesforce endpoint or middleware layer, which updates SalesforceUse when the team wants custom processing, centralized integration logic, or additional validation outside Persona

In this design, the preferred path is Persona Workflow with a Salesforce connection. Persona already has the actionId, so the Workflow can locate the corresponding Persona Action and update its status based on the verification result.

For example:

  • If the Persona Inquiry is approved, update the Persona Action status to Approved.
  • If the Persona Inquiry fails or is declined, update the Persona Action status to Failed.
  • If the result requires manual review, route it according to the business process, such as keeping the action pending or assigning it to a review queue.

Webhooks are still a valid integration option. They are especially useful when the Salesforce update needs custom Apex logic, middleware transformation, additional fraud checks, or complex orchestration. The important design principle is the same in both patterns: Persona must send enough context, especially actionId, so the exact Persona Action can be updated deterministically.

End-to-End Flow

The end-to-end flow looks like this:

  1. A Salesforce process or upstream risk engine flags a customer as high risk.
  2. Salesforce creates a Persona Action with status New.
  3. Salesforce calls Persona’s API to create a Persona Inquiry from the selected Inquiry Template.
  4. Persona returns the Persona Inquiry ID.
  5. Salesforce stores the Persona Inquiry ID on the Persona Action.
  6. Salesforce generates or requests a verification link.
  7. Salesforce sends the link to the customer by email, SMS, portal notification, or another approved channel.
  8. Salesforce updates the Persona Action status to Requested.
  9. The customer opens the Persona verification flow.
  10. The customer completes ID upload, selfie or liveness capture, and matching.
  11. Persona evaluates the verification result.
  12. A Persona Workflow uses the Salesforce connection to update the matching Persona Action record to Approved or Failed.

Salesforce then controls the downstream process:

  • If the Persona Action becomes Approved, the sales process can continue.
  • If the Persona Action becomes Failed, Salesforce can apply business rules, such as creating a new Persona Action for another attempt.
  • If the Persona Action becomes Expired, the current verification request should no longer be usable.

Calling Persona from Salesforce

The exact payload depends on your Persona configuration, but the following Apex-style example shows the key integration values Salesforce should send when creating a Persona Inquiry. It is intentionally short: production code should add stronger error handling, request/response logging, retry controls, response typing, and secure exception handling.

public with sharing class PersonaInquiryService {
public static String createInquiry(
Id accountId,
Id personaActionId,
String inquiryTemplateId,
Datetime expiresAt
) {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Persona_Named_Credential/api/v1/inquiries');
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setHeader('Idempotency-Key', String.valueOf(personaActionId));
Map<String, Object> body = new Map<String, Object>{
'data' => new Map<String, Object>{
'attributes' => new Map<String, Object>{
'inquiry-template-id' => inquiryTemplateId,
'expires-at' => expiresAt.formatGmt('yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\''),
'fields' => new Map<String, Object>{
'actionId' => new Map<String, Object>{
'type' => 'string',
'value' => String.valueOf(personaActionId)
}
}
}
},
'meta' => new Map<String, Object>{
'auto-create-account-reference-id' => String.valueOf(accountId)
}
};
req.setBody(JSON.serialize(body));
HttpResponse res = new Http().send(req);
if (res.getStatusCode() < 200 || res.getStatusCode() >= 300) {
throw new CalloutException('Persona create inquiry failed: ' + res.getBody());
}
Map<String, Object> parsed =
(Map<String, Object>) JSON.deserializeUntyped(res.getBody());
Map<String, Object> data = (Map<String, Object>) parsed.get('data');
return (String) data.get('id');
}
}

In this implementation pattern, the create-inquiry API response returns the Persona Inquiry ID. Salesforce should save that ID on the Persona Action record. If Salesforce needs a customer access link, it can generate the hosted URL from the Inquiry ID or make a separate Persona API call to create a one-time link, depending on the selected user experience.

Use a Salesforce Named Credential or secure middleware layer for Persona authentication. Do not hardcode API keys in Apex.

Hosted Flow, Embedded Flow, and Link Strategy

The diagram for this article shows a Persona Hosted Flow pattern. In that approach, Salesforce sends the customer a Persona-hosted verification URL by email, SMS, or another communication channel. The customer leaves the Salesforce-controlled process, completes the Persona experience, and Persona updates Salesforce after verification.

That is not the only possible pattern.

Once Salesforce has created and stored the Persona Inquiry ID, the same architecture can also support an Embedded Flow pattern. In an embedded flow, the business can present Persona inside a web page or portal experience instead of sending the customer to a separate hosted page. The key design remains the same: Salesforce owns the Persona Action, and Persona owns the Persona Inquiry.

There are also different link strategies:

Link StrategyDescription
Persistent verification URLA Persona domain plus Inquiry ID
One-time linkSalesforce calls Persona to generate a temporary access link for the same Persona Inquiry

One-time links are usually a better production pattern for email or SMS because they avoid exposing the raw Inquiry ID in the customer-facing link. A one-time link should be treated as single-use access, not as a reusable resume link.

If the customer needs to resume verification later, Salesforce can generate a fresh one-time link for the same Persona Inquiry. That can be triggered by a support agent, sales rep, automated reminder, or secure self-service resend flow.

Expiration Design

Expiration is important because verification links should not live forever.

This pattern uses two expiration controls:

  1. When Salesforce creates the Persona Inquiry, it sets or relies on an expiration policy so the inquiry is not valid indefinitely.
  2. When Salesforce sets the Persona Action status to Expired, Salesforce triggers an API call to Persona to expire the Persona Inquiry.

Both controls are useful.

Persona-side expiration protects verification sessions and links that were created but never completed. Salesforce-driven expiration handles business events: a sale is cancelled, a duplicate request is found, a newer verification attempt replaces the old one, or a user manually withdraws the verification requirement.

Expiration should be controlled from both sides: Persona protects the verification session with inquiry/session expiration, while Salesforce can explicitly expire the Persona Inquiry when the Persona Action is no longer valid.

After the Persona Inquiry is expired, the old customer link should no longer allow verification. That keeps the Salesforce business state and the Persona verification state aligned.

Salesforce Status Lifecycle

The Persona Action status is the control point for the Salesforce process.

StatusMeaning
NewPersona Action created, but no Persona link has been sent yet
RequestedPersona link sent to the customer
ApprovedPersona verification succeeded
FailedPersona verification failed
ExpiredPersona Action is no longer valid; Salesforce expires the Persona Inquiry

Persona has its own inquiry statuses and events. Salesforce does not need to mirror them exactly. Instead, Salesforce should map Persona results into business-friendly Persona Action statuses that downstream automation can understand.

For example, Persona can use a Workflow and Salesforce connection to update a Persona Action to Approved. Salesforce can then trigger the next sales process. If Persona updates the action to Failed, Salesforce can apply the retry rules defined by the business.

Design Considerations and Best Practices

A few design choices make this integration easier to support:

  • Use a Salesforce Named Credential or secure middleware layer for Persona API authentication.
  • Store the Persona Inquiry ID on the Salesforce Persona Action.
  • Use Salesforce Account ID as the Persona reference-id, rather than email address or sensitive personal information.
  • Use actionId so Persona Workflow or webhook-based updates can find the exact Persona Action.
  • If using Persona Workflow with a Salesforce connection, keep the field mapping simple and deterministic.
  • If using webhooks, make webhook processing idempotent because events may be retried.
  • Log request and response metadata for operational support.
  • Consider one-time links for email or SMS delivery.
  • Decide whether Salesforce should use the latest Inquiry Template ID or a pinned Inquiry Template Version ID.
  • Define retry rules clearly so each new attempt creates a clean Persona Action and Persona Inquiry.

The retry rule is especially important. If a customer fails verification and the business allows another attempt, a clean design is to create a new Persona Action and a new Persona Inquiry. That keeps every attempt separate and auditable.

Why This Pattern Works

This pattern works well because responsibilities are clearly separated:

  • Salesforce keeps the customer record, audit trail, and sales process state.
  • Persona handles the specialized identity verification experience.
  • The Persona Action and Persona Inquiry mapping makes each attempt traceable.
  • Retry and expiration rules remain controlled by Salesforce business logic.
  • Persona Workflow can update Salesforce directly, while webhooks remain available for teams that need additional integration control.

Conclusion

The main design principle is straightforward:

Salesforce owns the sales process and Persona Action lifecycle; Persona owns the identity verification experience through the Persona Inquiry.

This division of responsibility gives Salesforce teams a reusable integration pattern. Salesforce decides when verification is needed, tracks every verification attempt, controls downstream automation, and keeps the audit trail. Persona provides the specialized ID verification flow and can update Salesforce directly through a Workflow and Salesforce connection.

For high-risk new sales, this pattern creates a clean bridge between risk decisioning, customer identity verification, and Salesforce-driven business process automation.

Automated PDF Generation in Salesforce Using Conga Composer

Posted on

A practical Salesforce architecture for generating PDFs with Conga Composer using Flow, asynchronous Apex, and REST-based integration.

Introduction

Salesforce is excellent at managing customer data and automating business processes. But when teams need to generate complex documents such as sales contracts, renewal notices, and customer agreements, the native platform often needs help from a dedicated document generation tool.

In enterprise Salesforce implementations, document generation is rarely a one-click problem. Sales and renewal processes often require:

  • Dynamic data from multiple Salesforce objects
  • Conditional logic based on deal type, product, customer segment, or region
  • Corporate-approved branding and formatting
  • Automated generation as part of a larger business workflow

This article walks through a practical architecture for automated PDF generation in Salesforce using Conga Composer. The focus is not only the Conga merge itself, but the surrounding automation pattern: Flow, asynchronous Apex, REST-based invocation, and downstream document reuse.

The key design choice is to treat Conga Composer as part of the Salesforce automation architecture, rather than as a standalone button users click manually. Done well, automated document generation reduces manual errors, supports compliance, and gives sales and operations teams a reliable document pipeline.

Business Scenario

Consider a sales process where a PDF must be generated immediately after an Opportunity is closed won and the related Order is created. The generated document may need to support email delivery, physical mailing, audit history, or later customer service workflows.

The main requirements are:

  • Generate the PDF automatically after a business transaction completes.
  • Use Salesforce data as the source of truth.
  • Save the generated PDF so other processes can reuse it.
  • Make the document visible from the Order, Opportunity, and Account.
  • Keep the design scalable enough for enterprise sales and renewal processes.

In the example architecture, the Order becomes the document anchor. After an Opportunity is marked Closed Won, Salesforce creates an Order with the data required for the merge. Conga Composer generates the PDF, saves it to the Order, and asynchronous Apex associates the same file with the Opportunity and Account for visibility and downstream use.

Solution Overview

The solution combines three main components:

  • Salesforce Flow to start the process when the Order is ready.
  • Asynchronous Apex to handle callouts, polling, persistence, and follow-up work.
  • Conga Composer REST APIs to generate and save the PDF document.

At a high level, the workflow is:

  1. An Opportunity is marked Closed Won.
  2. A Salesforce Order is created with the relevant data.
  3. A record-triggered Flow starts an asynchronous Apex process.
  4. Apex selects the correct Conga template based on the Order and related records.
  5. Apex invokes Conga Composer through the REST API.
  6. Conga generates the PDF and saves it to Salesforce.
  7. Apex associates the PDF with the Order, Opportunity, and Account.
  8. Downstream processes use the document for email, mailing, compliance, or fulfillment.

Salesforce Automation Design

Use the Order as the Document Anchor

Using the Salesforce Order as the primary document anchor keeps the document generation process stable. The Opportunity may continue to evolve as part of sales reporting, but the Order is usually a better representation of the completed transaction that needs documentation.

In this pattern, the Order serves as:

  • The primary source of data for PDF generation
  • The first attachment target for the generated PDF
  • A stable anchor for downstream automation

Keep Flow Simple and Move Heavy Work to Apex

A record-triggered Flow can detect that the Order is ready and then hand off the heavy work to asynchronous Apex, such as a Queueable class. This keeps the Flow maintainable while giving Apex responsibility for external callouts, polling, error handling, and file association.

This approach also avoids putting long-running integration logic directly inside the transaction that creates or updates the Order.

The benefits are practical:

  • Governor limits are easier to manage.
  • The user interface remains responsive.
  • Callouts to Conga Composer can be handled in a controlled async process.
  • The architecture can support retries, logging, and operational monitoring.

Conga Composer Integration

REST-Based Invocation Pattern

For automated enterprise workflows, REST-based invocation is usually the cleaner pattern. Apex authenticates with Conga, starts the merge request, receives a correlation ID, and then checks the generation status until the document is complete.

The integration typically includes:

  • OAuth authentication with Conga using a client ID and client secret.
  • A POST request to the Conga Ingress API to initiate document generation.
  • A correlation ID returned by Conga for tracking the async generation request.
  • A status check that confirms when the PDF has been generated.
  • Persistence of the generated PDF back into Salesforce based on the request options.

The request normally includes the Salesforce access token, Salesforce instance URL, Conga template ID, and Salesforce master object ID, such as the Order ID.

Apex Code Example: Conga REST Ingress Call

The following simplified Apex example shows how an asynchronous Salesforce process can initiate PDF generation for an Order. In production, use secure credential storage, add retry and timeout handling, and log integration events so support teams can troubleshoot failed document jobs.

// 1. Set the Conga Ingress API endpoint
String endpoint = 'https://coreapps-rlsprod.congacloud.com/api/ingress/v1/Merge';
// 2. Build the JSON request body
Map<String, Object> legacyOptions = new Map<String, Object>{
'TemplateId' => 'a4LXXXXXXXXXXXXXXX', // Conga template record ID
'APIMode' => '1', // Attach document to master object
'DefaultPDF' => '1' // Generate PDF output
};
Map<String, Object> jsonBody = new Map<String, Object>{
'access_token' => sfAccessToken,
'instance_url' => Url.getOrgDomainUrl().toExternalForm(),
'salesforceMasterObjId' => orderId,
'LegacyOptions' => legacyOptions
};
// 3. Prepare the HTTP request
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint);
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setHeader('Authorization', 'Bearer ' + congaAuthToken);
req.setBody(JSON.serialize(jsonBody));
req.setTimeout(60000);
// 4. Send the request
Http http = new Http();
HttpResponse res = http.send(req);
// 5. Handle the response
if (res.getStatusCode() == 200 || res.getStatusCode() == 201) {
Map<String, Object> responseMap =
(Map<String, Object>) JSON.deserializeUntyped(res.getBody());
return (String) responseMap.get('correlationId');
}
throw new CalloutException('Conga API Error: ' + res.getBody());

URL-Based Invocation as a Legacy Pattern

Conga Composer also supports a URL-based invocation model. Some Salesforce implementations still use it, especially older automations or button-driven processes. In that model, an HTTPS GET request passes parameters through a generated URL, and authentication is commonly handled through the Salesforce session context.

That pattern can still work, but REST-based invocation is better suited for scalable automated document generation because it separates initiation, status tracking, and persistence more cleanly.

Template Selection Logic

Conga Composer templates are Salesforce records, which makes them manageable from inside the platform. A template is stored as anAPXTCong4__Conga_Template__crecord and can be selected dynamically using SOQL, Flow configuration, custom metadata, or business rules implemented in Apex.

This gives the implementation useful flexibility:

  • Different templates can be selected based on Order, Account, Opportunity, product, region, or customer segment.
  • Template changes can be made without redeploying Apex code.
  • Template access can follow Salesforce security and governance practices.
  • Business teams can evolve document content while the integration pattern remains stable.

Document Persistence Strategy

Once Conga finishes processing, the generated PDF should be saved in a place where users and automation can reliably find it. The first save target is usually the master object passed to Conga, such as the Order. From there, asynchronous Apex can associate the same document with related records.

A common persistence strategy is:

  • Attach or relate the generated PDF to the Order.
  • Associate the same PDF with the Opportunity for sales visibility.
  • Associate the same PDF with the Account for account-level history.
  • Trigger downstream processes only after the PDF is confirmed to exist.

Decoupling document generation from distribution makes the architecture more flexible. Email delivery, mailing integrations, compliance workflows, and customer service processes can all consume the same generated document without each one needing to understand the Conga merge process.

Conclusion

Automated document generation is a core capability in many Salesforce sales and renewal processes. Salesforce provides the data, workflow, and platform automation foundation, while Conga Composer provides the document merge and formatting engine needed for polished customer-facing PDFs.

The strongest implementations treat document generation as an architecture pattern, not a one-off button. Flow starts the process, asynchronous Apex handles integration and orchestration, Conga generates the PDF, and Salesforce stores the resulting document where users and downstream automation can use it.

For teams building scalable Salesforce processes, this pattern reduces manual work, improves document consistency, and creates a reliable foundation for email, mailing, fulfillment, and audit workflows.

Programmatically Check the salesforce field properties

It is very common that we need to check the field properties of a salesforce object. If there are a large number of fields, it is very time consuming to click on each field one at a time from salesforce user interface.  The following Apex code demonstrates how to print the nullable properties of all the fields in the Account object. You can change it to other objects or print different field properties.

Schema.DescribeSObjectResult r = Account.sObjectType.getDescribe();

Map<String,Schema.SObjectField> M = r.fields.getMap();
for(String fieldName : M.keySet()){
Schema.SObjectField field = M.get(fieldName);
Schema.DescribeFieldResult F = field.getDescribe();
Boolean isFieldreq  = F.isNillable() ;
System.debug (fieldName + ‘ is null:  ‘ +  isFieldreq);

}

Getting Salesforce.com Certified Force.com Developer Certification

Posted on

A good study resource for Dev 401

Getting Salesforce.com Certified Force.com Developer Certification.

Salesforce rule and trigger execution order

Posted on

The following is the order salesforce logic is applied to a record.

  1. Old record loaded from database (or initialized for new inserts)
  2. New record values overwrite old values
  3. System Validation Rules
  4. All Apex before triggers (EE / UE only)
  5. Custom Validation Rules
  6. Record saved to database (but not committed)
  7. Record reloaded from database
  8. All Apex after triggers (EE / UE only)
  9. Assignment rules
  10. Auto-response rules
  11. Workflow rules
  12. Escalation rules
  13. Parent Rollup Summary Formula value updated (if present)
  14. Database commit
  15. Post-commit logic (sending email)

Additional notes:

There is no way to control the order of execution within each group above.

Workflow field updates that run based on an approval process or time-dependent action do not trigger any rules.

Formula fields do not execute in this way. They calculate and display their results real-time whenever the field is accessed in any way. So for example if a Workflow Rule uses a Formula Field in its criteria or formula, the formula field is evaluated when the Workflow Rule criteria is checked.

The features that have to be enabled by Salesforce Support

Posted on

Hide SFDC Brand
Hide SFDC Logo in CSS (Hide Salesforce Logo in Self Service Portal)
Manage Person Accounts
Multi-currency
More Decimals on Price
Single Sign-On
Translation Workbench
Daily Lead Limit
Daily Case Limit
Upload Size (MB)
Max Active Rules Per Entity (mass workflow rules)
Max Sharing Rules Per Entity
Max Actions per rule
Customizable Forecasting
Create Audit Fields (System Modifiable Fields)
Extended Mail Merge
Encrypted Fields
Disable Email Change Notification AND/OR Add Allowed Domain
Trial Expiration Date
Mass Email Permission (for trial)
Massmail Recipient Limit
Roll-Up Summary Field
Enable Content Delivery Setup
API Returns the state [address] regardless of the user locale
Advanced Search in Sidebar
Campaign association to opportunity from contact
Case duration age in business hours
HTML Solutions
Local Names
Quantity schedule revenue related
Rename Standard Objects
End User Languages
Supply Default Opportunity line item values
Territory Management
License Count Synchronization Between Sandbox & Production
Change “System Administrator” user e-mail address
Data Export
Divisions Enabled
Daily Massmail Limit
Increase API Request Limit Override
Daily Incoming Email Limit
One-Off Salesforce Sandbox Refresh
[Please be advised that the only time we are able to approve sandbox refreshes is when the sandbox did not refresh correctly due to a bug or error.]
Migrating Archived Activities