Skip to main content

Transparent LLM usage tracking — OpenAI and Anthropic wrappers that send cost and token metrics to Nightswatch.

Project description

Nightswatch SDK — Installation & Integration Guide

Base URL: https://api.nightswatch.work


Requirements

  • Python 3.9+
  • An active Nightswatch account and API key (nw_ prefix)

Installation

pip install nightswatch-sdk

To enable NER-based PII redaction (recommended for production):

pip install nightswatch-sdk spacy
python -m spacy download en_core_web_sm

Without spacy, PII redaction falls back to regex-only (SSN, credit cards, emails, phones, IP addresses still redacted).


Quick Start

1. Initialize

Call nightswatch.init() once at application startup, before any LLM calls.

import nightswatch

nightswatch.init(
    api_key="nw_your_api_key_here",
    default_team="backend",
    default_service="chat-api",
)

Parameters

Parameter Type Required Default Description
api_key string Yes Your API key from the Nightswatch dashboard
default_team string No "unknown" Team label applied to all events unless overridden per-call
default_service string No "unknown" Service/product label applied to all events

2. Wrap your LLM client

Pass your existing client to nightswatch.wrap(). The returned object is a drop-in replacement — all existing call signatures remain unchanged.

client = nightswatch.wrap(client)

Provider Integration

OpenAI

import nightswatch
from openai import OpenAI

nightswatch.init(api_key="nw_your_api_key_here", default_team="backend", default_service="chat-api")

client = nightswatch.wrap(OpenAI())

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Explain async/await in Python"}],
)
print(response.choices[0].message.content)

Anthropic

import nightswatch
import anthropic

nightswatch.init(api_key="nw_your_api_key_here", default_team="ml-team", default_service="summarizer")

client = nightswatch.wrap(anthropic.Anthropic())

message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Summarize this document..."}],
)
print(message.content[0].text)

Gemini support is on the roadmap (v1.1). The SDK currently wraps openai.OpenAI and anthropic.Anthropic clients. Gemini integration ships in the next release. For now, instrument Gemini via the REST API below.


REST API (Manual Instrumentation)

If you are not using Python, or need to instrument a language without a native SDK, send events directly to the ingestion endpoint.

POST /v1/ai-usage/events
Authorization: Bearer nw_your_api_key_here
Content-Type: application/json

Request body

Field Type Required Description
provider string Yes LLM provider: openai, anthropic, google, etc.
model string Yes Model name, e.g. gpt-4o, claude-sonnet-4-6, gemini-2.5-flash
prompt_tokens integer Yes Input token count
completion_tokens integer Yes Output token count
total_tokens integer Yes Sum of prompt + completion tokens
cost_usd float No Cost in USD (computed server-side from token counts if 0)
team string No Team label for cost attribution
service string No Service/product label
user_id string No End-user identifier (for per-user analytics)
metadata object No Arbitrary key-value pairs; PII is redacted before storage

Example

curl -X POST https://api.nightswatch.work/v1/ai-usage/events \
  -H "Authorization: Bearer nw_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "openai",
    "model": "gpt-4o",
    "prompt_tokens": 142,
    "completion_tokens": 89,
    "total_tokens": 231,
    "cost_usd": 0.0,
    "team": "backend",
    "service": "chat-api"
  }'

Response 200

{
  "status": "ok",
  "event_id": "64d3f2a1-..."
}

Errors

Code Reason
401 Missing or invalid API key
422 Required field missing or wrong type

Batch Ingestion

Send up to 100 events in a single request.

POST /v1/ai-usage/events/batch
Authorization: Bearer nw_your_api_key_here
Content-Type: application/json

Request body

{
  "events": [
    { "provider": "openai", "model": "gpt-4o", "prompt_tokens": 100, "completion_tokens": 50, "total_tokens": 150 },
    { "provider": "anthropic", "model": "claude-3-haiku-20240307", "prompt_tokens": 200, "completion_tokens": 80, "total_tokens": 280 }
  ]
}

Configuration Options

Per-call overrides

Override default_team or default_service for a specific call by passing keyword arguments (where supported by the provider wrapper):

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[...],
    nightswatch_team="data-science",
    nightswatch_service="embeddings",
)

Data Retention

Retention is configured per-tenant via the API. Valid values: 7, 30, or 90 days.

# Get current retention setting
curl https://api.nightswatch.work/v1/tenants/retention \
  -H "Authorization: Bearer nw_your_api_key_here"

# Update retention to 30 days
curl -X PUT https://api.nightswatch.work/v1/tenants/retention \
  -H "Authorization: Bearer nw_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"retention_days": 30}'

Response

{ "tenant_id": "...", "retention_days": 30 }

Events older than the configured window are automatically deleted nightly.


PII Redaction

All prompt text and metadata values are automatically redacted before storage and AI analysis. The following are detected and replaced with [REDACTED]:

PII Type Examples
SSN 123-45-6789
Credit card numbers Visa, Mastercard, Amex (with or without spaces/dashes)
Email addresses alice@example.com
Phone numbers US, UK, Indian formats
IP addresses 192.168.1.1
Aadhaar / PAN Indian government IDs
Named entities Person names, organizations, locations (requires spacy)

Raw prompt text is never stored. The Nightswatch AI risk classifier only receives token counts, model name, provider, cost, team, and service — never prompt content.

To verify redaction is active in your environment:

from backend.services.pii_redactor import redact

print(redact("Contact alice@example.com or call 555-867-5309"))
# → "Contact [REDACTED] or call [REDACTED]"

Troubleshooting

Symptom Cause Fix
401 Unauthorized Invalid or missing API key Confirm key starts with nw_ and is passed in Authorization: Bearer header
422 Unprocessable Entity Required field missing Ensure provider, model, prompt_tokens, completion_tokens, total_tokens are present
Events not appearing in dashboard Clock skew on event timestamp Use UTC timestamps; Nightswatch rejects events more than 24 h in the past
Cost shows 0.0 cost_usd not sent Either send cost_usd from your LLM client, or Nightswatch computes it from token counts automatically for known models
spaCy NER not running Package not installed pip install spacy && python -m spacy download en_core_web_sm; falls back to regex if unavailable
ValueError: retention_days must be... Invalid retention value Only 7, 30, or 90 are accepted

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nightswatch_sdk-0.1.2.tar.gz (108.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nightswatch_sdk-0.1.2-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

File details

Details for the file nightswatch_sdk-0.1.2.tar.gz.

File metadata

  • Download URL: nightswatch_sdk-0.1.2.tar.gz
  • Upload date:
  • Size: 108.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nightswatch_sdk-0.1.2.tar.gz
Algorithm Hash digest
SHA256 e98142eac1b9f52528506f4b2093d0b6aa8cb5ca913e5c808142acac357352bb
MD5 7102e9a87dd44dc91515154004927d35
BLAKE2b-256 3bd09c0db289703291587427435d14d407f013133d42245e80868561d703474f

See more details on using hashes here.

Provenance

The following attestation bundles were made for nightswatch_sdk-0.1.2.tar.gz:

Publisher: publish-sdk.yml on Nightswatch-Work/nightswatch-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nightswatch_sdk-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: nightswatch_sdk-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nightswatch_sdk-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 76d63e96f5f6b6ccd7ec0fc9d462d154f7b1a2b5c6ef3478808129c50b420059
MD5 ce99685555423c443561be2d5fa97a12
BLAKE2b-256 615786f5eaf1ad3b8cef234374162cff4ed8661ec02d6ff3464d80203ac40a12

See more details on using hashes here.

Provenance

The following attestation bundles were made for nightswatch_sdk-0.1.2-py3-none-any.whl:

Publisher: publish-sdk.yml on Nightswatch-Work/nightswatch-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page