# BatchPath Specification

**Version:** 0.1 (Working Draft)  
**Date:** 2026-04-11  
**Status:** Draft — breaking changes allowed until v1.0

---

## Abstract

BatchPath is an open chain-of-custody standard for tattoo supplies (inks, needles, cartridges). It defines how manufacturers, distributors, studios, and clients exchange traceability data across the supply chain.

The standard is vendor-neutral and implementation-agnostic. Any organization can publish or consume BatchPath events. This spec is based on the cannabis seed-to-sale model (Metrc) adapted for the tattoo industry.

**Versioning Policy:** Semantic versioning. v0.1 is a working draft. Breaking changes are allowed until v1.0 stable release.

---

## Entities

### Manufacturer
Producer of a physical supply item (ink, needle, cartridge). Identified by `manufacturer_id`. Publishes lot data and receives/broadcasts recalls.

### Lot
Manufacturing batch of a supply item.

**Fields:**
- `lot_id` — unique identifier (e.g., `INK-2024-Q1-001`)
- `manufacturer_id` — producer identifier
- `product` — supply type (e.g., "Black Ink", "Round Liner", "Cartridge Liner")
- `produced_at` — ISO 8601 timestamp
- `expires_at` — ISO 8601 timestamp
- `quantity` — units in batch (e.g., 100 bottles)
- `metadata` — optional JSON (ingredients, batch notes, certifications)

### Distributor
Wholesaler handling transfers from manufacturers to studios. Identified by `distributor_id`. Logs receipts and transfers.

### Studio
End-user of supplies. Identified by `studio_id`. Logs sessions that consume lots.

### Artist
Operator inside a studio who performs the tattoo. Identified by `artist_id`.

### Client
Tattoo recipient (de-identified in public spec). Identified by `client_hash` — a one-way hash of PII (e.g., SHA256 of email + phone).

### Session
Tattoo appointment. Identified by `session_id`. Links studio, artist, one or more lots, and a client.

**Fields:**
- `session_id` — unique identifier
- `studio_id` — originating studio
- `artist_id` — artist who performed it
- `client_hash` — de-identified client
- `session_date` — ISO 8601 date
- `lots_used` — array of `lot_id`s consumed in this session

### Consent Form
Client-signed record linking session to lots used. Closes the chain of custody.

**Fields:**
- `consent_id` — unique identifier
- `session_id` — reference to session
- `client_signature` — signed consent (offline or digital)
- `timestamp` — when signed
- `acknowledged_lots` — client confirms knowledge of lots used

---

## Event Types

All events are append-only, forming an immutable chain. Each event includes:
- `event_id` — unique identifier
- `event_type` — type below
- `timestamp` — ISO 8601 UTC
- `actor_id` — entity initiating the event (manufacturer, distributor, studio)
- `subject_lot_id` — lot being referenced
- `payload` — event-specific data (JSON)
- `prev_event_hash` — SHA256 hash of previous event (Merkle-style chain)

### lot.created
Manufacturer creates a new lot.

**Payload:**
```json
{
  "lot_id": "INK-2024-Q1-001",
  "manufacturer_id": "mfg_123",
  "product": "Black Ink",
  "produced_at": "2024-01-15T10:00:00Z",
  "expires_at": "2026-01-15T23:59:59Z",
  "quantity": 100,
  "metadata": {}
}
```

### lot.shipped
Manufacturer ships a lot to a distributor.

**Payload:**
```json
{
  "lot_id": "INK-2024-Q1-001",
  "distributor_id": "dist_456",
  "shipped_at": "2024-01-16T14:00:00Z",
  "tracking_number": "TRACK123"
}
```

### lot.received
Distributor receives and logs a lot.

**Payload:**
```json
{
  "lot_id": "INK-2024-Q1-001",
  "distributor_id": "dist_456",
  "received_at": "2024-01-18T09:30:00Z",
  "quantity_verified": 100,
  "notes": "Received in good condition"
}
```

### lot.transferred
Distributor transfers a lot to a studio.

**Payload:**
```json
{
  "lot_id": "INK-2024-Q1-001",
  "distributor_id": "dist_456",
  "studio_id": "studio_789",
  "transferred_at": "2024-01-20T11:00:00Z",
  "quantity": 50
}
```

### session.logged
Studio logs a session consuming one or more lots.

**Payload:**
```json
{
  "session_id": "sess_001",
  "studio_id": "studio_789",
  "artist_id": "artist_abc",
  "client_hash": "sha256(email+phone)",
  "session_date": "2024-02-01",
  "lots_used": ["INK-2024-Q1-001", "LINER-2024-Q1-005"],
  "notes": "Color work, two lots used"
}
```

### consent.signed
Client signs consent form linking session to lots. **Closes the chain.**

**Payload:**
```json
{
  "consent_id": "cons_001",
  "session_id": "sess_001",
  "client_signature": "digital_signature_or_acknowledgment",
  "acknowledged_lots": ["INK-2024-Q1-001", "LINER-2024-Q1-005"],
  "timestamp": "2024-02-01T15:30:00Z"
}
```

### lot.recalled
Manufacturer broadcasts a recall for a lot (e.g., contamination, safety issue).

**Payload:**
```json
{
  "lot_id": "INK-2024-Q1-001",
  "manufacturer_id": "mfg_123",
  "recall_reason": "Microbial contamination detected",
  "recall_severity": "critical",
  "recommended_action": "Cease use, isolate, contact studio clients",
  "recall_timestamp": "2024-03-10T09:00:00Z"
}
```

---

## Event Schema (JSON)

```json
{
  "event_id": "evt_abc123",
  "event_type": "lot.created",
  "timestamp": "2024-01-15T10:00:00Z",
  "actor_id": "mfg_123",
  "subject_lot_id": "INK-2024-Q1-001",
  "payload": { /* event-specific data */ },
  "prev_event_hash": "sha256(previous_event_json)"
}
```

---

## Recall Query Patterns

Three canonical queries systems MUST support:

### Query 1: Recall → Affected Sessions & Clients
**Input:** `lot_id` (recalled lot)  
**Output:** List of `session_id`s and corresponding `client_hash`es that consumed this lot.

```
given recalled_lot_id
find all session.logged events where lots_used contains recalled_lot_id
return { session_ids, client_hashes }
```

Use case: Manufacturer broadcasts recall → distributor/studio runs this query to identify affected clients.

### Query 2: Session → Upstream Lots & Manufacturers
**Input:** `session_id`  
**Output:** List of `lot_id`s and `manufacturer_id`s used in this session.

```
given session_id
find session.logged event matching this session_id
return lots_used array + map each lot_id to its manufacturer_id
```

Use case: Studio receives recall notice → run this query to see all manufacturers for a given client session.

### Query 3: Distributor Inventory
**Input:** `distributor_id`  
**Output:** Current active lots held by distributor.

```
given distributor_id
find all lot.transferred events TO this distributor
subtract lot.transferred events FROM this distributor (outgoing)
return { active_lot_ids, quantities }
```

Use case: Distributor dashboard shows current inventory; used for one-click recall notifications.

---

## Compliance Alignment

### EU REACH (Active)
Article 33 requires manufacturers to provide substance information to downstream recipients. BatchPath events (`lot.created` with `metadata`) satisfy this by embedding substance data in the lot payload.

### FDA MoCRA (Anticipated)
Modernization of Cosmetics Regulation is moving toward mandatory supply chain traceability for cosmetics, including tattoo ink. BatchPath's event model aligns with expected FDA requirements.

### Cannabis Precedent
Metrc (cannabis seed-to-sale) is the operational precedent. Same data model, adapted for tattoo supplies and regulatory drivers.

---

## Implementation Notes

### API Design
Suggested REST endpoint for event submission:

```
POST /v1/events
Content-Type: application/json
X-Signature: HMAC-SHA256(body, secret_key)

{
  "event_id": "evt_abc123",
  "event_type": "lot.created",
  ...
}
```

Response: `201 Created` with event hash.

### Webhook-Friendly
Any form tool (GHL, Typeform, etc.) can POST events to a `/v1/events` endpoint. No SDK required. Standard JSON.

### No Proprietary Lock-In
Entities exchange events via standard HTTP + JSON. Query the chain via REST API or direct database access. Vendor-agnostic.

### Client De-Identification
`client_hash` is a one-way SHA256 hash of PII (e.g., `sha256(email + phone + studio_id)`). Allows downstream traceability without exposing personal data in the public chain.

---

## Versioning

- **v0.1** — Working draft. Breaking changes allowed.
- **v0.5** — Beta. Soliciting feedback from manufacturers and distributors.
- **v1.0** — Stable release. Backwards-compatible changes only.

Changes will be tracked in a `CHANGELOG.md` and published as new spec versions at `spec.batchpath.com/v{N}`.

---

## Next Steps

1. **Manufacturer pilot** — identify 1–2 ink manufacturers willing to publish lot data
2. **Distributor pilot** — Needlejig or Coalition adopts BatchPath API
3. **Studio pilot** — GHL consent form integration emits `consent.signed` events
4. **Recall drill** — test end-to-end recall notification workflow
5. **v0.5 feedback round** — gather input, publish 0.5 release
6. **v1.0 stable** — finalize spec, submit to industry bodies (if appropriate)
