Metadata-Version: 2.4
Name: mock-happenstance-api
Version: 0.1.0
Summary: Mock implementation of the Happenstance API for generating synthetic relationship-intelligence data
Author: Alex Garcia
License-Expression: MIT
Project-URL: Repository, https://github.com/garcia-alex/mock-happenstance-api
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: faker>=30
Requires-Dist: fastapi>=0.110
Requires-Dist: pydantic>=2.9
Requires-Dist: pydantic-settings>=2.5
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: uvicorn[standard]>=0.30
Dynamic: license-file

# mock-happenstance-api

> This is a public-source project — see [CONTRIBUTING.md](CONTRIBUTING.md)
> for the PR policy.

A deterministic, self-hosted mock of the [Happenstance](https://happenstance.ai)
relationship-intelligence API — same endpoints, request/response shapes, and
async job-polling behavior as the real API, backed by a synthetic
VC/startup-flavored people graph instead of real data.

Built for projects that need a Happenstance connector but have no access to
(or need for) the real, paid API while developing.

## Quickstart

```bash
uv sync
make seed   # generates happenstance.db from a fixed seed
make dev    # serves the API on http://localhost:8000
```

```bash
curl -s http://localhost:8000/v1/search -H "Authorization: Bearer test" \
  -H "Content-Type: application/json" \
  -d '{"text": "biotech founders in Boston"}'
```

Any non-empty bearer token is accepted — there's no real key management.

## Endpoints

`POST /v1/search`, `GET /v1/search/{id}`, `POST /v1/search/{id}/find-more`,
`POST /v1/research`, `GET /v1/research/{id}`, `GET /v1/users/me`,
`GET /v1/usage`, `GET /v1/groups`, `GET /v1/groups/{id}` — mirroring the real
API's shape (see `developer.happenstance.ai`).

## Data model

`make seed` deterministically generates ~300-500 synthetic people, ~40-60
companies, and ~15-20 co-investor groups, all connected by a real graph of
colleague/connection/co-investor/advisor/board edges. Search, mutuals,
`@mention` filtering, and warm-intro paths all read from that graph rather
than being randomized per call.

## Testing error paths

- `X-Mock-Force-Status: 402` or `429` header forces that error on any request.
- A research `description` containing `__FAIL__` or `__FAIL_AMBIGUOUS__`
  forces that terminal research status.
- `HAPPENSTANCE_MOCK_DELAY=realistic` (env var) simulates the real API's
  30-60s (search) / 1-3min (research) `RUNNING` → `COMPLETED` delay instead
  of completing instantly.

## Development

```bash
make test       # pytest
make lint       # ruff + pyright
```
