AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Approval Process Apex Patterns

skill-pranavnagrecha-awesomesalesforceskills-approval-process-apex-patterns · by PranavNagrecha

Programmatically driving Salesforce Approval Processes from Apex — `Approval.process(ProcessSubmitRequest)` to submit, `ProcessWorkitemRequest` to approve / reject / reassign, recall semantics, querying `ProcessInstance` and `ProcessInstanceWorkitem` to find pending approvals, and the bulk-submit / bulk-action error-row handling. Covers when to use Apex-driven approval (system-initiated submissio…

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-pranavnagrecha-awesomesalesforceskills-approval-process-apex-patterns

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-pranavnagrecha-awesomesalesforceskills-approval-process-apex-patterns)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Approval Process Apex Patterns? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Approval Process Apex Patterns

The platform provides standard approval-process buttons (Submit for Approval, Approve, Reject, Reassign) on record pages. They work for human-driven, single-record approvals. They don't cover:

  • Programmatic submission (a scheduled batch creates 1,000 records

and submits them all for approval).

  • Programmatic action (a system event approves / rejects on behalf

of a user — careful with this one).

  • Custom UI (a custom Lightning component that bundles submit +

status display + approve buttons).

  • Querying pending items (which records are awaiting approval, by

whom, for how long).

This skill covers the Apex API for those cases.

What this skill is NOT. Defining the Approval Process itself (entry criteria, approval steps, approver assignment) is declarative admin work — see admin/approval-process-design. The modern Flow-based equivalent (Flow Orchestration with interactive steps assigned to approvers) is a different runtime entirely — see flow/flow-orchestration-patterns.


Before Starting

  • Confirm the Approval Process is defined and active. Apex calls

reference the process by name; if it's inactive, the call fails with a generic error.

  • Decide who initiates the approval. User-initiated submissions

carry the user's context (running user becomes the submitter). System-initiated submissions need a submitterId (the user the approval is "from").

  • Decide the bulk shape. Approval.process(...) accepts a list

of Requests up to 200. Above that, batch the submissions.

  • Decide the error-row policy. allOrNone = true (default):

any failure rolls back the whole batch. allOrNone = false: individual failures are reported but successful submissions proceed.


Core Concepts

Request types

| Request | Purpose | |---|---| | Approval.ProcessSubmitRequest | Submit a record into an approval process | | Approval.ProcessWorkitemRequest | Take action on a pending work item — approve / reject / reassign / remove |

Both are passed to Approval.process(...). The call returns a list of Approval.ProcessResult (one per input Request) with success / errors.

ProcessSubmitRequest essentials

Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
req.setObjectId(record.Id);
req.setProcessDefinitionNameOrId('Expense_Approval_Process');  // approval process API name
req.setSubmitterId(UserInfo.getUserId());                       // who's "submitting"
req.setComments('Submitting via batch on month-end close');
req.setSkipEntryCriteria(false);                                 // run the entry criteria
Approval.ProcessResult result = Approval.process(req);

Key options:

  • setProcessDefinitionNameOrId — the API name of the approval

process. Use the API name; hardcoded record IDs are brittle.

  • setSubmitterId — defaults to running user; set explicitly when

you want the approval to appear as "submitted by" a specific user.

  • setSkipEntryCriteria(true) — submit even if the record doesn't

match the process's entry criteria. Useful but dangerous; document why.

  • setNextApproverIds(new List{ ... }) — override the platform's

approver lookup. Required when the process uses "submitter manually selects approver".

ProcessWorkitemRequest essentials

// Find the pending workitem.
ProcessInstanceWorkitem workitem = [
    SELECT Id FROM ProcessInstanceWorkitem
    WHERE ProcessInstance.TargetObjectId = :recordId
      AND ProcessInstance.Status = 'Pending'
    ORDER BY CreatedDate DESC LIMIT 1
];

Approval.ProcessWorkitemRequest req = new Approval.ProcessWorkitemRequest();
req.setWorkitemId(workitem.Id);
req.setAction('Approve');     // 'Approve', 'Reject', 'Removed' (recall), or null + setNextApproverIds for reassign
req.setComments('Approved by system per policy 4.2');
Approval.ProcessResult result = Approval.process(req);

Action values:

  • 'Approve' — approve the workitem.
  • 'Reject' — reject the workitem.
  • 'Removed' — recall the submission (admin-only typically; check

process settings).

  • For reassign: leave action null, set

setNextApproverIds(new List{ newApproverId }).

Querying pending approvals

List pending = [
    SELECT Id, TargetObjectId, Status, CreatedDate,
           (SELECT ActorId, ProcessNodeId FROM Workitems)
    FROM ProcessInstance
    WHERE Status = 'Pending'
      AND TargetObject.Type = 'Expense_Report__c'
];

ProcessInstance is the in-flight approval. ProcessInstanceStep is the audit trail of completed steps. ProcessInstanceWorkitem is the open assignment to a specific approver.

The most common query is "find pending workitems older than N days assigned to inactive users" — the stuck-approval audit pattern.

Bulk submission

Approval.process(...) accepts a List up to 200. Above 200, batch into chunks:

List requests = ...;
for (Integer i = 0; i  chunk =
        new List();
    for (Integer j = i; j  toSubmit = [
            SELECT Id FROM Expense__c
            WHERE Status__c = 'Draft'
              AND Total_Amount__c >= 1000
              AND Submitted_Date__c = NULL
        ];

        List requests = new List();
        for (Expense__c e : toSubmit) {
            Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
            req.setObjectId(e.Id);
            req.setProcessDefinitionNameOrId('Expense_Approval');
            req.setSubmitterId(e.OwnerId);  // from the owner, not the running batch user
            req.setComments('Auto-submitted by month-end batch');
            requests.add(req);
        }

        // Bulk submit, allow partial success.
        for (Integer i = 0; i  chunk = new List();
            for (Integer j = i; j  stuck = [
    SELECT Id, ActorId, Actor.IsActive, CreatedDate,
           ProcessInstance.TargetObjectId, ProcessInstance.Status
    FROM ProcessInstanceWorkitem
    WHERE ProcessInstance.Status = 'Pending'
      AND CreatedDate  7 days on inactive users | **Pattern C** with scheduled batch | Operational monitoring |
| Source record changes invalidate the approval | **Pattern D** recall | Don't let an invalid approval complete |
| Custom Lightning component shows approval status + buttons | Apex-driven submit + workitem actions | Wrap Approval.process() in @AuraEnabled |
| Approval process uses "manually select approver" | Always set `setNextApproverIds` | Required by the process; otherwise submit fails |
| Bulk approve as part of a system batch | **Pattern B** shape (find workitems → ProcessWorkitemRequest) | Same governor budget per call (200 max) |
| User wants to delegate approvals to another user | Standard Delegated Approver field on User; no Apex | Platform handles delegation |
| Audit trail of who-approved-what | Query `ProcessInstanceStep` | Complete audit history per approval |

---

## Recommended Workflow

1. **Confirm the approval process is defined and active.** API name is what Apex references.
2. **Identify the use case.** User-initiated standard button (no Apex), system-initiated submission (Pattern A), system-initiated action (Pattern B), monitoring (Pattern C), recall (Pattern D).
3. **Build with `allOrNone = false`** for any bulk submission to preserve successful submissions.
4. **Set `setSubmitterId` explicitly** when the running user isn't the right "from" user.
5. **For action requests**, query the workitem first (don't try to compute it from the record alone).
6. **Test the failure cases.** Inactive approver, record not matching entry criteria, recalled submission, bulk with mixed valid + invalid records.

---

## Review Checklist

- [ ] Approval process API name (not record Id) is referenced in `setProcessDefinitionNameOrId`.
- [ ] `setSubmitterId` is set explicitly when running-user-as-submitter is wrong.
- [ ] `allOrNone = false` for bulk submissions where partial success is acceptable.
- [ ] `Approval.ProcessWorkitemRequest` finds the workitem via `ProcessInstanceWorkitem` query, not assumed.
- [ ] Auto-approval pattern (Pattern B) has explicit security review — who can publish the trigger event.
- [ ] Recall pattern (Pattern D) handles permission errors gracefully (some processes restrict recall to admins).
- [ ] Stuck-approval monitoring (Pattern C) runs as a scheduled batch with results surfaced to admins.

---

## Salesforce-Specific Gotchas

1. **`setProcessDefinitionNameOrId` accepts the API name; hardcoded record IDs break across orgs.** Use API name. (See `references/gotchas.md` § 1.)
2. **Default `allOrNone = true` rolls back the whole batch on first failure.** Bulk submissions need `allOrNone = false` to preserve successful records. (See `references/gotchas.md` § 2.)
3. **`setSubmitterId` defaults to the running user.** System batches that don't set it explicitly produce approvals "submitted by" the batch service account, not the actual owner. (See `references/gotchas.md` § 3.)
4. **`ProcessWorkitemRequest` action values are case-sensitive strings** — `'Approve'` not `'approve'`. (See `references/gotchas.md` § 4.)
5. **Recall (`'Removed'` action) requires permission** that not every running user has. Test under the actual context. (See `references/gotchas.md` § 5.)
6. **Auto-approval bypasses the approval-process step's "Approver assignment"** — the platform records the running user as the approver, not the configured one. Audit implications. (See `references/gotchas.md` § 6.)
7. **Approval Process Apex API has a per-call governor of 200 requests.** Bulk submissions above 200 need batching. (See `references/gotchas.md` § 7.)

---

## Output Artifacts

| Artifact | Description |
|---|---|
| Apex class implementing the chosen pattern | Submit / action / monitor / recall |
| Bulk submission helper | Chunks 200-at-a-time with allOrNone = false + per-row error logging |
| Stuck-approval monitor | Scheduled batch query + admin notification |
| Test class | Covers success, partial-success, recall, and the inactive-approver case |

---

## Related Skills

- `admin/approval-process-design` — declarative definition of the approval process this skill drives.
- `flow/flow-orchestration-patterns` — modern multi-stage approval pattern in Flow; consider before reaching for Apex.
- `apex/apex-event-bus-subscriber` — when system events drive approval actions (Pattern B).
- `apex/apex-mocking-and-stubs` — for the test class that covers Approval.process() failure modes.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [PranavNagrecha](https://github.com/PranavNagrecha)
- **Source:** [PranavNagrecha/AwesomeSalesforceSkills](https://github.com/PranavNagrecha/AwesomeSalesforceSkills)
- **License:** Apache-2.0
- **Homepage:** https://pypi.org/project/sfskills-mcp/

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.