{"id":50237185,"url":"https://github.com/dougborg/frontapp-openapi-client","last_synced_at":"2026-05-26T20:07:40.800Z","repository":{"id":353637802,"uuid":"1220219460","full_name":"dougborg/frontapp-openapi-client","owner":"dougborg","description":"Pythonic Frontapp API client ecosystem with transport-layer retries, rate-limit awareness, and auto-pagination. Python + TypeScript clients + MCP server.","archived":false,"fork":false,"pushed_at":"2026-05-04T15:52:45.000Z","size":1383,"stargazers_count":0,"open_issues_count":26,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-04T17:28:26.800Z","etag":null,"topics":["api","front","frontapp","mcp-server","openapi","python","typescript"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dougborg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"docs/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["dougborg"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2026-04-24T17:11:34.000Z","updated_at":"2026-05-04T15:29:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dougborg/frontapp-openapi-client","commit_stats":null,"previous_names":["dougborg/frontapp-openapi-client"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dougborg/frontapp-openapi-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dougborg%2Ffrontapp-openapi-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dougborg%2Ffrontapp-openapi-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dougborg%2Ffrontapp-openapi-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dougborg%2Ffrontapp-openapi-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dougborg","download_url":"https://codeload.github.com/dougborg/frontapp-openapi-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dougborg%2Ffrontapp-openapi-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33536864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"ssl_error","status_checked_at":"2026-05-26T15:22:15.568Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","front","frontapp","mcp-server","openapi","python","typescript"],"created_at":"2026-05-26T20:07:39.757Z","updated_at":"2026-05-26T20:07:40.781Z","avatar_url":"https://github.com/dougborg.png","language":"Python","funding_links":["https://github.com/sponsors/dougborg"],"categories":[],"sub_categories":[],"readme":"# Frontapp — API Client Ecosystem\n\nMulti-language client ecosystem for the\n[Front](https://dev.frontapp.com/reference/introduction) customer-communication\nplatform. Front is a shared-inbox product that unifies email, SMS, chat, and social\nchannels into one place for support and sales teams. Their\n[Core API](https://dev.frontapp.com/reference/introduction) exposes conversations,\nmessages, contacts, teammates, tags, inboxes, and more.\n\nThis monorepo ships:\n\n- A production-grade **Python client** with transport-layer retries, rate-limit\n  awareness, and pagination handling for Front's cursor-token paging.\n- A **TypeScript client** generated from the same OpenAPI spec via\n  [hey-api](https://heyapi.dev).\n- An **MCP server** exposing Frontapp operations as tools to AI assistants like Claude\n  Desktop and Cursor.\n\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n[![TypeScript](https://img.shields.io/badge/typescript-5.0+-blue.svg)](https://www.typescriptlang.org/)\n[![OpenAPI 3.0.0](https://img.shields.io/badge/OpenAPI-3.0.0-green.svg)](https://spec.openapis.org/oas/v3.0.0)\n\nThe OpenAPI spec is vendored from\n[frontapp/front-api-specs](https://github.com/frontapp/front-api-specs) and sanitized by\n`scripts/vendor_spec.py` (strips binary attachment-download paths and normalizes a few\nupstream quirks that trip the generators).\n\n## Packages\n\n| Package                                                | Language   | Version | Description                                                 |\n| ------------------------------------------------------ | ---------- | ------- | ----------------------------------------------------------- |\n| [frontapp-openapi-client](frontapp_public_api_client/) | Python     | 0.1.0   | API client with transport-layer resilience + domain helpers |\n| [frontapp-mcp-server](frontapp_mcp_server/)            | Python     | 0.1.0   | Model Context Protocol server for AI assistants             |\n| [frontapp-client](packages/frontapp-client/)           | TypeScript | 0.1.0   | Generated TypeScript/JavaScript client                      |\n\n## Features\n\n| Feature                                        | Python | TypeScript | MCP Server              |\n| ---------------------------------------------- | ------ | ---------- | ----------------------- |\n| Automatic retries (network + 5xx)              | Yes    | Yes        | Yes (via Python client) |\n| Rate-limit retry with exponential backoff      | Yes    | Yes        | Yes                     |\n| Cursor-token pagination helpers                | Yes    | Yes        | Yes                     |\n| Two-step confirm on mutations (ctx.elicit)     | —      | —          | Yes                     |\n| Full type safety (attrs + Pydantic / TS types) | Yes    | Yes        | Yes                     |\n| AI tool surface                                | —      | —          | Claude Desktop, Cursor  |\n\n## Quick Start\n\n### Python Client\n\n```bash\npip install frontapp-openapi-client\n```\n\n```python\nimport asyncio\nfrom frontapp_public_api_client import FrontappClient\n\nasync def main():\n    async with FrontappClient() as client:\n        # List recent open conversations tagged \"urgent\"\n        conversations = await client.conversations.list(\n            q=\"status:open tag:urgent\", limit=25\n        )\n        for conv in conversations:\n            assignee = conv.assignee.username if conv.assignee else \"unassigned\"\n            print(f\"{conv.id}: {conv.subject!r} — {conv.status} ({assignee})\")\n\nasyncio.run(main())\n```\n\n### TypeScript Client\n\n```bash\nnpm install frontapp-client\n```\n\n```typescript\nimport { FrontappClient } from \"frontapp-client\";\n\nconst client = await FrontappClient.create();\nconst { data } = await client.listConversations({ query: { q: \"status:open\" } });\nconsole.log(`${data._results.length} open conversations`);\n```\n\n### MCP Server (Claude Desktop)\n\n```bash\npip install frontapp-mcp-server\n```\n\nAdd to Claude Desktop config\n(`~/Library/Application Support/Claude/claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"frontapp\": {\n      \"command\": \"uvx\",\n      \"args\": [\"frontapp-mcp-server\"],\n      \"env\": {\n        \"FRONTAPP_API_KEY\": \"your-api-key-here\"\n      }\n    }\n  }\n}\n```\n\nGet an API key at Front → Settings → Developers → API tokens.\n\n## Configuration\n\nAll packages authenticate with a Front API token via bearer auth:\n\n1. **Environment variable**: `FRONTAPP_API_KEY`\n2. **`.env` file**: `FRONTAPP_API_KEY=your-key`\n3. **Direct parameter**: `FrontappClient(api_key=\"...\")`\n4. **`~/.netrc`**: `machine api2.frontapp.com` + `password your-key`\n\n```bash\n# .env\nFRONTAPP_API_KEY=your-api-key-here\nFRONTAPP_BASE_URL=https://api2.frontapp.com  # optional override\n```\n\n## API Coverage\n\nThe generated clients cover Front's full Core API — **139 paths, 233 operations**\nspanning conversations, messages, contacts, teammates, accounts, tags, inboxes,\nchannels, rules, custom fields, drafts, message templates, analytics, and more. Browse\n`frontapp_public_api_client/api/` (Python) or\n`packages/frontapp-client/src/generated/sdk.gen.ts` (TS) for the full surface.\n\nHand-written ergonomic helpers (Python `client.\u003cresource\u003e.…`) and MCP tools wrap the\nhighest-value subset. Current status:\n\n| Resource                    | Python helper (`client.X.…`) | MCP tools                                                                                                                                                                                        |\n| --------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| Conversations               | ✅ `.conversations`          | list / get / search / list_messages / list_comments / update / add_comment                                                                                                                       |\n| Drafts                      | ✅ `.drafts`                 | list_conversation_drafts / create_draft_on_channel / create_draft_reply / edit_draft / delete_draft                                                                                              |\n| Contacts                    | ✅ `.contacts`               | list / get / lookup_by_email / list_team / list_teammate / list_conversations / list_notes / create (+ team/teammate variants) / update / merge / delete / add_note / add_handle / delete_handle |\n| Contact Lists               | ✅ `.contact_lists`          | list (+ team/teammate scopes) / list_members / create (+ team/teammate variants) / delete / add_contacts / remove_contacts                                                                       |\n| Contact Groups (deprecated) | ✅ `.contact_groups`         | Same shape as contact_lists; Front has deprecated this surface — prefer contact_lists for new code                                                                                               |\n| Messages                    | ✅ `.messages`               | get / seen_status / mark_seen                                                                                                                                                                    |\n| Tags                        | ✅ `.tags`                   | list (+ company/team/teammate scopes) / get / list_children / list_tagged_conversations / add_tag_to_conversation / remove_tag_from_conversation / create / create_child / update / delete       |\n| Inboxes                     | ✅ `.inboxes`                | list (+ team/teammate scopes) / get / list_conversations / list_channels / list_access / create (+ team) / grant_access / revoke_access                                                          |\n| Teammates                   | ✅ `.teammates`              | list / get / list_inboxes / list_assigned_conversations / update                                                                                                                                 |\n| Attachments                 | ✅ `.attachments`            | download_attachment + `attachment_paths` parameter on every draft / reply / comment tool                                                                                                         |\n| Analytics                   | ⏳ planned                   | ⏳ planned (create→poll recipe)                                                                                                                                                                  |\n\nSee the [issue tracker](https://github.com/dougborg/frontapp-openapi-client/issues) for\nthe roadmap. The full generated surface is usable today via direct imports from\n`frontapp_public_api_client.api.\u003ctag\u003e` — helpers and MCP tools just add ergonomic polish\non top.\n\n### Front Search Syntax\n\nConversation list/search endpoints accept Front's `q=` search syntax:\n\n| Query               | Description                 |\n| ------------------- | --------------------------- |\n| `status:open`       | Open conversations          |\n| `status:archived`   | Archived                    |\n| `tag:urgent`        | Tagged urgent               |\n| `assignee:me`       | Assigned to the token owner |\n| `is:unassigned`     | Unassigned                  |\n| `inbox:support`     | In a named inbox            |\n| `after:2024-01-01`  | Updated after a date        |\n| `before:2024-12-31` | Updated before a date       |\n\nCombine with `AND` / `OR`: `status:open AND tag:urgent`.\n\n## MCP Tools\n\nMutations use a two-step confirm pattern — call with `confirm=false` for a preview, then\n`confirm=true` to apply (which also elicits explicit user approval via `ctx.elicit`).\nCustomer-facing replies always go through the drafts vertical: agents draft, humans\nsend.\n\n### Conversations\n\n| Tool                         | Mutation? | Description                                              |\n| ---------------------------- | --------- | -------------------------------------------------------- |\n| `list_conversations`         | no        | Filter + cursor-paginate, reverse chronological          |\n| `get_conversation`           | no        | Full detail for one conversation                         |\n| `search_conversations`       | no        | Full Front search syntax as the primary filter           |\n| `list_conversation_messages` | no        | Messages inside a conversation (most recent first)       |\n| `list_conversation_comments` | no        | Internal teammate comments on a conversation             |\n| `update_conversation`        | yes       | Archive/reopen, reassign, retag, move inbox              |\n| `add_conversation_comment`   | yes       | Add a teammate-only comment (never reaches the customer) |\n\n### Drafts (drafts-first outbound)\n\n| Tool                       | Mutation? | Description                                        |\n| -------------------------- | --------- | -------------------------------------------------- |\n| `list_conversation_drafts` | no        | Existing drafts on a conversation                  |\n| `create_draft_on_channel`  | yes       | Brand-new outbound draft on a channel              |\n| `create_draft_reply`       | yes       | Draft a reply on an existing conversation          |\n| `edit_draft`               | yes       | Full-replacement edit (body + channel_id required) |\n| `delete_draft`             | yes       | Discard a draft                                    |\n\nFront exposes no programmatic `send_draft` — drafts are reviewed and sent by a human in\nFront's UI. There is intentionally no `reply_to_conversation` tool.\n\nReads are cached for 30s via `ResponseCachingMiddleware`.\n\n## Resilience (Python client)\n\nEvery endpoint inherits these transport-layer behaviors automatically — no decorators or\nwrappers needed:\n\n- **Retries**: `httpx-retries` retries idempotent methods on 502/503/504 and any method\n  on 429 (safe because 429 means \"not processed\"). Configurable via `max_retries`.\n- **Rate-limit awareness**: `Retry-After` headers are honored when present; otherwise\n  exponential backoff.\n- **Sensitive-data redaction**: `Authorization` headers and common secret field names\n  (`api_key`, `password`, `token`, etc.) are scrubbed from log output.\n\n**Auto-pagination** for Front's cursor-token paging — every paginated list method has an\n`iter_*` async-iterator counterpart:\n\n| Helper                 | `iter_all`                | Variant iterators                                                          |\n| ---------------------- | ------------------------- | -------------------------------------------------------------------------- |\n| `client.conversations` | yes                       | `iter_search`, `iter_messages`                                             |\n| `client.contacts`      | yes                       | `iter_for_team`, `iter_for_teammate`, `iter_conversations`                 |\n| `client.tags`          | yes                       | `iter_company`, `iter_for_team`, `iter_for_teammate`, `iter_conversations` |\n| `client.inboxes`       | (no top-level pagination) | `iter_conversations`                                                       |\n\n```python\nasync for conv in client.conversations.iter_all(q=\"status:open\", max_items=500):\n    print(conv.id, conv.subject)\n```\n\nThe iterator walks `_pagination.next` until exhausted or a safety limit (`max_items`,\n`max_pages`) trips. Pass `page_token` manually to the underlying `list()` if you need\ncursor control instead.\n\n## Project Structure\n\n```text\nfrontapp-openapi-client/               # Monorepo root\n├── pyproject.toml                      # uv workspace configuration\n├── pnpm-workspace.yaml                 # pnpm TS workspace\n├── scripts/vendor_spec.py              # download + sanitize Front's OpenAPI spec\n├── docs/\n│   ├── frontapp-openapi.yaml           # OpenAPI 3.0.0 spec (vendored + sanitized)\n│   ├── FRONTAPP_API_ENDPOINTS.md       # Prioritization reference\n│   └── *.md                            # Shared documentation\n├── frontapp_public_api_client/         # Python client\n│   ├── frontapp_client.py              # Resilient client + transport layer\n│   ├── domain/                         # Pydantic domain models (Conversation, …)\n│   ├── helpers/                        # Ergonomic facades (client.conversations)\n│   ├── utils.py                        # unwrap/is_success + error types\n│   ├── api/, models/                   # Generated from the OpenAPI spec\n│   └── docs/                           # Package documentation\n├── frontapp_mcp_server/                # MCP server (FastMCP)\n│   └── src/frontapp_mcp/\n│       ├── server.py                   # Lifespan, auth, caching middleware\n│       ├── tools/                      # MCP tool modules (conversations, …)\n│       └── resources/                  # help + workspace-orientation resources\n└── packages/\n    └── frontapp-client/                # TypeScript client (hey-api)\n        ├── src/\n        │   ├── client.ts               # createClient + transport stack\n        │   ├── transport/              # resilient.ts, pagination.ts\n        │   └── generated/              # Generated from the same spec\n        └── openapi-ts.config.ts\n```\n\n## Development\n\n### Prerequisites\n\n- **Python 3.12+** for Python packages\n- **Node.js 18+** for the TypeScript package\n- **uv** ([install](https://docs.astral.sh/uv/getting-started/installation/))\n- **pnpm** ([install](https://pnpm.io/installation))\n\n### Setup\n\n```bash\ngit clone https://github.com/dougborg/frontapp-openapi-client.git\ncd frontapp-openapi-client\n\nuv sync --extra dev          # install Python deps including dev tools\nuv run pre-commit install    # install git hooks\npnpm install                 # install TS deps\ncp .env.example .env         # add FRONTAPP_API_KEY\n```\n\n### Common Commands\n\n```bash\nuv run python scripts/vendor_spec.py      # refresh docs/frontapp-openapi.yaml from upstream\nuv run poe regenerate-client              # regenerate the Python client from the spec\npnpm --filter frontapp-client generate    # regenerate the TypeScript client\nuv run poe test                           # pytest -n 4\nuv run poe quick-check                    # format + lint\nuv run poe check                          # format + lint + typecheck + test\n```\n\n### Commit Standards\n\nConventional commits drive per-package semantic-release versioning:\n\n```bash\ngit commit -m \"feat(client): add contacts helper\"\ngit commit -m \"fix(client): handle empty paginated response\"\ngit commit -m \"feat(mcp): add tools for tag management\"\ngit commit -m \"feat(ts): export retry middleware\"\ngit commit -m \"docs: update quick-start\"\n```\n\nUse `!` for breaking changes: `feat(client)!: drop Python 3.11 support`.\n\nSee [MONOREPO_SEMANTIC_RELEASE.md](docs/MONOREPO_SEMANTIC_RELEASE.md) for details.\n\n## Acknowledgements\n\n- Scaffolding pattern lifted from\n  [dougborg/statuspro-openapi-client](https://github.com/dougborg/statuspro-openapi-client)\n  and\n  [dougborg/katana-openapi-client](https://github.com/dougborg/katana-openapi-client),\n  which established the shape of this ecosystem (Python + TS client + FastMCP server,\n  transport-layer resilience, two-step confirm mutations, etc.).\n- OpenAPI spec from\n  [frontapp/front-api-specs](https://github.com/frontapp/front-api-specs).\n\n## License\n\nMIT License — see [LICENSE](LICENSE).\n\n## Contributing\n\nContributions welcome. See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdougborg%2Ffrontapp-openapi-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdougborg%2Ffrontapp-openapi-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdougborg%2Ffrontapp-openapi-client/lists"}