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

Dsc Endpoint Help

skill-j-256-claude-code-skills-dsc-endpoint-help · by j-256

Look up a spec field on, or diff a failing request against, one named endpoint in a Salesforce API reference published on developer.salesforce.com ("DSC"). Invoke whenever the user's ask is about what one specific endpoint's spec says or why one specific call doesn't match it – OAuth scopes, query params, request body, response schema, auth scheme, HTTP method/path, or a cURL/HTTP request paired…

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

Install

$ agentstack add skill-j-256-claude-code-skills-dsc-endpoint-help

✓ 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 Used
  • Filesystem access No
  • Shell / process execution Used
  • 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-j-256-claude-code-skills-dsc-endpoint-help)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo 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 Dsc Endpoint Help? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

DSC Endpoint Help

Answer one question about one endpoint in a Salesforce API reference on DSC – either by quoting the relevant spec field, or (when a failing request is attached) by diffing the request against the spec and naming the root cause. Every claim is backed by a public developer.salesforce.com URL the user can forward to a customer.

When to use

Lookup branch (no failing request attached):

  • A direct spec-field question about a named endpoint: "what scopes does shopper-products getProducts need", "which query params does searchOrders take", "what auth scheme guards createOrder".
  • A code-generation ask that references a named endpoint: "write me a node script that calls getProduct" – quote the spec the user can write the code against; don't write the code.
  • A how-to ask that's really a spec-field question in disguise: "how do I paginate search results", "what limit does X accept" – quote the relevant param.

Diff branch (a failing request is attached):

  • A cURL command + an error body: "why is this 403ing", "what's wrong with this request".
  • A request + an insufficient_scope / invalid_client / unauthorized_client envelope, optionally with a JWT to decode for the scope diff.
  • A content-type / body-shape failure: "diff this against the spec", "is this 415 because content-type is wrong".

Inputs from the user

The user's prompt usually contains some of:

  • A reference name ("shopper-products", "orders", "scapi shopper baskets") – maybe abbreviated, maybe product-branded ("SCAPI Shopper Products" → shopper-products).
  • An operation identifier ("getProducts", "createOrder", sometimes partial: "the products get endpoint", "that getCustomer call").
  • A concrete spec-field question (lookup branch): what scopes, what params, what body, what response, what method/path, what auth scheme.
  • A request artifact (diff branch): cURL, raw HTTP, or {method + URL}. Required for the diff branch.
  • An error response (diff branch): {status, body}. Required for the diff branch. Body can be JSON or prose.
  • An access token (JWT) (diff branch, optional): if provided (or embedded in the request's Authorization: Bearer header), the skill decodes the scp claim for a high-confidence scope diff.
  • Registered client scopes (diff branch, optional): if the user has the list from their SLAS/OAuth client config, pass it instead (confidence: medium, with a disclaimer).
  • Reference URL (diff branch): the developer.salesforce.com URL of the reference containing this endpoint. Usually inferrable from the request path (/checkout/shopper-baskets/...https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-baskets). If the path is ambiguous, ask.

Sometimes one of these is missing. See "Disambiguation" below.

Choosing the output shape

The diff branch fires when both of these conditions hold; the lookup branch fires otherwise.

  1. Request artifact present. A cURL command, a raw HTTP request line/block, or a {method, url, body?} shaped paste. Detection cues: curl followed by a URL; HTTP request-line pattern ( HTTP/); an explicit Authorization: / x-dw-client-id: / similar request-shaped header line.
  2. Error artifact present. A 4xx or 5xx status code in proximity to the request artifact (returns 403, 403ing, status: 401); a recognized error body / fault envelope (SCAPI's {"error": "..."} shape, OCAPI's {"fault": {"type": "...", ...}} shape, OAuth's invalid_client / insufficient_scope / unauthorized_client strings); or explicit failure framing tied to the request (why is this failing, what's wrong, diff this against the spec).

If both are present, the prompt is asking "why is this specific call broken" – diff branch (triage.js). If only one or neither is present, the prompt is asking a spec-field question (possibly with failure-themed phrasing) – lookup branch (query.js).

Boundary cases this resolves cleanly

| Input shape | Branch | Why | |---|---|---| | Bare spec-field Q ("what scopes does X need") | lookup | No request, no error | | cURL pasted, no error mentioned | lookup | Request present, but no failure to diff against | | Error body / status alone, no request | lookup | Failure-themed, but nothing to compare against | | cURL + error body together | diff | Both signals present | | getCustomer 403 + JWT decode | diff | cURL implied, JWT-decode is the diff | | createBasket 400 missing_parameter (status only, no body) | lookup-with-nudge | Spec-field framing dominates; brief mention that the 400 likely indicates a required field, paste the body for a real diff | | B2C job webhook silently dropping events (decline) | declined | No endpoint, no request – falls into the decline list |

Cache location

Use ~/.cache/dsc-scrape/ as the cache root. Create it if it doesn't exist (scrape will create subdirs itself). This is shared across projects – scraping once benefits future sessions.

Per-reference layout inside the cache mirrors dsc-scrape's output:

~/.cache/dsc-scrape/
└── /
    ├── _index.json           full slug list + title + siblings
    ├── Summary.json          overview prose (NOT an endpoint)
    ├── .json    one file per endpoint
    └── types/.json one file per named type

Lookup branch flow

  1. Pick reference + slug from the user's question. If either is missing or ambiguous, disambiguate (see below) before running anything.
  2. Always refresh first. Run scrapeRefresh (from lib/scrape-refresh.js) against the reference root before querying. The shared scrape library owns a 1-hour TTL matching DSC's upstream cache-control: max-age=3600, so when the cache is fresh this costs one _index.json read and zero network round-trips. The returned summary has refreshed: true (new data fetched) or refreshed: false (cache already fresh).
  3. Query locally by running scripts/query.js. If it exits 0, you have the data. If exit 3 (slug not found / ambiguous), use the returned candidates to confirm with the user or narrow.
  4. Write the answer in prose, quoting only the field the user asked about, and cite the public DSC URL – the url field in the JSON returned by query.js. Never cite the local cache path in your output. (If the user explicitly asks "where's the local copy?", read the absolute path from query.js's file field on demand; don't volunteer it.)

Step 1: Resolve reference + slug

The user's question may name a reference directly ("shopper-products getProducts"), name it under a brand or rebrand ("SCAPI products" → shopper-products; "Data Cloud" → Data 360), or leave it implicit ("how do I paginate searches" – which search?). Resolve to a concrete / pair before any other step.

Default discovery path: bootstrap via the shared scrape library. When the reference name isn't already concrete in your context, call scrapeRefresh against https://developer.salesforce.com/docs/apis first. This writes ~/.cache/dsc-scrape/_catalog.json listing every product DSC publishes, with each product's referenceUrl, a referenceShape tag (area-landing / reference-root / atlas / static-html / unknown – only the first two are scrapeable), and a searchKeys array (acronyms drawn from the product's landing titles plus hand-curated entries like "SCAPI"). Match the user's hint case-insensitive substring against title, body, AND searchKeys – the third surface is what makes acronyms like "OCI" or "MIAW" resolve cold-cache without relying on the model's training data. Once a product is picked, scrape its referenceUrl (a product-area landing) to get _landing/_.json, which lists every reference in that area with its id, title, and referenceType (rest-oa3 / rest-raml / rest-oa2 are scrapeable; markdown isn't). Read these files to anchor your slug pick to ground truth instead of guessing. Both list-only modes share the 1-hour TTL with reference scrapes – once _catalog.json exists locally, follow-on discovery in this session is free.

Shortcut: skip the catalog scrape only if the reference name is already concrete. If the user explicitly named a Commerce SCAPI reference ("shopper-products", "shopper-baskets", "orders") or one you've already cached this session, you can scrape its reference root directly without going through the catalog. The 1-hour TTL absorbs the cost if you're wrong about cache state.

You can list what's already on disk via node scripts/list.js ~/.cache/dsc-scrape/ to skip a redundant catalog scrape.

Common name drifts to anchor against the catalog/landing:

| User says | Reference slug | |---|---| | "Shopper Products", "SCAPI products", "the products API" | shopper-products | | "Orders API", "SCAPI orders" | orders (merchant-facing, under commerce-api) or shopper-orders (shopper-facing) – different references | | "Customer Groups" | the operations live in customers, not customer-groups | | "Data Cloud X", "Data 360 X" | Data 360 references (Salesforce rebranded) |

The slug is typically the operationId (getProducts, createOrder). Fuzzy matching is built in – query.js will resolve "products" against the index if there's exactly one match.

Step 2: Refresh the cache

Use lib/scrape-refresh.js to warm the cache before every query. The helper owns the subprocess dance, calls into the shared scrape library at lib/scrape/scrape.js, and returns a normalized {refreshed, reference, format, specUrl, files, cacheRoot} object. When the cache is still within its 1-hour TTL, scrapeRefresh returns refreshed: false without fetching – calling it unconditionally is effectively free.

const { scrapeRefresh } = require('./lib/scrape-refresh.js');

const result = await scrapeRefresh({
  referenceUrl: 'https://developer.salesforce.com/docs///references/',
  // scrapeScript defaults to lib/scrape/scrape.js (resolved via require.resolve)
  // cacheRoot defaults to ~/.cache/dsc-scrape
});

Scraping the reference root (no ?meta=) writes the whole reference in one pass – Summary + every endpoint + every type + _index.json. Do this even if the user only asked about one endpoint. The network cost is identical: the scraper downloads a single static spec file that already contains every operation, and writing one slug vs. all of them is just a parse-time decision. Upsides of the whole-reference scrape:

  1. Slug safety – if the user's slug guess was slightly off, _index.json lets you correct it without a second fetch.
  2. Future cache hits – any later question about any other endpoint in this reference is free.
  3. Type resolution works--resolve-refs reads types/.json. Those files only exist if the whole reference was scraped.
  4. TTL is cheap.

Only scrape a single slug (?meta=) if the user explicitly asked for just that one to land on disk.

If the scrape exits 1 with a 404 on a reference root (your shortcut path was wrong – misspelled, rebranded, or not in that product area), fall back to the same cascade Step 1 describes: scrape /docs/apis for _catalog.json, then the product's referenceUrl for _landing/.json, then the corrected reference root. Don't guess variations by re-scraping them one at a time.

A few products have /references/ pages but don't appear in the /docs/apis catalog – if the catalog has no match for a product the user named, lowercase the user's hint and substring-match it against the keys in lib/scrape/aliases.js (the CATALOG_MISSING_ALIASES map) for the area-landing URL. Only ask the user for a DSC URL if neither catalog nor alias map resolves the hint.

If referenceType is anything other than rest-oa3, rest-raml, or rest-oa2 (for example markdown), the reference isn't a machine-readable spec the scrape library can deliver – tell the user and stop.

After a successful scrape, run query.js. If it can't find the slug, read _index.json's slug list – the user's operation name may also be off (e.g. searchCustomerGroups plural vs. searchCustomerGroup singular).

Step 3: Query locally

node /scripts/query.js ~/.cache/dsc-scrape/   [--field ]

Match the question to the right field – this keeps the output small and focused:

| User asks... | Use --field | |---|---| | "what scopes...", "what OAuth...", "which permissions..." | security | | "what params...", "what query params...", "required params..." | parameters | | "what's the request body", "what fields in the POST body" | body – add --resolve-refs | | "what response schema", "what does it return", "what's the 200 response" | responses – add --resolve-refs | | "HTTP method", "path", "endpoint URL" – any of these alone | all (the header is included with every field) | | "show me the whole endpoint" | all or raw if they want the full JSON untouched |

--resolve-refs matters a lot for body and responses questions. Without it you get back schemaRef: "#/components/schemas/Product" and you'd have to read types/Product.json separately (and every type it nests) to get real fields. --resolve-refs inlines the referenced type in one call, so the user's question ("what does it return?") gets a direct answer from a single script run instead of a chain of file reads.

Examples are stripped by default (they can be huge). Pass --include-examples only if the user explicitly wants them.

Step 4: Answer in prose

Lead with the direct answer, then show the evidence (one-line quote of the relevant JSON shape), then the file path. One or two paragraphs for most questions; grouped bullets when there are many related facts (e.g. long parameter list, wide response type).

Freshness preamble: If scrapeRefresh returned refreshed: true and there was a prior cache (i.e. this wasn't a first-ever scrape), open with a single short sentence: "I refreshed the cache first – the upstream spec had changed." Then answer. If refreshed: false, or if this was the first scrape of this reference, skip the preamble and go straight to the answer. You can tell it's a first-ever scrape if _index.json didn't exist before your scrapeRefresh call.

Format guidance – this matters because answers are read in a terminal:

  • Use prose + bullets. Skip markdown tables – they render fine in a rendered preview but look like walls of | characters in the raw terminal most users are actually reading. Bullets degrade gracefully.
  • Use one-line JSON-ish quotes (security: [{ scheme: "X", scopes: [...] }]) for shape, not full pretty-printed blocks. The user can open the cited file if they want the full thing.
  • Group related fields when a type is wide (e.g. a Product response with 45 fields). "Scalars: ..., Pricing: ..., Merchandising: ..." beats an alphabetical dump.
  • No hedging preamble. Don't open with "Based on the cached JSON, I can tell you that..." – just answer.
  • Cite the url field from query.js's structured output at the end, not inline mid-sentence. Never cite the local cache path.

Example: "what scopes does shopper-products getProducts need?"

> getProducts's spec lists sfcc.shopper-products and sfcc.shopper-standard under the ShopperToken scheme – either grants access. sfcc.shopper-standard is a meta-scope that bundles the common shopper feature scopes (including sfcc.shopper-products), so a token with shopper-standard covers getProducts already; see https://developer.salesforce.com/docs/commerce/commerce-api/guide/standard-shopper-scope.html. > > security: [{ scheme: "ShopperToken", scopes: ["sfcc.shopper-products", "sfcc.shopper-standard"] }] > > Source: https://developer.salesforce.com/docs/commerce/commerce-api/references/shopper-products?meta=getProducts

Note on security[] semantics in practice. OAS says all scopes within a single security[] entry are required together (AND); multiple entries in the array are a

Source & license

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

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.