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.20" and the tenant, actor, scopes, and capabilities your workflow expects.
{
"data": {
"apiVersion": "v1",
"apiContractVersion": "v1.20",
"org": { "id": "org-id", "name": "Northstar Chemical" },
"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", "notes:read", "notes:write", "customers:read"],
"accessMode": "restricted",
"storedGrants": ["company-reference:read", "search:read", "notes:read", "notes:write", "customers:read"],
"effectiveScopes": ["company-reference:read", "search:read", "notes:read", "notes:write", "customers: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": {
"search": { "viewableTypes": ["customer", "contact", "product", "order", "purchase_order", "location"] },
"notes": { "create": true, "view": true, "update": true, "viewableSubjectTypes": ["customer", "product"] },
"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 } },
"productFamilies": { "view": true, "create": false, "update": false },
"orders": { "view": false, "changedRecordDiscovery": false, "commercialEconomics": false },
"purchaseOrders": { "view": false, "changedRecordDiscovery": false, "commercialEconomics": false },
"reports": { "available": [] },
"writeReadiness": {
"notes": { "create": true, "update": true },
"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 } },
"productFamilies": { "create": false, "update": 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 /search for ambiguous cross-resource resolution. It takes a required q, an optional comma-separated types list, and an optional limit from 1 to 20.
curl "$SHELFCYCLE_API_BASE_URL/search?q=Northstar&types=customer,contact,purchase_order&limit=10" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Email notes automation"
{
"data": [
{
"type": "contact",
"id": "contact-id",
"displayName": "Jordan Buyer",
"subtitle": "Northstar Chemical · jordan@example.com · President",
"url": "https://app.shelfcycle.com/org-northstar/customers/customer-id/contacts",
"archived": false,
"matchedFields": [
{ "field": "email", "label": "Email", "value": "jordan@example.com" },
{ "field": "parent.name", "label": "Customer", "value": "Northstar Chemical" }
],
"parent": { "type": "customer", "id": "customer-id", "displayName": "Northstar Chemical" }
}
],
"meta": {
"requestId": "request-id",
"limit": 10,
"types": ["customer", "contact", "purchase_order"],
"rankingIsContractual": false,
"truncated": false,
"durationMs": 24
}
}
Use the matched fields and selected {type,id} to support your workflow's target-selection policy. If meta.truncated is true, narrow the query first.
If a request needs repair, v1.20 validation errors can include a machine-readable next step. Use fields such as repairCategory, suggestedAction, validValues, acceptedFilters, requiredCombination, documentationPath, and example to change the request once before retrying.
{
"error": {
"type": "validation_error",
"code": "validation_failed",
"message": "Request validation failed.",
"param": "type",
"suggestedAction": "replace_param",
"repairCategory": "unknown_param",
"validValues": { "types": ["customer", "supplier", "contact", "product", "order", "purchase_order", "location"] },
"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. Finders require narrowing predicates and are not sync/export lists.
Sales-order and purchase-order finders also support paired updatedAtFrom and updatedAtTo windows for parent-row changed-record discovery. Use those windows to discover recently changed order records, then fetch exact documents by id.
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.
For customer, supplier, or product source files, use the parent-scoped attached document routes after selecting the exact record: GET /customers/{id}/documents, GET /suppliers/{id}/documents, or GET /products/{id}/documents. Product document responses can also include the product SDS pointer when one is available.
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.
6. Preflight the note write
For supported POST and PATCH 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. Stay inside v1.20 boundaries
v1.20 supports active customer/supplier reference directory paging, search, narrowed finders, governed report rollups with flexible period comparisons, product setup references, safe detail reads, subject-scoped note reads, parent-scoped contact and child-location reads, parent-scoped attached document reads and link creates, optional write-readiness checks, note/contact writes, bounded customer/supplier profile writes, parent-scoped customer location/address and supplier ship-from writes, bounded product and product-family writes, read-only sales/purchase order documents, scope-gated profit, margin, and cost details, and repair-aware validation responses.
It does not create packaging or suppliers from product setup, upload binary files, delete documents, update orders, update purchase orders, export report source rows, mutate inventory, pricing, costs, receiving, invoices, bills, payments, AP, AR, GL, margin, or accounting records.