WePeopleDocs
IntegrationsPricingDocsSign inGet started
Get started
Docs home

Getting Started

  • What is WePeople
  • First week checklist
  • Core concepts

Product

  • Monitoring
  • Reports
  • People & profiles
  • SPACE scoring
  • Organization settings
  • Statistics
  • Billing & retention
  • Privacy model

Integrations

  • Overview
  • Slack
  • GitHub
  • Jira
  • Trust model

Developers

  • Platform overview
  • Quick start
  • Ingest guide
  • Custom statistics
  • Hosted MCP
  • TypeScript SDK

API Reference

  • Overview
  • Auth & headers
  • GET ping
  • POST events
  • POST snapshots
  • Apps statistics
  • Error codes
  • OpenAPI & SDK

Browse docs

Developers

Ingest guide

Everything you need to wire your CRM, CI pipeline, AI agents, or internal tools into WePeople. Pair this guide with the API reference for per-endpoint contracts.

Concepts

The Ingest API is private and per-organization. You create one or more developer apps inside an organization; each app owns its own API keys, event-type whitelist, and synthetic integration connection. Events show up on the monitoring dashboard as custom:<app-slug>, side by side with Slack, GitHub, and Jira.

Two primitives: events (discrete timeline rows) and snapshots (point-in-time gauges on the user strip).

Authentication

Authenticate every request with a bearer token. Generate keys from Organization → Developer → New key. Keys are prefixed with wp_live_ and shown once.

Smoke-test with GET /api/v1/ingest/ping. See Auth & headers for idempotency and CORS details.

Authorization headerhttp
Authorization: Bearer wp_live_9f3c3e4c1e9b4b2d9c1e3f4b2c3d4e5f

Identifying workers

Every event and snapshot belongs to a worker. The actor object accepts three identifiers; the server resolves in order:

  1. workerId — existing WePeople worker id.
  2. externalId— your system’s stable id (recommended). Unique per app.
  3. email — match against the org directory.

When nothing matches, WePeople auto-provisions a worker and links it to the app’s custom:<slug> connection. Optional displayName sets the name on create.

Events

Events are batched — up to 100 per request, body ≤ 1 MB. Each entry needs eventType (whitelisted), category, and actor. Optional timestamp (ISO 8601), duration (0–86400 seconds), and metadata(≤ 16 KB JSON).

Full field reference: POST events.

POST /api/v1/ingest/eventsjson
{
  "events": [
    {
      "eventType": "deploy.shipped",
      "category": "CODE_CHANGE",
      "timestamp": "2026-04-19T12:05:00Z",
      "actor": { "externalId": "eng-17" },
      "duration": 612,
      "metadata": {
        "service": "checkout-api",
        "sha": "3c4d8a1",
        "env": "production"
      }
    }
  ]
}

The response includes accepted, rejected, and a per-row breakdown. Partial success yields 207 — resend only the rejected indices.

Snapshots

A snapshot replaces the previous snapshot for the same (worker, snapshotType) pair. The user strip renders up to four metrics per app. Metrics may be plain numbers, short strings, or rich objects with value, unit, and label.

See POST snapshots.

POST /api/v1/ingest/snapshotsjson
{
  "snapshotType": "oncall_queue",
  "actor": { "email": "alex@acme.com" },
  "metrics": {
    "active": 2,
    "waiting": { "value": 5, "unit": "count", "label": "queued" },
    "p95_ack": { "value": 3.4, "unit": "minutes", "label": "p95 ack" }
  }
}

Idempotency

Add an Idempotency-Key header (≤ 200 chars) on every write. The first response for a given key is cached for ten minutes and replayed verbatim on retry — safe for at-least-once queues and cron jobs.

The TypeScript SDK generates one per call by default. Override when you want your queue to dedupe:

@wepeople/sdkts
await client.ingestEvents(events, {
  idempotencyKey: `${jobId}:${attempt}`,
});

Rate limits & caps

Three independent budgets apply:

  • Per key: 60 req/s (sliding window).
  • Per organization: 600 req/s aggregate across all keys.
  • Monthly events: plan cap maxEventsPerMonth. Returns quota_exceeded (402) when exhausted.

On rate_limited (429), respect Retry-After and X-RateLimit-* headers. The SDK retries with exponential backoff and jitter.

Errors

Every error is JSON with a stable code, human-readable message, requestId, and docsUrl pointing to error codes.

Error payloadjson
{
  "error": {
    "code": "forbidden_event_type",
    "message": "eventType 'deploy.shipped' is not in this app's whitelist.",
    "requestId": "req_01HP3K5V4J3M9NVT8XZKQ9YQ2E",
    "docsUrl": "https://wepeople.app/docs/reference/errors"
  }
}

Handle distinctly: invalid_key, quota_exceeded, rate_limited, forbidden_event_type, and invalid_body. Transient failures (internal_error) are retryable.

Security

Keys are bcrypt-hashed, shown once, and revocable from the Developer tab. All writes use TLS. Metadata is stored as JSONB and is retrievable only within the owning organization. If a key leaks, revoke immediately — revocation takes effect on the next auth lookup (≤ 60 seconds with the current cache).

Ingest endpoints allow browser CORS for Authorization and Idempotency-Key; still treat keys as server-side secrets in production.

On this page

  • Concepts
  • Authentication
  • Identifying workers
  • Events
  • Snapshots
  • Idempotency
  • Rate limits & caps
  • Errors
  • Security
WePeople

Team insight, not surveillance. A lead's-eye view built on metadata from the tools your team already uses — never source code, never messages, never DMs.

Product

  • Monitoring & Reports
  • SPACE scoring
  • Pricing

Docs

  • Docs home
  • Getting started
  • Developer platform
  • API reference
  • MCP

Integrations

  • Browse integrations

Company

  • Support
  • Status

Legal

  • Brand
  • Privacy
  • Terms

© 2026 WePeople. Built with care.

Metadata only. No source code, no message bodies, no DMs — read the policy.