Python SDK for Plane API
Project description
Plane Python SDK
A comprehensive, type-annotated Python SDK for interacting with the Plane API. This SDK provides a clean, modern interface for all Plane API operations, following Python best practices with full type safety and Pydantic v2 integration.
Features
- ๐ Type-Safe: Full type annotations with Pydantic v2 models
- ๐ง Modern Python: Built for Python 3.10+ with modern typing idioms
- ๐ก๏ธ Error Handling: Comprehensive error types and exception handling
- ๐ Retry Logic: Built-in retry mechanism with configurable backoff
- ๐ฆ Resource-Based: Clean resource-based API organization
- ๐ฏ Comprehensive: Support for all major Plane API endpoints
- โก Synchronous: Uses
requestswith connection pooling
Breaking Changes (v0.2.0 vs v0.1.x)
This SDK (v0.2.0) replaces the v0.1.x OpenAPI-generated client and introduces intentional breaking changes for a cleaner, type-safe developer experience.
-
Authentication and client
- New
PlaneClient(base_url, api_key | access_token)replaces OpenAPIConfiguration/ApiClientusage - Exactly one of
api_keyoraccess_tokenis required; providing both raises aConfigurationError base_urlshould NOT include/api/v1; the SDK appends/api/v1automatically
- New
-
HTTP headers
- API key header standardized to
X-Api-Key; access tokens useAuthorization: Bearer <token>
- API key header standardized to
-
Resource paths and naming
- All paths use
work-itemsinstead of v0.1.xissues - Sub-resources are grouped under
client.work_items.<subresource>
- All paths use
-
Method names
- Methods are standardized across resources:
list,create,retrieve,update,delete - Replaces verbose, OpenAPI-generated method names
- Methods are standardized across resources:
-
Models and DTOs
- Uses Pydantic v2 with: response models
extra="allow"; Create*/Update* DTOsextra="ignore" - Separate DTOs for create/update:
Create*andUpdate* - Field naming is normalized
- Uses Pydantic v2 with: response models
-
Pagination shape
- Paginated responses now expose:
results,total_count,next_page_number,prev_page_number - This replaces v0.1.x shapes that included different field names
- Paginated responses now expose:
-
Query parameters
- Typed query params via models like
WorkItemQueryParamsandRetrieveQueryParams - Common fields include
per_page,page,order_by,expand
- Typed query params via models like
-
Errors
- Raises
HttpError(message, status_code, response)on non-2xx responses - Configuration validation errors raise
ConfigurationError
- Raises
-
Imports and organization
- Import models from
plane.models.<resource> - No OpenAPI
*Apiclasses; use resource objects fromPlaneClient
- Import models from
-
Trailing slashes
- All endpoints include trailing
/by design; the SDK enforces this consistently
- All endpoints include trailing
Migration example (v0.1.x โ v0.2.0):
# v0.1.x (OpenAPI-generated)
from plane import Configuration, ApiClient
from plane.apis import WorkItemsApi
cfg = Configuration(host="https://api.plane.so")
cfg.api_key['X-API-Key'] = "<api-key>"
api = WorkItemsApi(ApiClient(cfg))
api.list_work_items(slug, project_id=project_id)
# v0.2.0 (this SDK)
from plane.client import PlaneClient
from plane.models.query_params import WorkItemQueryParams
client = PlaneClient(base_url="https://api.plane.so", api_key="<api-key>")
client.work_items.list(
workspace_slug=slug,
project_id=project_id,
params=WorkItemQueryParams(per_page=20, order_by="-created_at")
)
Installation
pip install plane-sdk
Quick Start
Authentication
โ ๏ธ Required: You must provide exactly one of api_key or access_token for authentication.
import os
from plane.client import PlaneClient
from plane.errors import ConfigurationError
# Using API key
client = PlaneClient(
base_url="https://api.plane.so",
api_key=os.environ["PLANE_API_KEY"]
)
# OR using access token (not both)
client = PlaneClient(
base_url="https://api.plane.so",
access_token=os.environ["PLANE_ACCESS_TOKEN"]
)
# Raises ConfigurationError if neither or both are provided
OAuth Authentication
The SDK also supports OAuth 2.0 authentication for more advanced use cases:
from plane import OAuthClient
# Initialize OAuth client
oauth_client = OAuthClient(
base_url="https://api.plane.so",
client_id="your_client_id",
client_secret="your_client_secret"
)
# Authorization Code Flow (for web applications)
# Step 1: Get authorization URL
auth_url = oauth_client.get_authorization_url(
redirect_uri="https://your-app.com/callback",
scope="read write",
state="random_state_string"
)
# Step 2: Exchange authorization code for token
token = oauth_client.exchange_code(
code="authorization_code_from_callback",
redirect_uri="https://your-app.com/callback"
)
# Step 3: Use the access token
client = PlaneClient(
base_url="https://api.plane.so",
access_token=token.access_token
)
# Client Credentials Flow (for server-to-server)
token = oauth_client.get_client_credentials_token(
scope="read write",
app_installation_id="optional_workspace_app_installation_id"
)
# Refresh expired tokens
new_token = oauth_client.refresh_token(token.refresh_token)
# Revoke tokens
oauth_client.revoke_token(token.access_token)
For detailed OAuth examples, see examples/oauth_example.py.
Basic Usage
# List projects in a workspace
projects = client.projects.list("my-workspace")
# Create a work item
from plane.models.work_items import CreateWorkItem
work_item = client.work_items.create(
workspace_slug="my-workspace",
project_id="project-id",
data=CreateWorkItem(name="New task", state_id="state-id")
)
# Retrieve a work item with parameters
from plane.models.query_params import RetrieveQueryParams
work_item = client.work_items.retrieve(
workspace_slug="my-workspace",
project_id="project-id",
work_item_id="work-item-id",
params=RetrieveQueryParams(expand="assignees,labels,state")
)
# List work items with pagination and filtering
from plane.models.query_params import WorkItemQueryParams
work_items = client.work_items.list(
workspace_slug="my-workspace",
project_id="project-id",
params=WorkItemQueryParams(per_page=50, order_by="-created_at")
)
Architecture
Client Structure
The SDK is organized around a central PlaneClient that provides access to various resource classes:
from plane.client import PlaneClient
client = PlaneClient(
base_url="https://api.plane.so",
api_key="your-api-key"
)
# Access different resources
client.users # User management
client.workspaces # Workspace operations
client.projects # Project management
client.work_items # Work item operations
client.cycles # Cycle management
client.modules # Module management
client.labels # Label management
client.states # State/workflow management
client.work_item_types # Work item type management
client.work_item_properties # Custom properties
client.epics # Epic management
client.intake # Intake management
client.pages # Page management
client.customers # Customer management
client.teamspaces # Teamspace management
client.stickies # Sticky management
client.initiatives # Initiative management
Resource Organization
All API resources extend a shared BaseResource class that handles:
- HTTP request/response logic
- Authentication headers
- Error handling and retry logic
- URL building with proper path formatting
Type Safety
The SDK uses Pydantic v2 models for all data structures:
- Request models
- Response models
- Query parameter models
Note: Response models are configured with extra="allow" to be forward-compatible with new fields. Create*/Update* DTOs and query parameter models use extra="ignore".
Available Resources
Core Resources
Users
# Get current user
me = client.users.get_me()
# Retrieve a specific user
user = client.users.retrieve(user_id)
# List all users
users = client.users.list()
Workspaces
# Get workspace members
members = client.workspaces.get_members(workspace_slug)
Project Management
Projects
# Create a project
from plane.models.projects import CreateProject
project = client.projects.create(
workspace_slug="my-workspace",
data=CreateProject(
name="My Project",
identifier="MP",
description="Project description"
)
)
# List projects
projects = client.projects.list(workspace_slug="my-workspace")
# Retrieve a project
project = client.projects.retrieve(workspace_slug, project_id)
# Update a project
from plane.models.projects import UpdateProject
project = client.projects.update(
workspace_slug, project_id,
data=UpdateProject(name="Updated Name")
)
# Delete a project
client.projects.delete(workspace_slug, project_id)
# Get worklog summary
worklog_summary = client.projects.get_worklog_summary(workspace_slug, project_id)
# Get project members
members = client.projects.get_members(workspace_slug, project_id)
Work Items
# Create a work item
from plane.models.work_items import CreateWorkItem
work_item = client.work_items.create(
workspace_slug="my-workspace",
project_id="project-id",
data=CreateWorkItem(
name="Fix login bug",
description_html="<p>Fix the login issue</p>",
state_id="state-id",
priority="high"
)
)
# Retrieve a work item
from plane.models.query_params import RetrieveQueryParams
work_item = client.work_items.retrieve(
workspace_slug, project_id, work_item_id,
params=RetrieveQueryParams(expand="assignees,labels,state")
)
# List work items
from plane.models.query_params import WorkItemQueryParams
work_items = client.work_items.list(
workspace_slug, project_id,
params=WorkItemQueryParams(per_page=50, order_by="-created_at")
)
# Update a work item
from plane.models.work_items import UpdateWorkItem
work_item = client.work_items.update(
workspace_slug, project_id, work_item_id,
data=UpdateWorkItem(priority="low", state_id="new-state-id")
)
# Delete a work item
client.work_items.delete(workspace_slug, project_id, work_item_id)
# Search work items
results = client.work_items.search(
workspace_slug, project_id,
query="bug fix"
)
Work Item Sub-Resources
# Comments
comments = client.work_items.comments.list(workspace_slug, project_id, work_item_id)
comment = client.work_items.comments.create(workspace_slug, project_id, work_item_id, data)
comment = client.work_items.comments.retrieve(workspace_slug, project_id, work_item_id, comment_id)
comment = client.work_items.comments.update(workspace_slug, project_id, work_item_id, comment_id, data)
client.work_items.comments.delete(workspace_slug, project_id, work_item_id, comment_id)
# Attachments
attachments = client.work_items.attachments.list(workspace_slug, project_id, work_item_id)
attachment = client.work_items.attachments.create(workspace_slug, project_id, work_item_id, data)
attachment = client.work_items.attachments.retrieve(workspace_slug, project_id, work_item_id, attachment_id)
client.work_items.attachments.delete(workspace_slug, project_id, work_item_id, attachment_id)
# Links
links = client.work_items.links.list(workspace_slug, project_id, work_item_id)
link = client.work_items.links.create(workspace_slug, project_id, work_item_id, data)
link = client.work_items.links.retrieve(workspace_slug, project_id, work_item_id, link_id)
link = client.work_items.links.update(workspace_slug, project_id, work_item_id, link_id, data)
client.work_items.links.delete(workspace_slug, project_id, work_item_id, link_id)
# Relations
relations = client.work_items.relations.list(workspace_slug, project_id, work_item_id)
relation = client.work_items.relations.create(workspace_slug, project_id, work_item_id, data)
# Activities
activities = client.work_items.activities.list(workspace_slug, project_id, work_item_id)
# Work Logs
work_logs = client.work_items.work_logs.list(workspace_slug, project_id, work_item_id)
work_log = client.work_items.work_logs.create(workspace_slug, project_id, work_item_id, data)
work_log = client.work_items.work_logs.retrieve(workspace_slug, project_id, work_item_id, work_log_id)
work_log = client.work_items.work_logs.update(workspace_slug, project_id, work_item_id, work_log_id, data)
client.work_items.work_logs.delete(workspace_slug, project_id, work_item_id, work_log_id)
Cycles
# Create a cycle
from plane.models.cycles import CreateCycle
cycle = client.cycles.create(
workspace_slug, project_id,
data=CreateCycle(
name="Sprint 1",
start_date="2024-01-01",
end_date="2024-01-15",
owned_by="user-id"
)
)
# List cycles
cycles = client.cycles.list(workspace_slug, project_id)
# Retrieve a cycle
cycle = client.cycles.retrieve(workspace_slug, project_id, cycle_id)
# Update a cycle
from plane.models.cycles import UpdateCycle
cycle = client.cycles.update(
workspace_slug, project_id, cycle_id,
data=UpdateCycle(name="Updated Sprint")
)
# Delete a cycle
client.cycles.delete(workspace_slug, project_id, cycle_id)
# List archived cycles
archived = client.cycles.list_archived(workspace_slug, project_id)
# Add work items to cycle
from plane.models.cycles import AddWorkItemsToCycleRequest
client.cycles.add_work_items(
workspace_slug, project_id, cycle_id,
data=AddWorkItemsToCycleRequest(issues=[work_item_id])
)
# Remove work item from cycle
client.cycles.remove_work_item(workspace_slug, project_id, cycle_id, work_item_id)
# List work items in cycle
cycle_items = client.cycles.list_work_items(workspace_slug, project_id, cycle_id)
# Transfer work items between cycles
from plane.models.cycles import TransferCycleWorkItemsRequest
client.cycles.transfer_work_items(
workspace_slug, project_id, cycle_id,
data=TransferCycleWorkItemsRequest(new_cycle_id="other-cycle-id")
)
# Archive/unarchive cycles
client.cycles.archive(workspace_slug, project_id, cycle_id)
client.cycles.unarchive(workspace_slug, project_id, cycle_id)
Modules
# Create a module
from plane.models.modules import CreateModule
module = client.modules.create(
workspace_slug, project_id,
data=CreateModule(name="Auth Module")
)
# List modules
modules = client.modules.list(workspace_slug, project_id)
# Retrieve a module
module = client.modules.retrieve(workspace_slug, project_id, module_id)
# Update a module
from plane.models.modules import UpdateModule
module = client.modules.update(
workspace_slug, project_id, module_id,
data=UpdateModule(name="Updated Module")
)
# Delete a module
client.modules.delete(workspace_slug, project_id, module_id)
# List archived modules
archived = client.modules.list_archived(workspace_slug, project_id)
# Add work items to module
from plane.models.modules import AddWorkItemsToModuleRequest
client.modules.add_work_items(
workspace_slug, project_id, module_id,
data=AddWorkItemsToModuleRequest(issues=[work_item_id])
)
# Remove work item from module
client.modules.remove_work_item(workspace_slug, project_id, module_id, work_item_id)
# List work items in module
module_items = client.modules.list_work_items(workspace_slug, project_id, module_id)
# Archive/unarchive modules
client.modules.archive(workspace_slug, project_id, module_id)
client.modules.unarchive(workspace_slug, project_id, module_id)
States
# Create a state
from plane.models.states import CreateState
state = client.states.create(
workspace_slug, project_id,
data=CreateState(
name="In Progress",
color="#3b82f6",
group="started"
)
)
# List states
states = client.states.list(workspace_slug, project_id)
# Retrieve a state
state = client.states.retrieve(workspace_slug, project_id, state_id)
# Update a state
from plane.models.states import UpdateState
state = client.states.update(
workspace_slug, project_id, state_id,
data=UpdateState(name="Updated Status")
)
# Delete a state
client.states.delete(workspace_slug, project_id, state_id)
Labels
# Create a label
from plane.models.labels import CreateLabel
label = client.labels.create(
workspace_slug, project_id,
data=CreateLabel(name="Bug", color="#ef4444")
)
# List labels
labels = client.labels.list(workspace_slug, project_id)
# Retrieve a label
label = client.labels.retrieve(workspace_slug, project_id, label_id)
# Update a label
from plane.models.labels import UpdateLabel
label = client.labels.update(
workspace_slug, project_id, label_id,
data=UpdateLabel(name="Updated Label")
)
# Delete a label
client.labels.delete(workspace_slug, project_id, label_id)
Work Item Configuration
Work Item Types
# Create a work item type
from plane.models.work_item_types import CreateWorkItemType
wit = client.work_item_types.create(
workspace_slug, project_id,
data=CreateWorkItemType(name="Story")
)
# List work item types
types = client.work_item_types.list(workspace_slug, project_id)
# Retrieve a work item type
wit = client.work_item_types.retrieve(workspace_slug, project_id, type_id)
# Update a work item type
from plane.models.work_item_types import UpdateWorkItemType
wit = client.work_item_types.update(
workspace_slug, project_id, type_id,
data=UpdateWorkItemType(name="Updated Type")
)
# Delete a work item type
client.work_item_types.delete(workspace_slug, project_id, type_id)
Work Item Properties
# Create a property
from plane.models.work_item_properties import CreateWorkItemProperty
prop = client.work_item_properties.create(
workspace_slug, project_id, work_item_type_id,
data=CreateWorkItemProperty(name="Severity")
)
# List properties
properties = client.work_item_properties.list(workspace_slug, project_id, work_item_type_id)
# Retrieve a property
prop = client.work_item_properties.retrieve(workspace_slug, project_id, work_item_type_id, property_id)
# Update a property
from plane.models.work_item_properties import UpdateWorkItemProperty
prop = client.work_item_properties.update(
workspace_slug, project_id, work_item_type_id, property_id,
data=UpdateWorkItemProperty(name="Updated Property")
)
# Delete a property
client.work_item_properties.delete(workspace_slug, project_id, work_item_type_id, property_id)
Additional Resources
Epics
# List epics
epics = client.epics.list(workspace_slug, project_id)
# Retrieve an epic
epic = client.epics.retrieve(workspace_slug, project_id, epic_id)
Intake
# Create intake issue
from plane.models.intake import CreateIntake
intake = client.intake.create(
workspace_slug, project_id,
data=CreateIntake(name="Customer request")
)
# List intake issues
intake_items = client.intake.list(workspace_slug, project_id)
# Retrieve intake issue
intake = client.intake.retrieve(workspace_slug, project_id, intake_id)
# Update intake issue
from plane.models.intake import UpdateIntake
intake = client.intake.update(
workspace_slug, project_id, intake_id,
data=UpdateIntake(status="completed")
)
# Delete intake issue
client.intake.delete(workspace_slug, project_id, intake_id)
Pages
# List workspace pages
pages = client.pages.list_workspace_pages(workspace_slug)
# List project pages
pages = client.pages.list_project_pages(workspace_slug, project_id)
# Retrieve a workspace page
page = client.pages.retrieve_workspace_page(workspace_slug, page_id)
# Retrieve a project page
page = client.pages.retrieve_project_page(workspace_slug, project_id, page_id)
Customers
# List customers
customers = client.customers.list(workspace_slug)
# Create a customer
from plane.models.customers import CreateCustomer
customer = client.customers.create(
workspace_slug,
data=CreateCustomer(name="Acme Inc")
)
# Retrieve a customer
customer = client.customers.retrieve(workspace_slug, customer_id)
# Update a customer
from plane.models.customers import UpdateCustomer
customer = client.customers.update(
workspace_slug, customer_id,
data=UpdateCustomer(name="Updated Name")
)
# Delete a customer
client.customers.delete(workspace_slug, customer_id)
# Customer properties
properties = client.customers.properties.list(workspace_slug, customer_id)
property = client.customers.properties.create(workspace_slug, customer_id, data)
# Customer requests
requests = client.customers.requests.list(workspace_slug, customer_id)
Data Models
The SDK provides comprehensive Pydantic v2 models for all API operations.
Query Parameters
BaseQueryParams- Base query parametersPaginatedQueryParams- Pagination support (per_page, page)WorkItemQueryParams- Work item specific queries (expand, order_by, etc.)RetrieveQueryParams- Retrieve operations (expand, fields, etc.)
Response Models
Paginated responses follow the pattern Paginated<Resource>Response and include:
results- Array of resource objectstotal_count- Total number of resultsnext_page_number- Next page number (if applicable)prev_page_number- Previous page number (if applicable)
Error Handling
The SDK provides comprehensive error handling with specific exception types:
from plane.errors import PlaneError, ConfigurationError, HttpError
# Configuration errors
try:
client = PlaneClient(base_url="https://api.plane.so")
# Missing both api_key and access_token
except ConfigurationError as e:
print(f"Configuration error: {e}")
# HTTP errors
try:
work_item = client.work_items.retrieve("workspace", "project", "invalid-id")
except HttpError as e:
print(f"HTTP error {e.status_code}: {e}")
print(f"Response: {e.response}")
Error Types
PlaneError- Base exception class with optional status_codeConfigurationError- Invalid client configuration (missing credentials or both auth methods provided)HttpError- HTTP request/response errors with status code and response body
Configuration
Basic Configuration
from plane.client import PlaneClient
client = PlaneClient(
base_url="https://api.plane.so",
api_key="your-api-key"
)
Advanced Configuration
from plane.config import Configuration, RetryConfig
from plane.client import PlaneClient
# Custom retry configuration
retry_config = RetryConfig(
total=5, # Number of retries
backoff_factor=0.5, # Backoff multiplier
status_forcelist=(429, 500, 502, 503, 504) # Retry on these status codes
)
# Create client with custom config
client = PlaneClient(
base_url="https://api.plane.so",
api_key="your-api-key",
timeout=60.0, # Request timeout in seconds
retry=retry_config # Optional retry config
)
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
base_url |
str |
Required | API base URL |
api_key |
str |
Optional | API key for authentication |
access_token |
str |
Optional | Access token for authentication |
timeout |
float | tuple[float, float] |
30.0 |
Request timeout in seconds |
retry |
RetryConfig |
None | Retry configuration |
Note: Provide exactly one of api_key or access_token.
Examples
Complete Workflow Example
from plane.client import PlaneClient
from plane.models.projects import CreateProject
from plane.models.work_items import CreateWorkItem
from plane.models.states import CreateState
from plane.models.labels import CreateLabel
from plane.models.query_params import WorkItemQueryParams
client = PlaneClient(
base_url="https://api.plane.so",
api_key="your-api-key"
)
# Create a project
project = client.projects.create(
workspace_slug="my-workspace",
data=CreateProject(
name="My New Project",
identifier="MNP",
description="A project created with the Python SDK"
)
)
# Create a state
state = client.states.create(
workspace_slug="my-workspace",
project_id=project.id,
data=CreateState(
name="In Progress",
color="#3b82f6",
group="started"
)
)
# Create a label
label = client.labels.create(
workspace_slug="my-workspace",
project_id=project.id,
data=CreateLabel(name="Bug", color="#ef4444")
)
# Create a work item
work_item = client.work_items.create(
workspace_slug="my-workspace",
project_id=project.id,
data=CreateWorkItem(
name="Fix authentication bug",
description_html="<p>Fix the authentication issue in the login flow</p>",
priority="high",
state_id=state.id,
labels=[label.id]
)
)
# List work items with filters
work_items = client.work_items.list(
workspace_slug="my-workspace",
project_id=project.id,
params=WorkItemQueryParams(per_page=20, order_by="-created_at")
)
print(f"Created work item: {work_item.name}")
print(f"Total work items: {len(work_items.results)}")
Working with Cycles
from plane.models.cycles import CreateCycle, AddWorkItemsToCycleRequest
# Create a cycle
cycle = client.cycles.create(
workspace_slug="my-workspace",
project_id=project.id,
data=CreateCycle(
name="Sprint 1",
description="First sprint of the project",
start_date="2024-01-01",
end_date="2024-01-15",
owned_by="user-id"
)
)
# Add work items to cycle
client.cycles.add_work_items(
workspace_slug="my-workspace",
project_id=project.id,
cycle_id=cycle.id,
data=AddWorkItemsToCycleRequest(issues=[work_item.id])
)
# List cycle work items
cycle_work_items = client.cycles.list_work_items(
workspace_slug="my-workspace",
project_id=project.id,
cycle_id=cycle.id
)
print(f"Cycle: {cycle.name}")
print(f"Work items in cycle: {len(cycle_work_items.results)}")
Working with Comments and Attachments
from plane.models.work_items import CreateWorkItemComment
# Add a comment
comment = client.work_items.comments.create(
workspace_slug="my-workspace",
project_id=project.id,
work_item_id=work_item.id,
data=CreateWorkItemComment(
comment_html="<p>This is a comment on the work item</p>",
access="INTERNAL"
)
)
# List comments
comments = client.work_items.comments.list(
workspace_slug="my-workspace",
project_id=project.id,
work_item_id=work_item.id
)
print(f"Total comments: {len(comments.results)}")
# Upload an attachment
attachment = client.work_items.attachments.create(
workspace_slug="my-workspace",
project_id=project.id,
work_item_id=work_item.id,
data={
"asset": "file", # URL to file or file path
"attributes": {"name": "screenshot.png"}
}
)
print(f"Attachment ID: {attachment.id}")
Requirements
- Python 3.10+
- requests >= 2.31.0
- pydantic >= 2.4.0
Development
Setup
git clone <repository-url>
cd plane-python-sdk
pip install -e ".[dev]"
Running Tests
# Run all tests
pytest
# Run specific test file
pytest tests/unit/test_work_items.py
# Run with coverage
pytest --cov=plane tests/
Code Quality
The project uses:
- Black for code formatting
- Ruff for linting (rules: E, F, I, UP, B)
- MyPy for type checking
- Pytest for testing
Run pre-commit checks:
pre-commit run --all-files
Project Structure
plane-python-sdk/
โโโ plane/
โ โโโ __init__.py
โ โโโ client.py # Main PlaneClient
โ โโโ config.py # Configuration classes
โ โโโ api/ # API resource classes
โ โ โโโ base_resource.py # Base class for all resources
โ โ โโโ work_items/ # Work item sub-resources
โ โ โโโ work_item_properties/
โ โ โโโ customers/
โ โ โโโ ...
โ โโโ models/ # Pydantic models
โ โ โโโ work_items.py
โ โ โโโ projects.py
โ โ โโโ query_params.py
โ โ โโโ enums.py
โ โ โโโ ...
โ โโโ errors/ # Exception classes
โ โโโ errors.py
โโโ tests/
โ โโโ unit/ # Unit tests
โ โโโ scripts/ # Integration test scripts
โโโ pyproject.toml
โโโ README.md
โโโ requirements.txt
License
MIT License - see LICENSE file for details.
Support
For issues and questions:
- GitHub Issues: [Repository Issues]
- Documentation: Plane Documentation
- Email: dev@plane.so
Note: This SDK is designed to work with Plane's REST API. Make sure you have the appropriate API credentials and permissions for the operations you're trying to perform.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file plane_sdk-0.2.1.tar.gz.
File metadata
- Download URL: plane_sdk-0.2.1.tar.gz
- Upload date:
- Size: 45.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c85ba18aa692a21aa3977f1cc5bffe43263aeafc19740827a9aecfbffb49605
|
|
| MD5 |
f97f69b1515b9b0eef27e4820953054f
|
|
| BLAKE2b-256 |
08d4bd8f49bc6b104fb4ebd2ea262259763d07ccc62068eb52d6ee9c5026c22f
|
File details
Details for the file plane_sdk-0.2.1-py3-none-any.whl.
File metadata
- Download URL: plane_sdk-0.2.1-py3-none-any.whl
- Upload date:
- Size: 65.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98cb39ce568d55ad052836b198a9a044f64b78cac086061ed1da0f46b7202f8a
|
|
| MD5 |
f1e107359ffabcfc1fb139e349b41857
|
|
| BLAKE2b-256 |
4eb226318c298a069fc5f4f79415541c1e838b57d3b2de027fadaf329dc7c546
|