Skip to content

dougborg/frontapp-openapi-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Frontapp — API Client Ecosystem

Multi-language client ecosystem for the Front customer-communication platform. Front is a shared-inbox product that unifies email, SMS, chat, and social channels into one place for support and sales teams. Their Core API exposes conversations, messages, contacts, teammates, tags, inboxes, and more.

This monorepo ships:

  • A production-grade Python client with transport-layer retries, rate-limit awareness, and pagination handling for Front's cursor-token paging.
  • A TypeScript client generated from the same OpenAPI spec via hey-api.
  • An MCP server exposing Frontapp operations as tools to AI assistants like Claude Desktop and Cursor.

Python 3.12+ TypeScript OpenAPI 3.0.0

The OpenAPI spec is vendored from frontapp/front-api-specs and sanitized by scripts/vendor_spec.py (strips binary attachment-download paths and normalizes a few upstream quirks that trip the generators).

Packages

Package Language Version Description
frontapp-openapi-client Python 0.1.0 API client with transport-layer resilience + domain helpers
frontapp-mcp-server Python 0.1.0 Model Context Protocol server for AI assistants
frontapp-client TypeScript 0.1.0 Generated TypeScript/JavaScript client

Features

Feature Python TypeScript MCP Server
Automatic retries (network + 5xx) Yes Yes Yes (via Python client)
Rate-limit retry with exponential backoff Yes Yes Yes
Cursor-token pagination helpers Yes Yes Yes
Two-step confirm on mutations (ctx.elicit) Yes
Full type safety (attrs + Pydantic / TS types) Yes Yes Yes
AI tool surface Claude Desktop, Cursor

Quick Start

Python Client

pip install frontapp-openapi-client
import asyncio
from frontapp_public_api_client import FrontappClient

async def main():
    async with FrontappClient() as client:
        # List recent open conversations tagged "urgent"
        conversations = await client.conversations.list(
            q="status:open tag:urgent", limit=25
        )
        for conv in conversations:
            assignee = conv.assignee.username if conv.assignee else "unassigned"
            print(f"{conv.id}: {conv.subject!r}{conv.status} ({assignee})")

asyncio.run(main())

TypeScript Client

npm install frontapp-client
import { FrontappClient } from "frontapp-client";

const client = await FrontappClient.create();
const { data } = await client.listConversations({ query: { q: "status:open" } });
console.log(`${data._results.length} open conversations`);

MCP Server (Claude Desktop)

pip install frontapp-mcp-server

Add to Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "frontapp": {
      "command": "uvx",
      "args": ["frontapp-mcp-server"],
      "env": {
        "FRONTAPP_API_KEY": "your-api-key-here"
      }
    }
  }
}

Get an API key at Front → Settings → Developers → API tokens.

Configuration

All packages authenticate with a Front API token via bearer auth:

  1. Environment variable: FRONTAPP_API_KEY
  2. .env file: FRONTAPP_API_KEY=your-key
  3. Direct parameter: FrontappClient(api_key="...")
  4. ~/.netrc: machine api2.frontapp.com + password your-key
# .env
FRONTAPP_API_KEY=your-api-key-here
FRONTAPP_BASE_URL=https://api2.frontapp.com  # optional override

API Coverage

The generated clients cover Front's full Core API — 139 paths, 233 operations spanning conversations, messages, contacts, teammates, accounts, tags, inboxes, channels, rules, custom fields, drafts, message templates, analytics, and more. Browse frontapp_public_api_client/api/ (Python) or packages/frontapp-client/src/generated/sdk.gen.ts (TS) for the full surface.

Hand-written ergonomic helpers (Python client.<resource>.…) and MCP tools wrap the highest-value subset. Current status:

Resource Python helper (client.X.…) MCP tools
Conversations .conversations list / get / search / list_messages / list_comments / update / add_comment
Drafts .drafts list_conversation_drafts / create_draft_on_channel / create_draft_reply / edit_draft / delete_draft
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
Contact Lists .contact_lists list (+ team/teammate scopes) / list_members / create (+ team/teammate variants) / delete / add_contacts / remove_contacts
Contact Groups (deprecated) .contact_groups Same shape as contact_lists; Front has deprecated this surface — prefer contact_lists for new code
Messages .messages get / seen_status / mark_seen
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
Inboxes .inboxes list (+ team/teammate scopes) / get / list_conversations / list_channels / list_access / create (+ team) / grant_access / revoke_access
Teammates .teammates list / get / list_inboxes / list_assigned_conversations / update
Attachments .attachments download_attachment + attachment_paths parameter on every draft / reply / comment tool
Analytics ⏳ planned ⏳ planned (create→poll recipe)

See the issue tracker for the roadmap. The full generated surface is usable today via direct imports from frontapp_public_api_client.api.<tag> — helpers and MCP tools just add ergonomic polish on top.

Front Search Syntax

Conversation list/search endpoints accept Front's q= search syntax:

Query Description
status:open Open conversations
status:archived Archived
tag:urgent Tagged urgent
assignee:me Assigned to the token owner
is:unassigned Unassigned
inbox:support In a named inbox
after:2024-01-01 Updated after a date
before:2024-12-31 Updated before a date

Combine with AND / OR: status:open AND tag:urgent.

MCP Tools

Mutations use a two-step confirm pattern — call with confirm=false for a preview, then confirm=true to apply (which also elicits explicit user approval via ctx.elicit). Customer-facing replies always go through the drafts vertical: agents draft, humans send.

Conversations

Tool Mutation? Description
list_conversations no Filter + cursor-paginate, reverse chronological
get_conversation no Full detail for one conversation
search_conversations no Full Front search syntax as the primary filter
list_conversation_messages no Messages inside a conversation (most recent first)
list_conversation_comments no Internal teammate comments on a conversation
update_conversation yes Archive/reopen, reassign, retag, move inbox
add_conversation_comment yes Add a teammate-only comment (never reaches the customer)

Drafts (drafts-first outbound)

Tool Mutation? Description
list_conversation_drafts no Existing drafts on a conversation
create_draft_on_channel yes Brand-new outbound draft on a channel
create_draft_reply yes Draft a reply on an existing conversation
edit_draft yes Full-replacement edit (body + channel_id required)
delete_draft yes Discard a draft

Front exposes no programmatic send_draft — drafts are reviewed and sent by a human in Front's UI. There is intentionally no reply_to_conversation tool.

Reads are cached for 30s via ResponseCachingMiddleware.

Resilience (Python client)

Every endpoint inherits these transport-layer behaviors automatically — no decorators or wrappers needed:

  • Retries: httpx-retries retries idempotent methods on 502/503/504 and any method on 429 (safe because 429 means "not processed"). Configurable via max_retries.
  • Rate-limit awareness: Retry-After headers are honored when present; otherwise exponential backoff.
  • Sensitive-data redaction: Authorization headers and common secret field names (api_key, password, token, etc.) are scrubbed from log output.

Auto-pagination for Front's cursor-token paging — every paginated list method has an iter_* async-iterator counterpart:

Helper iter_all Variant iterators
client.conversations yes iter_search, iter_messages
client.contacts yes iter_for_team, iter_for_teammate, iter_conversations
client.tags yes iter_company, iter_for_team, iter_for_teammate, iter_conversations
client.inboxes (no top-level pagination) iter_conversations
async for conv in client.conversations.iter_all(q="status:open", max_items=500):
    print(conv.id, conv.subject)

The iterator walks _pagination.next until exhausted or a safety limit (max_items, max_pages) trips. Pass page_token manually to the underlying list() if you need cursor control instead.

Project Structure

frontapp-openapi-client/               # Monorepo root
├── pyproject.toml                      # uv workspace configuration
├── pnpm-workspace.yaml                 # pnpm TS workspace
├── scripts/vendor_spec.py              # download + sanitize Front's OpenAPI spec
├── docs/
│   ├── frontapp-openapi.yaml           # OpenAPI 3.0.0 spec (vendored + sanitized)
│   ├── FRONTAPP_API_ENDPOINTS.md       # Prioritization reference
│   └── *.md                            # Shared documentation
├── frontapp_public_api_client/         # Python client
│   ├── frontapp_client.py              # Resilient client + transport layer
│   ├── domain/                         # Pydantic domain models (Conversation, …)
│   ├── helpers/                        # Ergonomic facades (client.conversations)
│   ├── utils.py                        # unwrap/is_success + error types
│   ├── api/, models/                   # Generated from the OpenAPI spec
│   └── docs/                           # Package documentation
├── frontapp_mcp_server/                # MCP server (FastMCP)
│   └── src/frontapp_mcp/
│       ├── server.py                   # Lifespan, auth, caching middleware
│       ├── tools/                      # MCP tool modules (conversations, …)
│       └── resources/                  # help + workspace-orientation resources
└── packages/
    └── frontapp-client/                # TypeScript client (hey-api)
        ├── src/
        │   ├── client.ts               # createClient + transport stack
        │   ├── transport/              # resilient.ts, pagination.ts
        │   └── generated/              # Generated from the same spec
        └── openapi-ts.config.ts

Development

Prerequisites

  • Python 3.12+ for Python packages
  • Node.js 18+ for the TypeScript package
  • uv (install)
  • pnpm (install)

Setup

git clone https://github.com/dougborg/frontapp-openapi-client.git
cd frontapp-openapi-client

uv sync --extra dev          # install Python deps including dev tools
uv run pre-commit install    # install git hooks
pnpm install                 # install TS deps
cp .env.example .env         # add FRONTAPP_API_KEY

Common Commands

uv run python scripts/vendor_spec.py      # refresh docs/frontapp-openapi.yaml from upstream
uv run poe regenerate-client              # regenerate the Python client from the spec
pnpm --filter frontapp-client generate    # regenerate the TypeScript client
uv run poe test                           # pytest -n 4
uv run poe quick-check                    # format + lint
uv run poe check                          # format + lint + typecheck + test

Commit Standards

Conventional commits drive per-package semantic-release versioning:

git commit -m "feat(client): add contacts helper"
git commit -m "fix(client): handle empty paginated response"
git commit -m "feat(mcp): add tools for tag management"
git commit -m "feat(ts): export retry middleware"
git commit -m "docs: update quick-start"

Use ! for breaking changes: feat(client)!: drop Python 3.11 support.

See MONOREPO_SEMANTIC_RELEASE.md for details.

Acknowledgements

License

MIT License — see LICENSE.

Contributing

Contributions welcome. See CONTRIBUTING.md for guidelines.

About

Pythonic Frontapp API client ecosystem with transport-layer retries, rate-limit awareness, and auto-pagination. Python + TypeScript clients + MCP server.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors