Skip to main content

Intent API

One endpoint. Typed intents. Zero boilerplate.

Intent API is a constraint-driven API framework for Python. Instead of writing dozens of REST endpoints, you declare intents — structured requests that describe what the caller wants to do. The framework dispatches them to the right handler automatically.

POST /api/intent
{
  "model": "Todo",
  "action": "create",
  "payload": { "title": "Ship Intent API", "done": false },
  "context": { "type": "user", "team_id": "abc-123" }
}

Install

pip install intent-api

Quickstart

from fastapi import FastAPI
from intent_api import IntentRouter, IntentService, MutationResponse

app = FastAPI()

# 1. Define a service
class TodoService(IntentService):
    async def create(self, *, db, user, context, payload):
        # Your create logic here
        return MutationResponse(success=True, id="1", message="Todo created")

    async def list(self, *, db, user, context, skip, limit):
        return {"items": [], "total": 0}

# 2. Create router and register services
router = IntentRouter()
router.register("Todo", TodoService())

# 3. Build and include the FastAPI router
app.include_router(router.build(
    get_user=my_auth_dependency,  # Your auth function
    get_db=my_db_dependency,      # Your DB session function
))

That's it. One endpoint handles all CRUD + custom commands for every model.

Core Concepts

IntentRequest

Every API call is an IntentRequest:

Field Type Description
model str Target resource (e.g., "Todo", "User")
action str "create", "read", "update", "delete", "list", "custom"
id any? Resource ID for read/update/delete
payload dict? Data for create/update/custom
command str? Named command when action is "custom"
context IntentContext? Caller context (role, team, org)
skip int? Pagination offset (default: 0)
limit int? Pagination limit (default: 10)

IntentContext

Context tells the backend who is calling and what scope they're in:

{
    "type": "member",          # Role/surface type
    "team_id": "uuid-123",     # Team scope
    "organization_id": null,   # Org scope (optional)
}

IntentService

Subclass IntentService for each model. Override the methods you need:

class UserService(IntentService):
    async def create(self, *, db, user, context, payload):
        ...

    async def read(self, *, db, user, id, context):
        ...

    async def update(self, *, db, user, id, context, payload):
        ...

    async def delete(self, *, db, user, id, context):
        ...

    async def list(self, *, db, user, context, skip, limit):
        ...

    async def custom_action(self, *, db, user, context, command, id, payload):
        if command == "archive":
            return await self._archive(db=db, id=id)
        raise ValueError(f"Unknown command: {command}")

Custom Commands

Custom commands let you go beyond CRUD:

{
    "model": "Report",
    "action": "custom",
    "command": "export_csv",
    "payload": { "date_from": "2024-01-01", "date_to": "2024-12-31" }
}

Multiple Surfaces

Intent API supports multiple access levels from the same registry:

router = IntentRouter()
router.register("Todo", TodoService())
router.register("User", UserService())

# Standard: authenticated users
app.include_router(router.build(
    get_user=my_auth_dependency,
    get_db=get_db,
))

# Admin: requires additional authorization
app.include_router(router.build_admin(
    get_user=my_auth_dependency,
    get_db=get_db,
    authorize=lambda user, ctx: user.email.endswith("@mycompany.com"),
))

# Guest: unauthenticated, restricted actions
app.include_router(router.build_guest(
    get_db=get_db,
))

Guest Access Control

Mark services as guest-accessible:

class PublicFeedService(IntentService):
    is_guest_allowed = True
    allowed_guest_actions = ["list", "read"]

    async def list(self, *, db, user, context, skip, limit):
        # user will be None for guest requests
        return {"items": [...], "total": 10}

Auth Integration

Intent API is auth-agnostic. Provide your own get_user dependency:

# Example with Clerk
async def get_user(credentials, context, db):
    clerk_user_id = verify_clerk_token(credentials.credentials)
    return db.query(User).filter(User.clerk_id == clerk_user_id).first()

# Example with Auth0
async def get_user(credentials, context, db):
    payload = decode_auth0_token(credentials.credentials)
    return db.query(User).filter(User.auth0_id == payload["sub"]).first()

# Wire it up
app.include_router(router.build(get_user=get_user, get_db=get_db))

Why Intent API?

Traditional REST Intent API
GET /users, POST /users, GET /users/:id, PUT /users/:id, DELETE /users/:id, POST /users/:id/archive, GET /reports/export ... POST /api/intent
40+ endpoints to maintain 1 endpoint, N services
Auth middleware on every route Auth once at the intent surface
No standard request format Every request is an IntentRequest
Hard to audit ("which endpoints access sensitive data?") One place to log all access

License

Copyright 2026 Chris Bora. All rights reserved.

Free for personal and evaluation use. Commercial use requires a license. See intentapi.dev/pricing for details.

Metadata

Release files for intent-api 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for intent-api 0.1.0
File Size Uploaded
intent_api-0.1.0.tar.gz 13.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for intent-api 0.1.0
File Interpreter ABI Platform
intent_api-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.5 kB

Release files / intent_api-0.1.0.tar.gz

Download URL intent_api-0.1.0.tar.gz
Size 13.8 kB
Tags Source
SHA-256 checksum
How to use checksums
79ae0457b9a81c65b9e0a2b89779de58292051c7ca14eb937211a025605c46f8
BLAKE2b-256 checksum
How to use checksums
c4aec06623f43bf0aa77fc961320d7f6a8afdd9beb3c919bf33c1d69358b24d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release files / intent_api-0.1.0-py3-none-any.whl

Download URL intent_api-0.1.0-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9f190301c31c7affa936632a696d54334fcc58cd50b60dd4ce17e218bdf0aa4a
BLAKE2b-256 checksum
How to use checksums
9bf4729202b789f0c6dda2adf53d814629c825ac239e756947c4f550b6855a3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release history Release notifications | RSS feed

0.5.1

1 release file

0.5.0

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page