# Nyxzie DaemonX Documentation

Bundle scope: core

## Table of Contents

- [Core API Overview](#overview)
- [List Counters](#01-get-api-v1-daemonx-counters)
- [Create Pairing Session](#02a-post-api-v1-daemonx-onboarding-sessions)
- [Check Pairing Session](#02b-get-api-v1-daemonx-onboarding-sessions-id)
- [Cancel Pairing Session](#02c-post-api-v1-daemonx-onboarding-sessions-cancel)
- [Replay Pairing Webhook](#02d-post-api-v1-daemonx-onboarding-sessions-webhook-replay)

---

## Core API Overview

Source: core/README.md

# Nyxzie Core - DaemonX B2B Developer API

> **Service Name:** Nyxzie Cloud Core - DaemonX Management & Telemetry API  
> **Production Base URL:** `https://api.nyxzie.com/api/v1/daemonx`  
> **Transport:** HTTPS with JSON payloads  

---

## 1. Architectural Overview

While the **DaemonX Local Bridge** (`http://127.0.0.1:9123`) runs on individual Windows workstations to handle silent ESC/POS hardware spooling, the **Nyxzie Core Cloud API** serves as the central orchestration and management platform:

```
┌──────────────────────────────────────┐
│  B2B Merchant SaaS / Developer App   │
└──────────────────┬───────────────────┘
                   │
                   │ HTTPS REST (Bearer nyx_daemonx_live_...)
                   ▼
┌────────────────────────────────────────────────────────┐
│              Nyxzie Cloud Core API                     │
│               (/api/v1/daemonx/*)                      │
│                                                        │
│  ├── Token Shield & Developer Tier Metering            │
│  ├── Counter Registry & Device Configuration           │
│  ├── Ephemeral Pairing Handshake Engine (Redis)        │
│  └── Offline Lease Signing & Cryptographic Validation  │
└──────────────────┬─────────────────────────────────────┘
                   │
                   │ Background Heartbeat & Lease Sync (60s/300s)
                   ▼
┌────────────────────────────────────────────────────────┐
│     DaemonX Windows Workstation (127.0.0.1:9123)       │
└────────────────────────────────────────────────────────┘
```

---

## 2. Authentication & Authorization

All B2B developer management endpoints are protected by **DaemonX API Tokens** issued from the Nyxzie Developer Portal:

### 2.1. Bearer Token Header
Requests must include the HTTP `Authorization` header:
```http
Authorization: Bearer nyx_daemonx_live_6b431eda073e6cb462bd0a9971687376ef5481887c46dfa688bcb618982fc905
```

| Token Type | Prefix | Description |
| :--- | :--- | :--- |
| **Live** | `nyx_daemonx_live_` | Production token bound to live counters and billing meters. |
| **Sandbox / Test** | `nyx_daemonx_sandbox_` | Development token isolated from production quotas and live transactions. |

### 2.2. Endpoint Scope
DaemonX developer tokens are also restricted by endpoint group. A token must include the relevant group in its `allowed_endpoints` list:

| Endpoint Group | Allows |
| :--- | :--- |
| `/api/v1/daemonx/counters` | `GET /api/v1/daemonx/counters` |
| `/api/v1/daemonx/onboarding/sessions` | Session creation, status lookup, cancellation, and webhook replay. |

If the token is valid but does not include the required endpoint group, Core returns `403 DAEMONX_ENDPOINT_NOT_ALLOWED`.

### 2.3. Error Responses & Envelopes
Responses follow a standard JSON envelope:

#### Success Envelope
```json
{
  "success": true,
  "counters": [ ... ]
}
```

#### Error Envelope
```json
{
  "success": false,
  "error": "Human-readable error description",
  "code": "ERROR_CODE"
}
```

---

## 3. Developer Endpoints Index

### Counters Management
| Method | Endpoint | Document Link | Description |
| :--- | :--- | :--- | :--- |
| `GET` | `/api/v1/daemonx/counters` | [01_GET_api_v1_daemonx_counters.md](./01_GET_api_v1_daemonx_counters.md) | Query, list, and filter registered counters by location or external reference. |

### Onboarding Sessions & Pairing
| Method | Endpoint | Document Link | Description |
| :--- | :--- | :--- | :--- |
| `POST` | `/api/v1/daemonx/onboarding/sessions` | [02a_POST_api_v1_daemonx_onboarding_sessions.md](./02a_POST_api_v1_daemonx_onboarding_sessions.md) | Initiate an onboarding session & generate a 6-digit desktop pairing code. |
| `GET` | `/api/v1/daemonx/onboarding/sessions/:id` | [02b_GET_api_v1_daemonx_onboarding_sessions_id.md](./02b_GET_api_v1_daemonx_onboarding_sessions_id.md) | Query onboarding session status and resolve paired counter UUID. |
| `POST` | `/api/v1/daemonx/onboarding/sessions/:id/cancel` | [02c_POST_api_v1_daemonx_onboarding_sessions_cancel.md](./02c_POST_api_v1_daemonx_onboarding_sessions_cancel.md) | Cancel an active or pending onboarding pairing session. |
| `POST` | `/api/v1/daemonx/onboarding/sessions/:id/webhook/replay` | [02d_POST_api_v1_daemonx_onboarding_sessions_webhook_replay.md](./02d_POST_api_v1_daemonx_onboarding_sessions_webhook_replay.md) | Request outbox redelivery of completion webhook for completed session. |

---

## List Counters

Source: core/01_GET_api_v1_daemonx_counters.md

# `GET /api/v1/daemonx/counters`
> **Endpoint:** `GET /api/v1/daemonx/counters`  
> **Auth Scope:** Developer Token Protected (`Authorization: Bearer nyx_daemonx_live_...`)  
> **Target Service:** Nyxzie Cloud Core API  
> **Introduced In:** v1.0.0  
> **Last Updated:** v1.0.0  

---

## 1. Description & Purpose

`GET /api/v1/daemonx/counters` is a B2B developer management endpoint that enables external platforms, POS frontends, and SaaS backends to query and inspect all retail counters associated with their DaemonX developer profile.

Key features:
1. **Multi-Store & Tenant Filtering:** Query by your platform's own external references (`external_customer_ref`, `external_location_ref`, `external_counter_ref`).
2. **Liveness & State Peeking:** Inspect whether the counter is currently registered (`is_active`), connected to the cloud (`is_online`), and its cumulative lifetime print jobs (`total_jobs_completed`).
3. **Privacy & Sanitization:** Internal infrastructure timestamps (such as low-level worker heartbeats) are stripped from this public B2B DTO.

---

## 2. Request Headers

| Header Name | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `Authorization` | `string` | **Yes** | Developer API Bearer Token | `Bearer nyx_daemonx_live_6b431eda073e...` |
| `Accept` | `string` | No | Response format | `application/json` |

---

## 3. Query Parameters

All query parameters are optional, trimmed strings (1–255 characters):

| Parameter | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `external_customer_ref` | `string` | Optional | Filter by merchant/customer identifier in your external platform. | `cust_milan_01` |
| `external_location_ref` | `string` | Optional | Filter by store branch or physical venue identifier. | `loc_colombo_flagship` |
| `external_counter_ref` | `string` | Optional | Filter by specific register / workstation identifier. | `pos_lane_01` |

---

## 4. TypeScript Contracts

```typescript
export interface DaemonxCounterListItem {
  counter_id: string;
  counter_name: string;
  environment: 'live' | 'sandbox';
  external_customer_ref?: string;
  external_location_ref?: string;
  external_counter_ref?: string;
  is_active: boolean;
  is_online: boolean;
  total_jobs_completed: number;
  created_at: string;
}

export interface DaemonxCounterListResponse {
  success: true;
  counters: DaemonxCounterListItem[];
}

export interface DaemonxErrorResponse {
  success: false;
  error: string;
  code?: string;
}
```

---

## 5. Successful Response (200 OK)

```json
{
  "success": true,
  "counters": [
    {
      "counter_id": "d402ddec-ecf7-4b39-b57a-86ce6008df05",
      "counter_name": "Cashier Counter 1",
      "environment": "live",
      "external_customer_ref": "cust_milan_01",
      "external_location_ref": "loc_colombo_flagship",
      "external_counter_ref": "pos_lane_01",
      "is_active": true,
      "is_online": true,
      "total_jobs_completed": 1420,
      "created_at": "2026-09-24T18:42:10.000Z"
    },
    {
      "counter_id": "8f3b610c-99d1-4cb5-8271-9f26038101ee",
      "counter_name": "Bar Station Register",
      "environment": "live",
      "external_customer_ref": "cust_milan_01",
      "external_location_ref": "loc_colombo_flagship",
      "external_counter_ref": "pos_bar_02",
      "is_active": true,
      "is_online": false,
      "total_jobs_completed": 350,
      "created_at": "2026-09-28T11:15:33.000Z"
    }
  ]
}
```

---

## 6. Error Responses

### 401 Unauthorized
Returned when `Authorization` header is missing, malformed, or the API token is revoked.
```json
{
  "success": false,
  "error": "Missing or invalid DaemonX API token.",
  "code": "UNAUTHORIZED"
}
```

### 429 Too Many Requests
Returned if request limits exceed the rate shield threshold.
```json
{
  "success": false,
  "error": "Rate limit exceeded. Please throttle your requests.",
  "code": "RATE_LIMIT_EXCEEDED"
}
```

---

## 7. Integration Snippets

### cURL
```bash
curl -X GET "https://api.nyxzie.com/api/v1/daemonx/counters?external_location_ref=loc_colombo_flagship" \
  -H "Authorization: Bearer nyx_daemonx_live_6b431eda073e6cb462bd0a9971687376ef5481887c46dfa688bcb618982fc905" \
  -H "Accept: application/json"
```

### TypeScript Client Function
```typescript
import type { DaemonxCounterListResponse, DaemonxCounterListItem } from './types';

export async function fetchDaemonxCounters(
  apiToken: string,
  filters?: {
    externalCustomerRef?: string;
    externalLocationRef?: string;
    externalCounterRef?: string;
  }
): Promise<DaemonxCounterListItem[]> {
  const url = new URL('https://api.nyxzie.com/api/v1/daemonx/counters');

  if (filters?.externalCustomerRef) {
    url.searchParams.set('external_customer_ref', filters.externalCustomerRef.trim());
  }
  if (filters?.externalLocationRef) {
    url.searchParams.set('external_location_ref', filters.externalLocationRef.trim());
  }
  if (filters?.externalCounterRef) {
    url.searchParams.set('external_counter_ref', filters.externalCounterRef.trim());
  }

  const res = await fetch(url.toString(), {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${apiToken.trim()}`,
      'Accept': 'application/json',
    },
  });

  if (!res.ok) {
    const errorBody = await res.json().catch(() => null);
    throw new Error(errorBody?.error || `Failed to fetch counters (HTTP ${res.status})`);
  }

  const data = (await res.json()) as DaemonxCounterListResponse;
  return data.counters;
}
```

---

## Create Pairing Session

Source: core/02a_POST_api_v1_daemonx_onboarding_sessions.md

# `POST /api/v1/daemonx/onboarding/sessions`

> **Endpoint:** `POST /api/v1/daemonx/onboarding/sessions`  
> **Auth Scope:** Developer Token Protected (`Authorization: Bearer nyx_daemonx_live_...`)  
> **Target Service:** Nyxzie Cloud Core API  
> **Introduced In:** v1.0.0  
> **Last Updated:** v1.0.0  

---

## 1. Description & Purpose

`POST /api/v1/daemonx/onboarding/sessions` initiates a secure counter onboarding session for retail workstations. It generates an ephemeral 6-digit pairing code (valid for 900 seconds / 15 minutes) that a cashier or technician enters into the **DaemonX Windows Desktop App** to pair the workstation with Nyxzie Core.

Key characteristics:
1. **Server-to-Server B2B Security:** Called by your backend with a Developer API token (`nyx_daemonx_live_*` or `nyx_daemonx_sandbox_*`). The token is **never** shared with the cashier browser or desktop machine.
2. **Deterministic Entity Correlation:** Binds the session to your platform's customer/merchant reference (`external_customer_ref`), store branch (`external_location_ref`), and register lane (`external_counter_ref`).

---

## 2. Request Headers

| Header Name | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `Authorization` | `string` | **Yes** | Developer API Bearer Token | `Bearer nyx_daemonx_live_6b431eda073e...` |
| `Content-Type` | `string` | **Yes** | Payload format | `application/json` |
| `Accept` | `string` | No | Response format | `application/json` |

---

## 3. Request Payload

```typescript
export interface CreateOnboardingSessionRequest {
  external_customer_ref: string;
  external_location_ref?: string;
  external_counter_ref?: string;
  counter_name: string;
}
```

| Field | Type | Required | Constraints | Description |
| :--- | :--- | :--- | :--- | :--- |
| `external_customer_ref` | `string` | **Yes** | 1–255 chars | Merchant / site identifier in your system. |
| `external_location_ref` | `string` | Optional | 1–255 chars | Store branch or venue identifier. |
| `external_counter_ref` | `string` | Optional | 1–255 chars | POS register lane or counter identifier. |
| `counter_name` | `string` | **Yes** | 2–100 chars | Friendly display name for the register. |

---

## 4. Successful Response (201 Created)

```json
{
  "success": true,
  "onboarding_session_id": "4b68ff5e-f001-4475-8025-a741544256eb",
  "pairing_code": "842915",
  "expires_in": 900,
  "onboarding_session": {
    "id": "4b68ff5e-f001-4475-8025-a741544256eb",
    "status": "pending",
    "external_customer_ref": "cust_milan_01",
    "external_location_ref": "loc_colombo_flagship",
    "external_counter_ref": "pos_lane_01",
    "counter_name": "Cashier Counter 1",
    "environment": "live",
    "is_sandbox": false,
    "counter_id": null,
    "completed_at": null,
    "expires_at": "2026-10-07T02:38:24.000Z",
    "created_at": "2026-10-07T02:33:24.000Z"
  }
}
```

---

## 5. TypeScript Contracts

```typescript
export interface DaemonxOnboardingSessionDTO {
  id: string;
  status: 'pending' | 'completed' | 'expired' | 'cancelled' | 'failed';
  external_customer_ref: string | null;
  external_location_ref?: string | null;
  external_counter_ref?: string | null;
  counter_name: string | null;
  environment: 'live' | 'sandbox';
  is_sandbox: boolean;
  counter_id?: string | null;
  completed_at?: string | null;
  expires_at: string;
  created_at: string;
}

export interface CreateOnboardingSessionResponse {
  success: true;
  onboarding_session_id: string;
  pairing_code: string;
  expires_in: number;
  onboarding_session: DaemonxOnboardingSessionDTO;
}

export interface DaemonxErrorResponse {
  success: false;
  error: string;
  code?: string;
}
```

---

## 6. Integration Snippets

### cURL
```bash
curl -X POST "https://api.nyxzie.com/api/v1/daemonx/onboarding/sessions" \
  -H "Authorization: Bearer nyx_daemonx_live_6b431eda073e6cb462bd0a9971687376ef5481887c46dfa688bcb618982fc905" \
  -H "Content-Type: application/json" \
  -d '{
    "external_customer_ref": "cust_milan_01",
    "external_location_ref": "loc_colombo_flagship",
    "external_counter_ref": "pos_lane_01",
    "counter_name": "Cashier Counter 1"
  }'
```

### TypeScript Backend Example
```typescript
import type { CreateOnboardingSessionResponse } from './types';

export async function createDaemonxPairingSession(
  apiToken: string,
  input: {
    customerRef: string;
    locationRef?: string;
    counterRef?: string;
    counterName: string;
  }
): Promise<CreateOnboardingSessionResponse> {
  const res = await fetch('https://api.nyxzie.com/api/v1/daemonx/onboarding/sessions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiToken.trim()}`,
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
    body: JSON.stringify({
      external_customer_ref: input.customerRef.trim(),
      external_location_ref: input.locationRef?.trim(),
      external_counter_ref: input.counterRef?.trim(),
      counter_name: input.counterName.trim(),
    }),
  });

  if (!res.ok) {
    const errorBody = await res.json().catch(() => null);
    throw new Error(errorBody?.error || `Failed to create onboarding session (HTTP ${res.status})`);
  }

  return (await res.json()) as CreateOnboardingSessionResponse;
}
```

---

## Check Pairing Session

Source: core/02b_GET_api_v1_daemonx_onboarding_sessions_id.md

# `GET /api/v1/daemonx/onboarding/sessions/:id`

> **Endpoint:** `GET /api/v1/daemonx/onboarding/sessions/:id`  
> **Auth Scope:** Developer Token Protected (`Authorization: Bearer nyx_daemonx_live_...`)  
> **Target Service:** Nyxzie Cloud Core API  
> **Introduced In:** v1.0.0  
> **Last Updated:** v1.0.0  

---

## 1. Description & Purpose

`GET /api/v1/daemonx/onboarding/sessions/:id` resolves the canonical lifecycle status of an existing onboarding session.

Use cases:
1. **Pairing Status Polling / Verification:** Check if the cashier has entered the 6-digit code in their desktop app and if workstation pairing has completed.
2. **Post-Pairing Metadata Resolution:** Once the session transitions to `"completed"`, this endpoint reveals the newly issued `counter_id` assigned to the physical workstation.
3. **Timeout / Expiration Inspection:** Detect if a pairing session expired (`"expired"`) or failed (`"failed"`).

---

## 2. Request Headers

| Header Name | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `Authorization` | `string` | **Yes** | Developer API Bearer Token | `Bearer nyx_daemonx_live_6b431eda073e...` |
| `Accept` | `string` | No | Response format | `application/json` |

---

## 3. Path Parameters

| Parameter | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `id` | `string` (UUID) | **Yes** | Onboarding session UUID returned when creating the session. | `4b68ff5e-f001-4475-8025-a741544256eb` |

---

## 4. Successful Response Examples (200 OK)

### State A: Session Completed (Workstation Paired)
```json
{
  "success": true,
  "onboarding_session": {
    "id": "4b68ff5e-f001-4475-8025-a741544256eb",
    "status": "completed",
    "external_customer_ref": "cust_milan_01",
    "external_location_ref": "loc_colombo_flagship",
    "external_counter_ref": "pos_lane_01",
    "counter_name": "Cashier Counter 1",
    "environment": "live",
    "is_sandbox": false,
    "counter_id": "d402ddec-ecf7-4b39-b57a-86ce6008df05",
    "completed_at": "2026-10-07T02:35:10.000Z",
    "expires_at": "2026-10-07T02:38:24.000Z",
    "created_at": "2026-10-07T02:33:24.000Z"
  }
}
```

### State B: Session Pending (Waiting for Code Entry on Desktop)
```json
{
  "success": true,
  "onboarding_session": {
    "id": "4b68ff5e-f001-4475-8025-a741544256eb",
    "status": "pending",
    "external_customer_ref": "cust_milan_01",
    "external_location_ref": "loc_colombo_flagship",
    "external_counter_ref": "pos_lane_01",
    "counter_name": "Cashier Counter 1",
    "environment": "live",
    "is_sandbox": false,
    "counter_id": null,
    "completed_at": null,
    "expires_at": "2026-10-07T02:38:24.000Z",
    "created_at": "2026-10-07T02:33:24.000Z"
  }
}
```

---

## 5. Lifecycle Status Values

| Status | Meaning | Next Action |
| :--- | :--- | :--- |
| `pending` | Pairing code has been issued and is awaiting desktop activation. | Continue polling or listen to SSE/webhook events. |
| `completed` | The workstation was successfully registered and activated. | Safe to dispatch print jobs using the returned `counter_id`. |
| `expired` | The 900-second TTL elapsed without being entered. | Generate a fresh pairing session. |
| `cancelled` | The session was cancelled via the developer API before pairing. | Ignore this session. |
| `failed` | Machine binding failed during pairing (e.g. invalid machine profile). | Review error logs or request a new code. |

---

## 6. TypeScript Contracts

```typescript
export interface DaemonxOnboardingSessionDTO {
  id: string;
  status: 'pending' | 'completed' | 'expired' | 'cancelled' | 'failed';
  external_customer_ref: string | null;
  external_location_ref?: string | null;
  external_counter_ref?: string | null;
  counter_name: string | null;
  environment: 'live' | 'sandbox';
  is_sandbox: boolean;
  counter_id?: string | null;
  completed_at?: string | null;
  expires_at: string;
  created_at: string;
}

export interface GetOnboardingSessionResponse {
  success: true;
  onboarding_session: DaemonxOnboardingSessionDTO;
}

export interface DaemonxErrorResponse {
  success: false;
  error: string;
  code?: string;
}
```

---

## 7. Integration Snippets

### cURL
```bash
curl -X GET "https://api.nyxzie.com/api/v1/daemonx/onboarding/sessions/4b68ff5e-f001-4475-8025-a741544256eb" \
  -H "Authorization: Bearer nyx_daemonx_live_6b431eda073e6cb462bd0a9971687376ef5481887c46dfa688bcb618982fc905" \
  -H "Accept: application/json"
```

### TypeScript Client Function
```typescript
import type { GetOnboardingSessionResponse, DaemonxOnboardingSessionDTO } from './types';

export async function getDaemonxOnboardingSession(
  apiToken: string,
  sessionId: string
): Promise<DaemonxOnboardingSessionDTO> {
  const res = await fetch(`https://api.nyxzie.com/api/v1/daemonx/onboarding/sessions/${encodeURIComponent(sessionId)}`, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${apiToken.trim()}`,
      'Accept': 'application/json',
    },
  });

  if (!res.ok) {
    const errorBody = await res.json().catch(() => null);
    throw new Error(errorBody?.error || `Failed to fetch session (HTTP ${res.status})`);
  }

  const data = (await res.json()) as GetOnboardingSessionResponse;
  return data.onboarding_session;
}
```

---

## Cancel Pairing Session

Source: core/02c_POST_api_v1_daemonx_onboarding_sessions_cancel.md

# `POST /api/v1/daemonx/onboarding/sessions/:id/cancel`

> **Endpoint:** `POST /api/v1/daemonx/onboarding/sessions/:id/cancel`  
> **Auth Scope:** Developer Token Protected (Writable Token Required)  
> **Target Service:** Nyxzie Cloud Core API  
> **Introduced In:** v1.0.0  
> **Last Updated:** v1.0.0  

---

## 1. Description & Purpose

`POST /api/v1/daemonx/onboarding/sessions/:id/cancel` cancels an active or pending onboarding pairing session before it is claimed or completed on a physical workstation.

Use cases:
1. **User Aborted Setup:** Cashier or administrator closes the pairing modal or clicks "Cancel" on the POS UI.
2. **Session Cleanup:** Invalidate an outstanding 6-digit pairing code before its 900-second TTL expires.
3. **Idempotent Invalidation:** Safe to call multiple times; already-cancelled sessions return the current cancelled session representation.

> [!NOTE]
> Sessions that have already transitioned to `"completed"` cannot be cancelled and will return a `409 Conflict` (`DAEMONX_ONBOARDING_COMPLETED`). To deactivate an already paired counter, use the counter unpair lifecycle.

---

## 2. Request Headers

| Header Name | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `Authorization` | `string` | **Yes** | Developer API Bearer Token (must have write permissions) | `Bearer nyx_daemonx_live_6b431eda073e...` |
| `Content-Type` | `string` | No | Body media type | `application/json` |
| `Accept` | `string` | No | Response format | `application/json` |

---

## 3. Path Parameters

| Parameter | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `id` | `string` (UUID) | **Yes** | The onboarding session UUID to cancel. | `4b68ff5e-f001-4475-8025-a741544256eb` |

---

## 4. Request Body

This endpoint is an empty-body command action. No parameters are required.

```json
{}
```

---

## 5. Successful Response Example (200 OK)

```json
{
  "success": true,
  "onboarding_session": {
    "id": "4b68ff5e-f001-4475-8025-a741544256eb",
    "status": "cancelled",
    "external_customer_ref": "cust_milan_01",
    "external_location_ref": "loc_colombo_flagship",
    "external_counter_ref": "pos_lane_01",
    "counter_name": "Cashier Counter 1",
    "environment": "live",
    "is_sandbox": false,
    "counter_id": null,
    "completed_at": null,
    "expires_at": "2026-10-07T02:38:24.000Z",
    "created_at": "2026-10-07T02:33:24.000Z"
  }
}
```

---

## 6. Error Responses

### 6.1. Cannot Cancel Completed Session (`409 Conflict`)
If the workstation has already completed pairing and bound to the session:
```json
{
  "success": false,
  "error": "Completed DaemonX onboarding sessions cannot be cancelled.",
  "code": "DAEMONX_ONBOARDING_COMPLETED"
}
```

### 6.2. Session Not Found (`404 Not Found`)
If the session UUID does not exist or belongs to another developer profile:
```json
{
  "success": false,
  "error": "DaemonX onboarding session not found.",
  "code": "DAEMONX_ONBOARDING_SESSION_NOT_FOUND"
}
```

### 6.3. Read-Only Token Used (`403 Forbidden`)
If a read-only developer token attempts to cancel a session:
```json
{
  "success": false,
  "error": "DaemonX token does not have write permissions.",
  "code": "DAEMONX_TOKEN_READ_ONLY"
}
```

---

## 7. TypeScript Contracts

```typescript
export interface DaemonxOnboardingSessionCancelResponse {
  success: true;
  onboarding_session: {
    id: string;
    status: 'cancelled';
    external_customer_ref: string | null;
    external_location_ref?: string | null;
    external_counter_ref?: string | null;
    counter_name: string;
    environment: 'live' | 'sandbox';
    is_sandbox: boolean;
    counter_id?: string | null;
    completed_at?: string | null;
    expires_at: string;
    created_at: string;
  };
}
```

---

## 8. cURL Example

```bash
curl -X POST https://api.nyxzie.com/api/v1/daemonx/onboarding/sessions/4b68ff5e-f001-4475-8025-a741544256eb/cancel \
  -H "Authorization: Bearer nyx_daemonx_live_6b431eda073e6cb462bd0a9971687376ef5481887c46dfa688bcb618982fc905" \
  -H "Content-Type: application/json" \
  -d '{}'
```

---

## Replay Pairing Webhook

Source: core/02d_POST_api_v1_daemonx_onboarding_sessions_webhook_replay.md

# `POST /api/v1/daemonx/onboarding/sessions/:id/webhook/replay`

> **Endpoint:** `POST /api/v1/daemonx/onboarding/sessions/:id/webhook/replay`  
> **Auth Scope:** Developer Token Protected (Writable Token Required)  
> **Target Service:** Nyxzie Cloud Core API  
> **Introduced In:** v1.0.0  
> **Last Updated:** v1.0.0  

---

## 1. Description & Purpose

`POST /api/v1/daemonx/onboarding/sessions/:id/webhook/replay` queues a redelivery of the `daemonx.onboarding.completed` webhook event for an already completed onboarding session.

Use cases:
1. **Developer Downtime Recovery:** If the developer's receiving webhook service was down, returned a 5xx error, or suffered a network timeout when the workstation originally completed pairing.
2. **Ops Resync:** Enables administrative tooling and background reconciliation workers to trigger a fresh webhook dispatch without requiring counter re-pairing or database intervention.
3. **Outbox Guarantee:** Generates a new pending outbox entry with a fresh `event_id` in `daemonx_webhook_events` that is immediately picked up by the outbox dispatcher.

> [!NOTE]
> This endpoint only accepts sessions that have successfully reached `"completed"` status. It cannot replay pending, expired, or cancelled sessions.

---

## 2. Request Headers

| Header Name | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `Authorization` | `string` | **Yes** | Developer API Bearer Token (must have write permissions) | `Bearer nyx_daemonx_live_6b431eda073e...` |
| `Accept` | `string` | No | Response format | `application/json` |

---

## 3. Path Parameters

| Parameter | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `id` | `string` (UUID) | **Yes** | Completed onboarding session UUID. | `4b68ff5e-f001-4475-8025-a741544256eb` |

---

## 4. Request Body

No request body is needed for this endpoint.

---

## 5. Successful Response Example (201 Created)

When the event is successfully queued in the outbox:

```json
{
  "success": true,
  "webhook": {
    "event_id": "dxe_9c2409f87c9343df8995a557",
    "event_type": "daemonx.onboarding.completed",
    "status": "pending"
  }
}
```

> [!TIP]
> The API returns the newly allocated outbox handle (`event_id` with `status: "pending"`). The actual webhook dispatch occurs asynchronously through the outbox dispatcher to the developer's configured webhook endpoint.

---

## 6. Dispatched Webhook Payload Structure

When the outbox dispatcher delivers the replayed webhook to your registered HTTPS endpoint, the HTTP `POST` body contains:

```json
{
  "event": "daemonx.onboarding.completed",
  "event_id": "dxe_9c2409f87c9343df8995a557",
  "onboarding_session_id": "4b68ff5e-f001-4475-8025-a741544256eb",
  "environment": "live",
  "is_sandbox": false,
  "external_customer_ref": "cust_milan_01",
  "external_location_ref": "loc_colombo_flagship",
  "external_counter_ref": "pos_lane_01",
  "counter_id": "d402ddec-ecf7-4b39-b57a-86ce6008df05",
  "counter_name": "Cashier Counter 1",
  "occurred_at": "2026-10-07T02:35:10.000Z"
}
```

Webhooks include the standard Nyxzie signature header:
- `X-DaemonX-Signature`: HMAC SHA-256 signature calculated over the raw request body using your developer webhook signing secret.

---

## 7. Error Responses

### 7.1. Session Not Completed (`404 Not Found`)
Returned if the session UUID does not exist under your developer profile, or if the session is not in `"completed"` status (e.g. still pending, expired, or cancelled):
```json
{
  "success": false,
  "error": "Completed DaemonX onboarding session not found.",
  "code": "DAEMONX_ONBOARDING_SESSION_NOT_COMPLETED"
}
```

### 7.2. Read-Only Token Used (`403 Forbidden`)
If a read-only developer token attempts to replay a webhook:
```json
{
  "success": false,
  "error": "DaemonX token does not have write permissions.",
  "code": "DAEMONX_TOKEN_READ_ONLY"
}
```

---

## 8. TypeScript Contracts

```typescript
export interface DaemonxOnboardingWebhookReplayResponse {
  success: true;
  webhook: {
    event_id: string;
    event_type: 'daemonx.onboarding.completed';
    status: 'pending' | string;
  };
}

export interface DaemonxOnboardingCompletedWebhookPayload {
  event: 'daemonx.onboarding.completed';
  event_id: string;
  onboarding_session_id: string;
  environment: 'live' | 'sandbox';
  is_sandbox: boolean;
  external_customer_ref: string | null;
  external_location_ref: string | null;
  external_counter_ref: string | null;
  counter_id: string;
  counter_name: string;
  occurred_at: string;
}
```

---

## 9. cURL Example

```bash
curl -X POST https://api.nyxzie.com/api/v1/daemonx/onboarding/sessions/4b68ff5e-f001-4475-8025-a741544256eb/webhook/replay \
  -H "Authorization: Bearer nyx_daemonx_live_6b431eda073e6cb462bd0a9971687376ef5481887c46dfa688bcb618982fc905"
```
