# Notes

List, read, create, and update notes for a selected record.

Canonical HTML: https://developer.shelfcycle.com/guides/notes

List, read, create, and update notes on confirmed customers, suppliers, and products.

Use this guide after selecting one customer, supplier, or product. For complete counts, rankings, and recent excerpts across notes, use the [Note activity guide](/guides/note-activity).

## List subject notes

```text
GET /notes
```

Required scope:

```text
notes:read
```

`GET /notes` requires a visible subject and returns metadata only. It is not a global note search.

```bash
curl "$SHELFCYCLE_API_BASE_URL/notes?primarySubjectType=customer&primarySubjectId=customer-id&limit=10" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"
```

Add `happenedAtFrom` and `happenedAtTo` to narrow the selected subject's notes by organization-calendar day. Add `noteType` to narrow the list to one supported type.

```bash
curl "$SHELFCYCLE_API_BASE_URL/notes?primarySubjectType=customer&primarySubjectId=customer-id&happenedAtFrom=2026-07-13&happenedAtTo=2026-07-19&noteType=EMAIL&limit=10" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"
```

Fetch the body only after selecting one visible note with `GET /notes/{id}`.

## Create a note

```text
POST /notes
```

Required scope:

```text
notes:write
```

Required header:

```text
Idempotency-Key: <stable-key>
```

Add `dryRun=true` to check the exact intended note write without mutating records.

Use `externalId` for the source note's stable identity. Keep it separate from the `Idempotency-Key` used for safe retries.

`primarySubject` can be `customer`, `supplier`, or `product`.

`linkedRecords` can be `customer`, `supplier`, `product`, `contact`, or `location`. ShelfCycle renders those records as mention and backlink rows and dedupes them with the primary subject.

Supported `noteType` values:

```text
NOTE, EMAIL, PHONE_MEETING, VIRTUAL_MEETING, PHYSICAL_MEETING, SAMPLE_REQUEST, OPPORTUNITY, QUOTE
```

## Request

```bash
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" },
      { "type": "supplier", "id": "supplier-id" }
    ],
    "noteType": "EMAIL",
    "title": "Inbound product thread",
    "body": "Jordan asked for follow-up on acetone availability.",
    "happenedAt": "2026-05-28T16:00:00.000Z",
    "externalId": "GMAIL-MESSAGE-7781"
  }'
```

## Response

```json
{
  "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",
    "externalId": "GMAIL-MESSAGE-7781",
    "createdBy": { "type": "user", "id": "user-id", "displayName": "Jordan Buyer" },
    "createdVia": { "type": "public_api", "actorUserId": "user-id" },
    "requestedVia": { "type": "api_key", "id": "api-key-id", "purpose": "Workflow for creating notes from source emails" },
    "idempotencyStatus": "created"
  }
}
```

Repeating the same route plus `Idempotency-Key` with the same request body in the same org returns the existing note with `idempotencyStatus: "replayed"` and does not mutate the existing note.

## Read a note

```text
GET /notes/{id}
```

Required scope:

```text
notes:read
```

For v1 compatibility, `notes:write` can read API-created notes. The response includes the latest `updatedAt` value to use as `If-Match` for updates.

## Update a note

```text
PATCH /notes/{id}
```

Required scope:

```text
notes:write
```

Required header:

```text
If-Match: <updatedAt from latest GET /notes/{id}>
```

Sparse patch fields:

```json
{
  "title": "Updated title",
  "body": "Updated note body.",
  "happenedAt": "2026-05-28T18:00:00.000Z",
  "noteType": "PHONE_MEETING",
  "externalId": "GMAIL-MESSAGE-7781",
  "linkedRecords": [
    { "type": "customer", "id": "customer-id" },
    { "type": "contact", "id": "contact-id" }
  ]
}
```

PATCH only updates notes created through the public API for the same organization. It can maintain `externalId` but cannot change the primary subject, creator, idempotency identity, archive state, or deletion state.

> **Warning**: Use customer, supplier, or product records as note subjects and links. Order context can be included in the note body.
