apex-salesforce-id-patterns
Use when working with Salesforce Ids in Apex — validating Id format, detecting the target sObject type from a string Id, or safely handling 15 vs 18-character Ids. Trigger keywords: Id prefix, Id.valueOf, Id.getSobjectType, 15-char, 18-char, case-insensitive Id. NOT for: record access / sharing decisions (see apex-user-and-permission-checks), or bulk Id collection patterns (see apex-bulk-patterns).
Best use case
apex-salesforce-id-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when working with Salesforce Ids in Apex — validating Id format, detecting the target sObject type from a string Id, or safely handling 15 vs 18-character Ids. Trigger keywords: Id prefix, Id.valueOf, Id.getSobjectType, 15-char, 18-char, case-insensitive Id. NOT for: record access / sharing decisions (see apex-user-and-permission-checks), or bulk Id collection patterns (see apex-bulk-patterns).
Teams using apex-salesforce-id-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/apex-salesforce-id-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How apex-salesforce-id-patterns Compares
| Feature / Agent | apex-salesforce-id-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when working with Salesforce Ids in Apex — validating Id format, detecting the target sObject type from a string Id, or safely handling 15 vs 18-character Ids. Trigger keywords: Id prefix, Id.valueOf, Id.getSobjectType, 15-char, 18-char, case-insensitive Id. NOT for: record access / sharing decisions (see apex-user-and-permission-checks), or bulk Id collection patterns (see apex-bulk-patterns).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Apex Salesforce Id Patterns
Activate this skill when Apex must reason about a Salesforce Id — validating it came from a real record, determining which sObject it points to, or comparing Ids across the 15/18-character boundary. It covers the difference between `String` and `Id` types, the prefix-based describe lookup, and case sensitivity of 15-character Ids.
---
## Before Starting
Gather this context before working on anything in this domain:
- Where does the Id come from? User input, external system, URL parameter, SOQL result, or trigger context?
- Is the Id expected to be one specific sObject, or could it be any of several?
- Do you need the **record**, or just the **sObject type**? Type detection is cheap (no SOQL). Fetching the record is not.
- Are both 15-char (case-sensitive) and 18-char (case-insensitive) versions potentially in play?
---
## Core Concepts
### 15 vs 18 Character Ids
- 15-char Ids are **case-sensitive**. `005A000000ABCdE` and `005A000000abcde` are different records.
- 18-char Ids append a 3-character checksum that makes them **case-insensitive** safe to compare as strings.
- The Apex `Id` type **normalizes to 18 characters** on assignment. Comparing `Id == Id` always works.
- Comparing **strings** across the boundary (e.g., a 15-char URL param to an 18-char SOQL result) will return `false` without warning.
### Apex `Id` Is A Typed Value, Not Just A String
- `Id` is a primitive type. Assigning an invalid string to `Id` throws `System.StringException`.
- `Id.valueOf(str)` validates format and sobject-type legitimacy — it throws if the prefix is not a known sObject.
- Prefer `Id` typing over `String` in method signatures when the parameter must be a Salesforce Id.
### Detecting sObject Type From An Id
Two mechanisms, same result:
1. `myId.getSobjectType()` — returns the `Schema.SObjectType` for a typed `Id`. Cheap, no SOQL.
2. `Schema.getGlobalDescribe().get(myId.substring(0,3))` — prefix lookup, but not all prefixes are unique (some managed packages overlap, and custom objects share the `a0*` range).
Rule: always prefer `getSobjectType()` on a typed `Id`. Fall back to prefix only if you have a `String` you cannot type yet.
### Key Prefixes To Recognize
| Prefix | sObject |
|---|---|
| `001` | Account |
| `003` | Contact |
| `005` | User |
| `006` | Opportunity |
| `00Q` | Lead |
| `500` | Case |
| `a0x–a0z, a0*` | Custom objects (prefix is org-specific) |
| `00D` | Organization |
| `0F0` | Folder |
Do NOT hardcode custom object prefixes. They are org-specific.
---
## Common Patterns
### Validate A User-Supplied Id Before Using It
**When to use:** A controller receives an `Id` from a URL, Experience Cloud form, or external integration.
**How it works:**
```apex
public static Account fetchAccount(String rawId) {
Id accountId;
try {
accountId = (Id) rawId;
} catch (System.StringException e) {
throw new AuraHandledException('Invalid Id format.');
}
if (accountId.getSobjectType() != Account.SObjectType) {
throw new AuraHandledException('Id does not belong to an Account.');
}
return [SELECT Id, Name FROM Account WHERE Id = :accountId WITH USER_MODE LIMIT 1];
}
```
**Why not the alternative:** Querying directly with an unvalidated string either throws `QueryException` (wrong prefix) or a less helpful `StringException` with no caller guidance.
### Detect Type Across A Heterogeneous List Of Ids
**When to use:** An Apex method accepts `List<Id>` where entries may belong to different sObjects.
**How it works:**
```apex
Map<Schema.SObjectType, List<Id>> byType = new Map<Schema.SObjectType, List<Id>>();
for (Id idValue : inputIds) {
Schema.SObjectType type = idValue.getSobjectType();
if (!byType.containsKey(type)) byType.put(type, new List<Id>());
byType.get(type).add(idValue);
}
// Issue one SOQL per type instead of per record.
```
### Normalize 15-Char Id To 18-Char For String Compare
**When to use:** Comparing an Id from an external system or CSV (often 15-char) with an Id from SOQL (always 18-char).
**How it works:** Cast through `Id`: `Id normalized = (Id) fifteenCharString;` — the typed Id is 18 chars and case-insensitive-safe for string compare.
---
## Decision Guidance
| Situation | Recommended Approach | Reason |
|---|---|---|
| Comparing two Ids you own | `Id == Id` | Apex normalizes to 18 chars automatically |
| Comparing strings from mixed sources | Cast both to `Id` first | 15 vs 18 char mismatch is silent |
| Detecting sObject from a typed Id | `id.getSobjectType()` | No SOQL, no describe overhead |
| Detecting sObject from a string when you cannot trust the prefix | `Id.valueOf(str).getSobjectType()` | Throws if not a legal Id |
| Validating external-system Ids | `try { (Id) str; } catch ...` | Give a helpful error, not a raw exception |
| Routing logic by object | Switch on `Schema.SObjectType` | Safer than hardcoded prefixes |
---
## Recommended Workflow
1. Identify every point the Id crosses a trust boundary — URL, DTO, CSV, external API response.
2. Type the parameter as `Id`, not `String`, everywhere possible.
3. Where the source is untrusted, wrap the cast in a `try/catch` and surface a clear error.
4. Before SOQL, confirm sObject with `getSobjectType()` (not a string prefix compare).
5. Add a negative test: pass an invalid string, an Id for the wrong object, and an empty string; each should fail cleanly.
---
## Review Checklist
- [ ] No hardcoded 3-character prefixes for custom objects.
- [ ] No `String.startsWith('001')` style type detection where an `Id` is available.
- [ ] All untrusted Id inputs are cast through `Id` or `Id.valueOf` with caught `StringException`.
- [ ] SOQL bind variables typed as `Id` or `Set<Id>`, not `String`.
- [ ] Tests cover: invalid format, wrong-type Id, empty/null.
---
## Salesforce-Specific Gotchas
1. **15-char strings do not equal 18-char strings** — always cast to `Id` before a string compare.
2. **Custom object prefixes are org-specific** — `a03` in one org is a different object in another.
3. **`Id.valueOf(null)` throws** — guard null separately.
4. **Some managed-package prefixes collide** with standard orgs — always prefer `getSobjectType()` over prefix lookup.
5. **Trigger `oldMap` keys are typed `Id`** — iterating as `String` loses the type info.
6. **`System.StringException` from `(Id) someString`** is the clue that a caller passed garbage; handle it with intent.
7. **`Id` cannot be deserialized from JSON with a typo** — `JSON.deserialize` silently becomes null on invalid strings, not throw.
---
## Output Artifacts
| Artifact | Description |
|---|---|
| `scripts/check_apex_salesforce_id_patterns.py` | Scans for string-prefix Id checks, 15/18 char string compares, and untyped Id parameters |
| `templates/apex-salesforce-id-patterns-template.md` | Work template for validating and typing Id inputs at trust boundaries |
---
## Related Skills
- `apex-user-and-permission-checks` — authorization once an Id has been validated
- `apex-with-user-mode` — enforcing FLS/CRUD on the SOQL that consumes the validated Id
- `apex-bulk-patterns` — when the Id is part of a bulkified collectionRelated Skills
salesforce-shield-deployment
Roll out Shield (Platform Encryption + Event Monitoring + Field Audit Trail) end-to-end, sequencing feature enablement to avoid data lockout. NOT for Classic Encryption or general PE design.
mfa-enforcement-patterns
Design MFA enforcement: auto-enablement, Salesforce Authenticator rollout, exceptions, service accounts, API-only users, SSO interop, and audit. Trigger keywords: MFA, multi-factor, two-factor, Salesforce Authenticator, MFA exception, MFA SSO, api-only MFA. Does NOT cover: end-user password policies, device-trust posture, or non-Salesforce IdP configuration.
ferpa-compliance-in-salesforce
Use this skill when implementing FERPA (Family Educational Rights and Privacy Act) compliance controls in Salesforce Education Cloud or Education Data Architecture (EDA): LearnerProfile FERPA boolean fields, directory information opt-out via FLS and Individual data privacy flags, ContactPointTypeConsent for parental and third-party disclosure, 45-day student records response window tracking, and consent workflow automation. Trigger keywords: FERPA, student records privacy, LearnerProfile, parental disclosure, directory information opt-out, education data privacy, student consent, education cloud compliance. NOT for GDPR/CCPA general data privacy (see gdpr-data-privacy skill), platform encryption at rest (see platform-encryption skill), or HIPAA health-data compliance.
encrypted-field-query-patterns
Design SOQL, filters, reporting, and indexes against Shield Platform Encryption fields. Trigger keywords: Shield Platform Encryption, encrypted field query, probabilistic vs deterministic encryption, encrypted SOQL filter, encrypted field index. Does NOT cover: Classic Encryption (deprecated), field-level security policy, or tenant secret key rotation.
apex-managed-sharing-patterns
Grant row-level access programmatically via __Share records when declarative sharing rules cannot express the policy. NOT for OWD, role hierarchy, or criteria-based sharing rule design.
omnistudio-testing-patterns
Use when testing or validating OmniStudio components — OmniScript preview, Integration Procedure step debugging, DataRaptor field-mapping validation, and end-to-end UTAM-based automation. NOT for Apex unit testing or standard Flow debugging.
omnistudio-error-handling-patterns
Use when designing fault behavior across Integration Procedures, DataRaptors, OmniScripts, and FlexCards — error routing, user-facing messaging, retry semantics, and idempotency. Triggers: 'omnistudio error', 'integration procedure fault', 'dataraptor error handling', 'omniscript retry', 'flexcard action failure'. NOT for general Apex exception design or Flow fault paths.
omnistudio-ci-cd-patterns
Use when designing or implementing CI/CD pipelines for OmniStudio components — DataPack export/import, versioning, environment promotion, and automated deployment. NOT for standard Salesforce metadata CI/CD or Apex-only pipelines.
omniscript-design-patterns
Use when designing or reviewing OmniScripts for guided experiences, step structure, branching, save/resume, and the boundary between OmniScript, Integration Procedures, DataRaptors, and custom LWCs. Triggers: 'omniscript design', 'too many steps in omniscript', 'save and resume omniscript', 'branching in omniscript', 'when should this be an integration procedure'. NOT for deep Integration Procedure or DataRaptor design when the guided interaction layer is not the main concern.
integration-procedure-cacheable-patterns
Use when designing Integration Procedures (IPs) with platform cache to cut latency and callout load. Covers cache key design, TTL selection, per-user vs org-wide partitions, invalidation on data changes, and safe fallback on cache miss/stale. Does NOT cover general IP authoring (see omnistudio-error-handling-patterns) or LWC client-side caching.
industries-cpq-vs-salesforce-cpq
Use this skill when comparing Industries CPQ (formerly Vlocity CPQ) with Salesforce CPQ (Revenue Cloud managed package) — covering feature parity, decision criteria, migration paths, and coexistence patterns. Trigger keywords: Vlocity CPQ, Industries CPQ, Salesforce CPQ comparison, Revenue Cloud migration, CPQ selection, which CPQ to use. NOT for implementing, configuring, or debugging either CPQ product.
flexcard-design-patterns
Use when designing, building, or reviewing OmniStudio FlexCards — including data source selection, card states, actions, conditional visibility, flyout configuration, and child card iteration. Triggers: 'FlexCard', 'card template', 'flyout', 'card action', 'card state', 'data source', 'child card', 'conditional visibility'. NOT for OmniScript design, standalone LWC development, or Apex controller architecture outside the FlexCard context.