Quickstart
Verify the key, resolve a record, inspect exact context, optionally preflight, and execute one supported write back to ShelfCycle.
This guide assumes you have a ShelfCycle API key. The key is scoped to one tenant and issued to one acting user. Store it locally and read it from the environment at runtime.
Never paste the key into a prompt, chat message, log line, or source control. Give local tooling the environment variable name, not the secret value.
1. Configure the environment
Set the key and base URL in a local .env file.
SHELFCYCLE_API_KEY=sk_...
SHELFCYCLE_API_BASE_URL=https://app.shelfcycle.com/api/v1
For local ShelfCycle development, use:
http://localhost:3000/api/v1
2. Verify the key
Call GET /me before any workflow step. It returns the route major, contract version, org, key preview, scopes, acting user, documentation links, and effective capabilities after live RBAC.
curl "$SHELFCYCLE_API_BASE_URL/me" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Email notes automation"
The response should include apiContractVersion: "v1.35", the compatibility floor, organization base currency, and the organization, actor, scopes, and capabilities your workflow expects. Compare versions numerically and treat a missing patch as zero; a v1.34.1 client is compatible with v1.35. See Authentication for the complete compatibility check.
{
"data": {
"apiVersion": "v1",
"apiContractVersion": "v1.35",
"minimumCompatibleContractVersion": "v1.21",
"org": { "id": "org-id", "name": "Northstar Chemical", "baseCurrencyCode": "USD" },
"key": {
"id": "api-key-id",
"name": "Email notes automation",
"purpose": "Workflow for creating notes from source emails",
"preview": "sk_...abcd",
"scopes": ["company-reference:read", "search:read", "tags:read", "certifications:read", "inventory:read", "reorder:read", "notes:read", "notes:write", "customers:read", "products:read"],
"accessMode": "restricted",
"storedGrants": ["company-reference:read", "search:read", "tags:read", "certifications:read", "inventory:read", "reorder:read", "notes:read", "notes:write", "customers:read", "products:read"],
"effectiveScopes": ["company-reference:read", "search:read", "tags:read", "certifications:read", "inventory:read", "reorder:read", "notes:read", "notes:write", "customers:read", "products:read"],
"retiredScopes": [],
"expiresAt": null
},
"actor": { "type": "user", "id": "user-id", "displayName": "Jordan Buyer" },
"documentation": {
"openapiJsonUrl": "https://app.shelfcycle.com/api/v1/openapi.json",
"llmsTxtUrl": "https://app.shelfcycle.com/llms.txt"
},
"effectiveCapabilities": {
"documentUploads": { "create": false },
"search": { "viewableTypes": ["customer", "contact", "product", "order", "purchase_order", "location"] },
"entityResolution": { "viewableClasses": ["customer", "product", "product_family"] },
"tags": { "vocabulary": true, "viewableEntityTypes": ["customer", "product", "product_family"] },
"productDirectory": { "view": true },
"notes": {
"create": true,
"view": true,
"update": true,
"activityReport": true,
"viewableSubjectTypes": ["customer", "product"]
},
"opportunities": { "view": false, "create": false, "update": false, "close": false, "metaUpsert": false },
"contacts": {
"create": false,
"view": false,
"update": false,
"customer": { "create": false, "view": false, "update": false },
"supplier": { "create": false, "view": false, "update": false }
},
"customers": {
"create": false,
"view": true,
"update": false,
"locations": { "view": true, "create": false, "update": false },
"addresses": { "view": true, "create": false, "update": false },
"documents": { "view": true, "create": false }
},
"suppliers": {
"create": false,
"view": false,
"update": false,
"shipFromLocations": { "view": false, "create": false, "update": false },
"documents": { "view": false, "create": false }
},
"companyReference": { "activeDirectory": true, "customers": true, "suppliers": false },
"products": {
"view": true,
"create": false,
"update": false,
"documents": { "view": true, "create": false },
"sds": { "view": true, "update": false }
},
"productFamilies": { "view": true, "create": false, "update": false },
"costBookEntries": { "view": false, "create": false },
"currentCostSources": { "read": false, "write": false },
"priceBookEntries": { "read": false, "write": false, "writeCurrencyMode": "org_base_only" },
"orders": { "view": false, "changedRecordDiscovery": false },
"purchaseOrders": {
"view": false,
"changedRecordDiscovery": false,
"execution": { "view": false, "currentStateRefresh": false },
"documents": { "view": false, "create": false }
},
"inventory": { "balances": { "view": false, "currentStateRefresh": false } },
"reorder": { "status": { "view": false, "currentStateRefresh": false } },
"certifications": { "view": true, "viewableSubjectTypes": ["customer", "product"] },
"reports": { "available": [] },
"writeReadiness": {
"notes": { "create": true, "update": true },
"opportunities": { "create": false, "update": false, "close": false, "metaUpsert": false },
"contacts": {
"create": false,
"update": false,
"customer": { "create": false, "update": false },
"supplier": { "create": false, "update": false }
},
"customers": {
"create": false,
"update": false,
"locations": { "create": false, "update": false },
"addresses": { "create": false, "update": false },
"documents": { "create": false }
},
"suppliers": {
"create": false,
"update": false,
"shipFromLocations": { "create": false, "update": false },
"documents": { "create": false }
},
"products": {
"create": false,
"update": false,
"documents": { "create": false },
"sds": { "update": false }
},
"productFamilies": { "create": false, "update": false },
"costBookEntries": { "create": false },
"currentCostSources": { "write": false },
"priceBookEntries": { "create": false },
"purchaseOrders": { "documents": { "create": false } }
}
}
}
}
Use the key preview, org name, contract version, and effective capabilities as the wiring check. Never print the full key.
3. Cache active company hints when needed
For inbox triage, intake review, or duplicate checks, use the active reference directory to page safe customer and supplier matching hints into a local cache.
curl "$SHELFCYCLE_API_BASE_URL/reference/customers?limit=250" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Email notes automation"
Reference rows are active-only hints. They are not complete profiles, not archived exports, and not write authorization. If meta.hasMore is true, continue with meta.nextCursor.
4. Resolve the target record
Use GET /entity-resolution when the workflow knows the record class and needs a stable ID. Send the source wording in q and choose customer, supplier, product, product_family, sales_order, or purchase_order as class.
curl "$SHELFCYCLE_API_BASE_URL/entity-resolution?q=Northstar%20Chemical&class=customer" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Email notes automation"
{
"data": {
"classesSearched": ["customer"],
"classResults": [{ "matchedClass": "customer", "totalMatches": 1 }],
"candidates": [
{
"entityId": "customer-id",
"displayName": "Northstar Chemical",
"matchedClass": "customer",
"matchRank": "exact",
"matchBasis": "canonical",
"matchedValue": "Northstar Chemical"
}
],
"archivedRecordsExcluded": true,
"selectionStatus": "auto_selected",
"selectedCandidate": { "entityId": "customer-id", "matchedClass": "customer" }
},
"meta": {
"capabilityKey": "resolve_entity",
"capabilityVersion": "1.1.0"
}
}
Use selectedCandidate.entityId when selectionStatus is auto_selected. If the response is needs_clarification, use the candidate names and match evidence to narrow the choice. Keep a no_match result unresolved rather than guessing. See Entity Resolution for all classes and response fields.
Existing connections can continue using GET /search for broader discovery across several resource types, including contacts and locations. For new record binding, use Entity Resolution, Tags, Product Directory, or a typed finder for the job at hand.
If a request needs repair, validation errors can include a machine-readable next step. Use fields such as repairCategory, suggestedAction, validValues, acceptedFilters, requiredCombination, repairContext, documentationPath, and example to change the request once before retrying.
{
"error": {
"type": "validation_error",
"code": "validation_failed",
"message": "Request validation failed.",
"param": "class",
"suggestedAction": "choose_valid_value",
"repairCategory": "invalid_enum",
"validValues": { "class": ["customer", "supplier", "product", "product_family", "sales_order", "purchase_order"] },
"documentationPath": "/api/v1/openapi.json",
"doNotRetrySameRequest": true,
"requestId": "request-id"
}
}
5. Hydrate exact context
After selecting a resource, fetch the exact detail, child list, attached document list, or order document endpoint when the workflow needs more context.
curl "$SHELFCYCLE_API_BASE_URL/customers/customer-id" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY"
For typed lookup before detail, use finder endpoints such as GET /customers?q=Northstar, GET /products?code=ACETONE-PAIL, GET /orders?orderNo=SO-10042, or GET /purchase-orders?orderNo=PO-4812. Company and product finders require a supported narrowing predicate. Order finders accept exact identifiers, status, customer or supplier, products, related orders, business dates, and last-updated ranges. Exact order-number, customer-order-number, and external-id filters accept as many as 25 comma-separated values where documented.
For recently changed sales and purchase orders, send paired changedFrom and changedTo timestamps. Continue larger finder results with meta.nextCursor, then fetch exact documents by id. Order detail returns 100 lines by default, accepts as many as 500, and continues with lineCoverage.nextLineCursor by itself.
For open purchasing workflows, use GET /purchase-order-execution to review current purchase lines, expected and received quantities, and receipt progress. Use executionChangedAt to identify newer operational activity, follow receiptEventsUrl for exact receipt history, and follow documentsUrl for purchase-order files. Periodically restart the original query to refresh the complete current view. See the Purchase execution guide for filters, continuation, and document examples.
After selecting a customer or supplier, use parent-scoped child endpoints when the workflow needs exact locations or addresses: GET /customers/{id}/locations, GET /customers/{id}/locations/{locationId}/addresses, or GET /suppliers/{id}/ship-from-locations.
For product intake, resolve setup references before product writes: GET /product-families, GET /product-families/{id}, and GET /reference/product-packaging.
When the workflow starts from an organization tag, use GET /tags to browse the vocabulary and GET /tagged-records to find authorized customers, suppliers, products, or product families carrying one exact tag. See the Tags guide for filters and continuation.
When the workflow starts from a UN/NA number, CAS number, hazard class, packing group, or product name, use GET /product-directory to find the matching product and family population. See the Product Directory guide before selecting a detail endpoint.
For customer, supplier, product, or purchase-order source files, use POST /document-uploads, send the file with the returned upload values, then attach data.document through the exact parent route. A successful uploaded-file attachment returns a durable data.integrity receipt, and an exact retry returns the same stored receipt. Product workflows can assign an uploaded PDF or image as the current SDS with PUT /products/{id}/sds. See the Attached documents guide for the complete flow.
For opportunity workflows, use GET /opportunities to find visible customer- and supplier-side opportunities by status, owner, product, relationship, created date, or matching text. Fetch GET /opportunities/{id} before an update, then use the latest updatedAt value for If-Match. See the Opportunities guide for create, update, close, and metadata examples.
For report workflows, call GET /reports before running a report. Use allowedForThisKey and effectiveCapabilities.reports.available to choose report keys the current key and actor can run. Customer AR Intelligence adds final-settlement behavior, current credit exposure, and matched invoice charges to the existing receivables aging view. The Reports guide covers these views alongside sales, purchasing, open-order, and pipeline reporting.
For organization-wide note review, use GET /note-activity to count notes by day, type, author, or subject, or to browse the newest matching excerpts. See the Note activity guide for date windows, filters, and continuation.
For product cost workflows, use GET /cost-book-entries to read current Cost Book truth or exact product, supplier, and ship-from history. Read GET /products/{id}/current-cost-source when the workflow needs the product's fixed or selected supplier origin. Use GET /products/{id}/cost-context to follow that source, or include supplierId for one explicit supplier. See the Cost Book guide before changing Current Source or creating an entry.
For current physical stock, use GET /inventory-balances to review on-hand, allocated, available, and quarantined-on-hand quantities by product and warehouse. Keep each row's quantity basis with its values, and see the Inventory balances guide for filtering and refresh guidance.
For stock-out questions, use the inventory response's complete census instead of counting the current page. For configured thresholds, use GET /reorder-status to review current stock, allocated and committed demand, projected availability, projected deficit, and status. See the Reorder status guide.
For certification questions, use GET /certification-types to learn the organization's vocabulary, GET /certification-records for stored records, and GET /certification-subjects for the authorized customers, suppliers, products, or customer addresses with matching records. See Certification Intelligence.
For customer and list pricing workflows, use GET /price-book-entries to review active, scheduled, expired, or historical configured prices with exact package and base-unit context. See the Price Book guide before previewing and applying a single-price update.
6. Preflight the note write
For supported POST, PATCH, and PUT writes, add dryRun=true to the same endpoint before execution when your workflow wants a readiness check. The dry run does not write. It uses the same scope, live permission, and rate-limit family as execution.
curl "$SHELFCYCLE_API_BASE_URL/notes?dryRun=true" \
-X POST \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: gmail-thread-123:customer-id:create-note" \
-d '{
"primarySubject": { "type": "customer", "id": "customer-id" },
"linkedRecords": [
{ "type": "contact", "id": "contact-id" },
{ "type": "product", "id": "product-id" }
],
"noteType": "EMAIL",
"title": "Inbound product thread",
"body": "Jordan asked for follow-up on acetone availability.",
"happenedAt": "2026-05-28T16:00:00.000Z"
}'
{
"data": {
"type": "write_readiness",
"operation": "notes.create",
"status": "ready",
"wouldWrite": false,
"checks": [
{ "code": "scope_authorized", "status": "passed", "message": "The key can create notes." },
{ "code": "target_available", "status": "passed", "message": "The subject is visible." },
{ "code": "idempotency_available", "status": "passed", "message": "The idempotency key is available." }
],
"duplicateCandidates": [],
"submit": { "method": "POST", "path": "/api/v1/notes", "query": {} },
"verification": {
"available": true,
"method": "GET",
"path": null,
"pathTemplate": "/api/v1/notes/{id}",
"requiresScopes": ["notes:read"],
"fallback": "detail_get"
},
"requestId": "request-id"
}
}
status: "blocked" can still return HTTP 200. Inspect checks and duplicateCandidates before deciding whether your policy allows execution.
7. Execute the note write
Remove dryRun=true when your workflow's policy allows execution. Send a stable Idempotency-Key built from source facts, not a random value.
curl "$SHELFCYCLE_API_BASE_URL/notes" \
-X POST \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: gmail-thread-123:customer-id:create-note" \
-d '{
"primarySubject": { "type": "customer", "id": "customer-id" },
"linkedRecords": [
{ "type": "contact", "id": "contact-id" },
{ "type": "product", "id": "product-id" }
],
"noteType": "EMAIL",
"title": "Inbound product thread",
"body": "Jordan asked for follow-up on acetone availability.",
"happenedAt": "2026-05-28T16:00:00.000Z"
}'
{
"data": {
"id": "note-id",
"type": "note",
"url": "https://app.shelfcycle.com/org-northstar/notes/note-id",
"createdAt": "2026-05-29T14:35:00.000Z",
"updatedAt": "2026-05-29T14:35:00.000Z",
"createdBy": { "type": "user", "id": "user-id", "displayName": "Jordan Buyer" },
"idempotencyStatus": "created"
}
}
Use the returned url or the readiness response's verification guidance for readback. If detail verification is not available for the key, treat the execute response as the readback.
Do not generate a random idempotency key for each retry. The same source event must reuse the same key. The same key with a different body returns 409 idempotency_key_reused.
8. Build with the v1.35 capabilities
v1.35 adds Customer AR Intelligence for reviewing final-settlement behavior, ranking current exposure across posted receivables and uninvoiced commitments, and tracing matched invoice charges and credits. It also includes configured reorder status, exact stock-out counts, Certification Intelligence, tag and product directories, Entity Resolution, Current Source selection, inventory balances, purchase execution and receipt history, opportunity management and pipeline summaries, receivables aging, Price Book reads and updates, order discovery, document workflows, note activity, reports, product and company setup, and readiness-aware writes.
Choose the narrowest endpoint for the job, verify effective capabilities through GET /me, and use the live OpenAPI reference for exact request and response shapes.