Agentforce: Your AI Sales Rep on Revenue Cloud

Agentforce: your next Salesforce sales rep is an AI agent, from Account to activated Order on Revenue Cloud Advanced in 9 chat messages
How our Agentforce SalesOpp Agent takes a sale on Salesforce Revenue Cloud Advanced from a brand-new Account to an activated Order in just nine chat messages, with the architecture, Apex actions, subagent rules and sandbox screenshots for every step.

⚡ Agentforce · Revenue Cloud · Client Case Study

Agentforce: Your AI Sales Rep on Revenue Cloud

How our Agentforce agent runs Revenue Cloud from Account to activated Order in just 9 chat messages.

AgentforceRevenue Cloud AdvancedApex @InvocableMethodSales AutomationEmployee Agent

✍️ By Shivam Shendre  ·  Illustre Software Services  ·  ⏱ 10 min read

9

chat messages from new customer to activated order

12

custom Apex actions, one job each

4

layers, 100% on the Salesforce platform

0

orders activated without a clear “yes”

Picture a sales rep who has just agreed a deal on a call. The customer is happy, the price is settled, and she should be moving on to her next call. Instead, she opens Salesforce and starts clicking. She creates the customer’s account. Then a deal. Then a quote. She searches for the product, types the quantity, adds the discount, sends it for approval, syncs it, creates the order and finally activates it.

That is nine separate screens and dozens of fields for one sale. It is a bit like having to fill in nine different forms every time you buy a coffee. It is slow, it is boring, and every form is another chance for a typo.

Before and after: 9 Salesforce screens versus 9 Agentforce chat messages

So we asked a simple question: what if she could just tell Salesforce what she wants, the same way she would ask a colleague? “Create an account for Asme.” “Add Blockgraph to the quote.” “Activate the order.” And Salesforce simply did it.

That is exactly what we built for one of our clients. The SalesOpp Agent is an AI assistant that lives inside Salesforce. It asks for anything that is missing, double-checks when something is unclear, and never activates an order without a clear “yes”. A full sale, from a brand-new customer to an activated order, now takes nine short chat messages.

One sale, two ways: clicking through Salesforce versus telling the SalesOpp Agent what to do
The SalesOpp Agent living inside the Agentforce panel in Salesforce.
Screenshot  The SalesOpp Agent living inside the Agentforce panel in Salesforce.

How it works, in simple terms

Think of the agent as a new team member with three things:

  • ➜A brain. Agentforce, Salesforce’s AI, understands what the rep types and decides what to do next.
  • ➜A toolbox. Twelve small tools, called actions. Each one does exactly one job, such as “create a quote” or “apply a discount”.
  • ➜A rulebook. Plain-English instructions that tell the agent when to use each tool, and when to stop and ask the rep first.

The rep talks, the brain picks the right tool, the rulebook keeps it safe, and the tool does the work in Salesforce. That’s it. The rest of this blog opens the hood and shows how each part is built.

Under the hood: the architecture

Now for the technical part. The solution runs entirely on the Salesforce platform, on Revenue Cloud Advanced (RCA / ARM) with Agentforce. It has four layers:

From the rep’s message down to the Revenue Cloud records.
Figure  From the rep’s message down to the Revenue Cloud records.
1Agentforce panel: where the rep types, right inside Lightning.
2SalesOpp Agent: an Agentforce Employee Agent with one subagent, “Sales Operations”, which holds the rulebook.
312 custom actions: Apex classes with an @InvocableMethod, one per sales step.
4Revenue Cloud: the standard Account, Opportunity, Quote, Approval and Order records the actions read and write.

The pattern behind every action

Before we go step by step, here is the pattern all twelve actions share. Agentforce reads the label and description of every action and input to decide when to call it, so these descriptions matter as much as the code. Every action also returns a simple Success flag and a plain-English Message instead of throwing errors, so the agent can always explain what happened.

📄 Shared pattern (excerpt)
@InvocableMethod(label='SalesOpp: Create Quote'
    description='Creates a Draft Quote linked to an Opportunity and its Account.')
public static List<Response> run(List<Request> requests) {
    ...
    } catch (Exception e) {
        res.success = false;
        res.message = 'Could not create the quote: ' + e.getMessage();
    }
}
🔒 Security note: every class uses “with sharing”, every query uses WITH USER_MODE and every insert or update runs “as user”. The agent can never do more than the rep is allowed to do.

The rulebook: subagent instructions

The “ask before you act” behaviour doesn’t come from code. It comes from the instructions we wrote for the Sales Operations subagent in Agentforce Builder. A few of the most important rules:

📘 Sales Operations subagent instructions (excerpt)
To create an account, collect Account Name, Account Phone (mandatory), Contact Name,
Contact Email and Billing Address. Ask for everything that is missing in one message.

Before creating a quote, call Find Opportunities. If more than one opportunity is
returned, show the list and ask the user to choose. Never guess.

Only call Activate Order after the user explicitly confirms.

With the pattern and the rulebook in place, let’s walk through the sale one step at a time.

Step 1 of 9

1Create an Account

The rep asks for a new customer account. The agent makes sure it has the phone number, contact and address before it creates anything.

💬 The rep types

Create an account for me

🛠 How it’s built

The action marks Account Phone as required, so the agent has to collect it before it can call the action. The Account and its primary Contact are then created in one go, both as the signed-in rep.

📄 SOA_CreateAccount.cls (excerpt)
@InvocableVariable(label='Account Phone'
    description='Main phone number of the account. Mandatory.' required=true)
public String phone;
...
Account acc = new Account(Name = r.accountName, Phone = r.phone,
    BillingStreet = r.street, BillingCity = r.city, BillingState = r.state, ...);
insert as user acc;
Contact con = new Contact(AccountId = acc.Id, Email = r.contactEmail, ...);
insert as user con;

✅ What happens

✓The agent asks for all missing details in one message, not one at a time.

✓The contact’s full name is split into first and last name automatically.

✓The result: Account “Asme agent”, Contact “Asme Manager”, Account Reference ARN-0063.

🧪 In the sandbox

The agent asks for the details it needs, with the phone number marked mandatory.
Screenshot  The agent asks for the details it needs, with the phone number marked mandatory.
The agent confirms the Account and Contact it created.
Screenshot  The agent confirms the Account and Contact it created.
The new Account record in the sandbox.
Screenshot  The new Account record in the sandbox.

Step 2 of 9

2Create a Deal (Opportunity)

The rep asks for a deal on the new account. When she says the deal should close “one month from today”, the agent works out the actual date.

💬 The rep types

Create a deal / opportunity for this account

one month from today

🛠 How it’s built

The close date input is a real Date. Its description tells the agent to convert relative phrases first, so the LLM does the date maths and the action only ever receives a clean value. The deal name is built from a count of the account’s existing deals.

📄 SOA_CreateOpportunity.cls (excerpt)
@InvocableVariable(label='Close Date' required=true
    description='Convert relative dates such as "one month from today" before calling.')
public Date closeDate;
...
Integer dealNo = [SELECT COUNT() FROM Opportunity WHERE AccountId = :acc.Id WITH USER_MODE] + 1;
Opportunity opp = new Opportunity(AccountId = acc.Id,
    Name = 'Deal ' + dealNo + ' for ' + acc.Name,
    StageName = 'Prospecting', CloseDate = r.closeDate);
insert as user opp;

✅ What happens

✓“one month from today” became 2026-09-27.

✓The deal is named “Deal 1 for Asme agent” and starts at Prospecting.

🧪 In the sandbox

The agent asks for the close date and resolves “one month from today”.
Screenshot  The agent asks for the close date and resolves “one month from today”.
Deal 1 for Asme agent at the Prospecting stage.
Screenshot  Deal 1 for Asme agent at the Prospecting stage.
The full Opportunity record in the sandbox.
Screenshot  The full Opportunity record in the sandbox.

Step 3 of 9

3Create a Quote

The rep asks for a quote. The sandbox had three deals with similar names, so instead of guessing, the agent showed them and asked which one to use.

💬 The rep types

Create a quote

🛠 How it’s built

This step uses two actions. Find Opportunities searches open deals by name and returns the matches. The rulebook tells the agent to show the list when there is more than one. Only after the rep picks one does Create Quote run.

📄 SOA_FindOpportunities.cls (excerpt)
res.opportunities = [SELECT Id, Name, StageName, CloseDate, Account.Name
                     FROM Opportunity
                     WHERE Name LIKE :pattern AND IsClosed = false
                     WITH USER_MODE ORDER BY LastModifiedDate DESC LIMIT 10];
res.matchCount = res.opportunities.size();   // > 1 means: ask the rep

✅ What happens

✓Returning a list of Opportunity records lets Agentforce show them as a pick-list in the chat.

✓Create Quote also sets the deal’s price book if it is empty, which quote sync needs later.

✓The result: Quote 00000080 in Draft, linked to the right deal.

🧪 In the sandbox

The agent finds three similar deals and asks the rep to choose.
Screenshot  The agent finds three similar deals and asks the rep to choose.
The new Quote 00000080 in Draft.
Screenshot  The new Quote 00000080 in Draft.
The full Quote record in the sandbox.
Screenshot  The full Quote record in the sandbox.

Step 4 of 9

4Add a Product

The rep asks to add a product. The agent shows the product catalogue right in the chat, she picks one, and the agent asks how many.

💬 The rep types

Add product to this quote

Blockgraph – $7.5/quarter, quantity 1

🛠 How it’s built

List Products reads the quote’s price book and returns a numbered list. Add Product to Quote then looks the product up by exact name. If it finds none, or more than one, it stops and asks instead of guessing.

📄 SOA_AddProduct.cls (excerpt)
List<PricebookEntry> pbes = [SELECT Id, Product2Id, UnitPrice FROM PricebookEntry
    WHERE Pricebook2Id = :q.Pricebook2Id AND IsActive = true
    AND Product2.Name = :r.productName WITH USER_MODE LIMIT 2];
if (pbes.size() != 1) { /* no match or several: ask the rep to choose */ }
QuoteLineItem line = new QuoteLineItem(QuoteId = q.Id, PricebookEntryId = pbes[0].Id,
    Quantity = r.quantity, UnitPrice = pbes[0].UnitPrice);
insert as user line;

✅ What happens

✓Quantity is a required input, so the agent always asks for it.

✓The quote’s Grand Total updates to $7,500.00.

🧪 In the sandbox

The agent lists the products from the catalogue.
Screenshot  The agent lists the products from the catalogue.
The rep picks the product and quantity.
Screenshot  The rep picks the product and quantity.
Grand Total updated to $7,500.00.
Screenshot  Grand Total updated to $7,500.00.
The Blockgraph quote line.
Screenshot  The Blockgraph quote line.

Step 5 of 9

5Apply a Discount

The rep asks for a 10% discount on the product. One sentence, and it’s done.

💬 The rep types

Apply a 10 percent discount to this product

🛠 How it’s built

Apply Discount finds the matching quote line (asking if several match) and sets the standard Discount percentage field.

📄 SOA_ApplyDiscount.cls (excerpt)
List<QuoteLineItem> lines = [SELECT Id, Product2.Name FROM QuoteLineItem
    WHERE QuoteId = :r.quoteId AND Product2.Name LIKE :pattern WITH USER_MODE];
...
lines[0].Discount = r.discountPercent;   // e.g. 10 for 10%
update as user lines[0];

✅ What happens

✓The Discount (Percentage) column on the line now shows 10.00%.

✓Tip: if your org uses Revenue Cloud pricing procedures, write lines through the Place Sales Transaction API so prices recalculate automatically.

🧪 In the sandbox

The agent confirms the 10% discount.
Screenshot  The agent confirms the 10% discount.
The quote line showing the 10.00% discount.
Screenshot  The quote line showing the 10.00% discount.

Step 6 of 9

6Submit for Approval

The rep sends the quote for approval. The agent politely offers to add a note for the approver first.

💬 The rep types

Submit this quote for approval

please approve

🛠 How it’s built

The action uses Salesforce’s standard Approval API, so the quote goes through the client’s existing approval process with no shortcuts. The optional comment is passed straight to the approver.

📄 SOA_SubmitForApproval.cls (excerpt)
Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
req.setObjectId(r.quoteId);
req.setSubmitterId(UserInfo.getUserId());
if (String.isNotBlank(r.comments)) req.setComments(r.comments);
Approval.ProcessResult pr = Approval.process(req);

✅ What happens

✓The comment is optional, so the rulebook tells the agent to offer it rather than demand it.

✓If your org uses Advanced Approvals, start that approval flow here instead.

🧪 In the sandbox

The agent offers optional comments for the approver.
Screenshot  The agent offers optional comments for the approver.
The Quote is submitted for approval.
Screenshot  The Quote is submitted for approval.

Step 7 of 9

7Sync the Quote

The rep asks to sync the quote, so the deal always shows the same products and prices as the quote.

💬 The rep types

Sync this quote

🛠 How it’s built

Syncing in Salesforce is a single field: the Opportunity’s SyncedQuoteId. The action simply points it at this quote.

📄 SOA_SyncQuote.cls (excerpt)
Quote q = [SELECT Id, OpportunityId FROM Quote WHERE Id = :r.quoteId WITH USER_MODE];
update as user new Opportunity(Id = q.OpportunityId, SyncedQuoteId = q.Id);

✅ What happens

✓Sync only works when the quote and the deal use the same price book. That’s why Create Quote sets it in Step 3.

🧪 In the sandbox

The agent confirms the Quote is synced with its Opportunity.
Screenshot  The agent confirms the Quote is synced with its Opportunity.
The synced Quote in the sandbox.
Screenshot  The synced Quote in the sandbox.

Step 8 of 9

8Create an Order

The rep turns the quote into an order. The agent creates it, tells her the order number, and asks if she wants to activate it.

💬 The rep types

Create an order on this quote

🛠 How it’s built

Instead of copying fields by hand, the action calls Revenue Cloud’s own standard action, createOrderFromQuote, from Apex. It runs in the background, so a second small action, Get Order for Quote, reads back the new order’s number and status.

📄 SOA_CreateOrder.cls (excerpt)
Invocable.Action action = Invocable.Action.createStandardAction('createOrderFromQuote');
action.setInvocationParameter('quoteRecordId', r.quoteId);
Invocable.Action.Result result = action.invoke()[0];

// SOA_GetOrderForQuote.cls
List<Order> orders = [SELECT Id, OrderNumber, Name, Status FROM Order
    WHERE QuoteId = :r.quoteId WITH USER_MODE ORDER BY CreatedDate DESC LIMIT 1];

✅ What happens

✓Using the standard action means products, pricing and billing details carry over exactly as Revenue Cloud intends.

✓Use API version 57.0 or later for createOrderFromQuote (we used 65.0).

✓The result: Order 00000140 in Draft.

🧪 In the sandbox

The agent reports the new Order and asks whether to activate it.
Screenshot  The agent reports the new Order and asks whether to activate it.
The new Order in the Quote’s Orders list.
Screenshot  The new Order in the Quote’s Orders list.
The Quote with its related Order in the sandbox.
Screenshot  The Quote with its related Order in the sandbox.

Step 9 of 9

9Activate the Order

The rep says “activate the order”. The agent checks once more, she says “yes”, and the sale is complete.

💬 The rep types

Activate the order

yes

🛠 How it’s built

Activation is the one step that can’t easily be undone, so it has two guards: the action’s description says to call it only after explicit confirmation, and the rulebook says the same. The code itself is a single update.

📄 SOA_ActivateOrder.cls (excerpt)
@InvocableMethod(label='SalesOpp: Activate Order'
    description='Moves an order from Draft to Activated. Only call after the user explicitly confirms.')
...
update as user new Order(Id = r.orderId, Status = 'Activated');

✅ What happens

✓The order moves from Draft to Activated with an amount of $7,500.00.

✓Nine prompts, zero record pages opened by hand.

🧪 In the sandbox

The rep confirms with “yes” and the agent activates the Order.
Screenshot  The rep confirms with “yes” and the agent activates the Order.
Order 00000140, status Activated, $7,500.00.
Screenshot  Order 00000140, status Activated, $7,500.00.
The activated Order in the sandbox.
Screenshot  The activated Order in the sandbox.

Testing the agent

We tested the agent in Agentforce Builder’s preview panel by running the nine prompts above, in order, and checking every response and record. Once it worked end to end, we saved the same prompts as test cases in Agentforce Testing Center, so every future change is checked against the full journey.

Wrapping up

The SalesOpp Agent shows that an AI agent doesn’t need to be complicated to be useful. Twelve small, well-described actions, one clear rulebook and Salesforce’s own security model were enough to turn a nine-screen process into a nine-message conversation.

  • ➜Faster deals. The full quote-to-order cycle takes minutes in one chat.
  • ➜Fewer errors. Mandatory fields are always collected, and unclear records are always confirmed.
  • ➜Same process every time. Approval and sync are never skipped.

Let’s build yours

Want an agent like this in your org?

We build Agentforce solutions on Revenue Cloud Advanced.

Talk to the Illustre team →✉ sales@illustresoftware.com📞 US: +1 732-429-7715

Or DM us: @illustresoftware

SS

Written by

Shivam Shendre

Shivam writes about Agentforce and Salesforce Revenue Cloud implementations at Illustre Software Services, sharing how we turn multi-screen sales processes into simple conversations.

Share This Post

Subscribe To Our Newsletter

Get updates and learn from the best

More To Explore

Do You Want To Boost Your Business?

drop us a line and keep in touch

Error: Contact form not found.

This will close in 20 seconds