API Reference
PBCP
Story API

Story API

Identity Resolution และ Story Composition — แปลง Business Context ให้กลายเป็น Story Projection ที่ Pulse และ consumer apps ใช้ render timeline

Base: https://pbcp-api.pcampus.co

Story API คืน business meaning — Context API คืน platform state ใช้ Story API สำหรับ Pulse, demos, และ end-user surfaces ทั้งหมด


GET /v1/story/resolve?q={input}

Identity Resolution — รับ input อะไรก็ได้ (phone, email, order ID, product name) แล้วคืน entity candidates ที่ตรงกัน

Headers: x-tenant-id (required)

Query params

ParamRequiredDescription
qYesCustomer ID, phone, email, order ID, product ID/SKU, product name

Response 200 — single match

{
  "query": "0812345678",
  "candidates": [
    {
      "entityType": "customer",
      "entityId": "ent_abc123",
      "label": "Somchai Jai-dee",
      "confidence": 1,
      "hint": "phone:exact"
    }
  ]
}

Response 200 — multiple matches

{
  "query": "Vitamin C",
  "candidates": [
    {
      "entityType": "product",
      "entityId": "P-101",
      "label": "Blackmores Vitamin C",
      "confidence": 0.88,
      "matchReason": "product_name"
    },
    {
      "entityType": "product",
      "entityId": "P-102",
      "label": "Vistra Vitamin C",
      "confidence": 0.88,
      "matchReason": "product_name"
    }
  ]
}

หลังได้ candidates → เลือก 1 candidate → เรียก GET /v1/story/{entityType}/{entityId}

Errors

StatusCodeWhen
400VALIDATION_ERROREmpty q
404NOT_FOUNDNo evidence in tenant (business-safe message)

GET /v1/story/{entityType}/{entityId}

Story Composition — compose และคืน Story Projection สำหรับ entity

Supported entityType: customer | order | product | session

Headers: x-tenant-id (required)

Response 200

{
  "entityType": "customer",
  "entityId": "ent_abc123",
  "label": "Somchai Jai-dee",
  "metadata": {
    "composedAt": "2026-06-28T10:30:00.000Z",
    "completeness": "full",
    "evidenceCount": 14
  },
  "timeline": [
    {
      "stepId": "step_001",
      "eventName": "customer.registered",
      "occurredAt": "2026-01-15T08:00:00.000Z",
      "label": "ลงทะเบียนเป็นลูกค้า",
      "payload": { "channel": "line_oa" }
    },
    {
      "stepId": "step_002",
      "eventName": "order.completed",
      "occurredAt": "2026-03-10T11:30:00.000Z",
      "label": "ซื้อสินค้า ฿1,200",
      "payload": { "orderId": "ORD-001", "total": 1200 }
    }
  ],
  "insights": [],
  "recommendations": []
}
💡

insights และ recommendations จะมีข้อมูลเมื่อ Intelligence layer enrich — Core คืน [] เสมอ ดู Intelligence API สำหรับ enriched story

Response 200 — partial completeness

เมื่อมี evidence บางส่วนแต่ไม่ครบ:

{
  "entityType": "customer",
  "entityId": "ent_abc123",
  "metadata": {
    "completeness": "partial",
    "missingTypes": ["payment_context"]
  },
  "timeline": [...]
}

Missing evidence ไม่ทำให้ error — คืน 200 พร้อม completeness: "partial"

Errors

StatusCodeWhen
400VALIDATION_ERRORMissing x-tenant-id or unsupported entityType
404NOT_FOUNDNo evidence for entity in tenant
500INTERNALStory composition failed

Usage pattern (Pulse)

// 1. User searches in Pulse search bar
const { candidates } = await pbcp.story.resolve({ q: '0812345678' })
 
// 2. Pick top candidate
const { entityType, entityId } = candidates[0]
 
// 3. Compose story for entity
const story = await pbcp.story.compose(entityType, entityId)
 
// 4. Render StoryTimeline component
<StoryTimeline steps={story.timeline} />

Examples

# Resolve by phone
curl -s 'https://pbcp-api.pcampus.co/v1/story/resolve?q=0812345678' \
  -H 'x-tenant-id: pharmacy-demo'
 
# Compose customer story
curl -s 'https://pbcp-api.pcampus.co/v1/story/customer/ent_abc123' \
  -H 'x-tenant-id: pharmacy-demo'
 
# Compose order story
curl -s 'https://pbcp-api.pcampus.co/v1/story/order/ent_ord1001' \
  -H 'x-tenant-id: pharmacy-demo'

Story API

Identity Resolution and Story Composition — transforms Business Context into Story Projections that Pulse and consumer apps use to render timelines.

Base: https://pbcp-api.pcampus.co

Story API returns business meaning — Context API returns platform state. Use Story API for Pulse, demos, and all end-user surfaces.


GET /v1/story/resolve?q={input}

Identity Resolution — accepts any input (phone, email, order ID, product name) and returns matching entity candidates.

Headers: x-tenant-id (required)

Query params

ParamRequiredDescription
qYesCustomer ID, phone, email, order ID, product ID/SKU, product name

Response 200 — single match

{
  "query": "0812345678",
  "candidates": [
    {
      "entityType": "customer",
      "entityId": "ent_abc123",
      "label": "Somchai Jai-dee",
      "confidence": 1,
      "hint": "phone:exact"
    }
  ]
}

Response 200 — multiple matches

{
  "query": "Vitamin C",
  "candidates": [
    {
      "entityType": "product",
      "entityId": "P-101",
      "label": "Blackmores Vitamin C",
      "confidence": 0.88,
      "matchReason": "product_name"
    },
    {
      "entityType": "product",
      "entityId": "P-102",
      "label": "Vistra Vitamin C",
      "confidence": 0.88,
      "matchReason": "product_name"
    }
  ]
}

After receiving candidates → select 1 candidate → call GET /v1/story/{entityType}/{entityId}

Errors

StatusCodeWhen
400VALIDATION_ERROREmpty q
404NOT_FOUNDNo evidence in tenant (business-safe message)

GET /v1/story/{entityType}/{entityId}

Story Composition — compose and return a Story Projection for an entity.

Supported entityType: customer | order | product | session

Headers: x-tenant-id (required)

Response 200

{
  "entityType": "customer",
  "entityId": "ent_abc123",
  "label": "Somchai Jai-dee",
  "metadata": {
    "composedAt": "2026-06-28T10:30:00.000Z",
    "completeness": "full",
    "evidenceCount": 14
  },
  "timeline": [
    {
      "stepId": "step_001",
      "eventName": "customer.registered",
      "occurredAt": "2026-01-15T08:00:00.000Z",
      "label": "ลงทะเบียนเป็นลูกค้า",
      "payload": { "channel": "line_oa" }
    },
    {
      "stepId": "step_002",
      "eventName": "order.completed",
      "occurredAt": "2026-03-10T11:30:00.000Z",
      "label": "ซื้อสินค้า ฿1,200",
      "payload": { "orderId": "ORD-001", "total": 1200 }
    }
  ],
  "insights": [],
  "recommendations": []
}
💡

insights and recommendations are populated when the Intelligence layer enriches — Core always returns []. See Intelligence API for enriched stories.

Response 200 — partial completeness

When partial evidence exists but is incomplete:

{
  "entityType": "customer",
  "entityId": "ent_abc123",
  "metadata": {
    "completeness": "partial",
    "missingTypes": ["payment_context"]
  },
  "timeline": [...]
}

Missing evidence does not cause an error — returns 200 with completeness: "partial".

Errors

StatusCodeWhen
400VALIDATION_ERRORMissing x-tenant-id or unsupported entityType
404NOT_FOUNDNo evidence for entity in tenant
500INTERNALStory composition failed

Usage pattern (Pulse)

// 1. User searches in Pulse search bar
const { candidates } = await pbcp.story.resolve({ q: '0812345678' })
 
// 2. Pick top candidate
const { entityType, entityId } = candidates[0]
 
// 3. Compose story for entity
const story = await pbcp.story.compose(entityType, entityId)
 
// 4. Render StoryTimeline component
<StoryTimeline steps={story.timeline} />

Examples

# Resolve by phone
curl -s 'https://pbcp-api.pcampus.co/v1/story/resolve?q=0812345678' \
  -H 'x-tenant-id: pharmacy-demo'
 
# Compose customer story
curl -s 'https://pbcp-api.pcampus.co/v1/story/customer/ent_abc123' \
  -H 'x-tenant-id: pharmacy-demo'
 
# Compose order story
curl -s 'https://pbcp-api.pcampus.co/v1/story/order/ent_ord1001' \
  -H 'x-tenant-id: pharmacy-demo'