Skip to main content

proiectro

Official Python SDK for the Proiect.ro API.

Fully typed with sync and async support via httpx.

Installation

pip install proiectro

Quick Start

from proiectro.client import AuthenticatedClient
from proiectro.api.orgs import tenant_orgs

# Authenticate (base_url defaults to https://proiect.ro)
client = AuthenticatedClient(
    base_url="https://proiect.ro",
    token="your_api_key_here",
)

# List customers
response = tenant_orgs.sync_detailed(
    tenant_path="my-workspace",
    client=client,
)

if response.status_code == 200:
    print(response.parsed)

Authentication

Create an API key in your workspace under Settings > API Keys. The SDK sends it as a Bearer token automatically.

from proiectro.client import AuthenticatedClient

client = AuthenticatedClient(
    base_url="https://proiect.ro",
    token="your_api_key_here",
)

Sync and Async

Every endpoint has four variants:

from proiectro.api.orgs import tenant_orgs

# Sync — returns parsed model or None
data = tenant_orgs.sync(tenant_path="my-workspace", client=client)

# Sync — returns full httpx.Response with .parsed, .status_code, .headers
response = tenant_orgs.sync_detailed(tenant_path="my-workspace", client=client)

# Async
data = await tenant_orgs.asyncio(tenant_path="my-workspace", client=client)

# Async — detailed
response = await tenant_orgs.asyncio_detailed(tenant_path="my-workspace", client=client)

Usage Examples

Customers

from proiectro.api.orgs import tenant_orgs, add_subtenant, edit_subtenant, delete_subtenant
from proiectro.models import AddSubtenant, EditSubtenant

# List all customers
customers = tenant_orgs.sync(tenant_path="my-workspace", client=client)

# Create a customer
add_subtenant.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddSubtenant(
        name="Acme Corp",
        parent_id="org-uuid",
        timezone="Europe/Berlin",
        default_currency="EUR",
        country="DE",
        manager="member-uuid",
    ),
)

# Update a customer
edit_subtenant.sync_detailed(
    tenant_path="my-workspace",
    subtenant_id="customer-uuid",
    client=client,
    body=EditSubtenant(
        name="Acme Corporation",
        timezone="Europe/Berlin",
        default_currency="EUR",
        country="DE",
        manager="member-uuid",
    ),
)

# Delete a customer
delete_subtenant.sync_detailed(
    tenant_path="my-workspace",
    subtenant_id="customer-uuid",
    client=client,
)

Leads

from datetime import datetime, timezone
from proiectro.api.leads import add_lead, tenant_all_leads, update_lead_status, mark_lead_converted
from proiectro.models import AddLead, AddLeadSource, UpdateLeadStatus, UpdateLeadStatusStatus, MarkLeadConverted

# Capture an inbound lead
add_lead.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddLead(
        name="Jane Doe",
        company_name="Acme Corp",
        email="jane@acme.example",
        source=AddLeadSource.WEB_FORM,
    ),
)

# List leads, filtered
leads = tenant_all_leads.sync(tenant_path="my-workspace", client=client, status="new", has_email=True)

# Move a lead through the pipeline. `updated_at` is the value you last read —
# the API rejects the write if someone else changed the lead in between.
update_lead_status.sync_detailed(
    tenant_path="my-workspace",
    lead_id="lead-uuid",
    client=client,
    body=UpdateLeadStatus(
        status=UpdateLeadStatusStatus.QUALIFIED,
        updated_at=datetime(2026, 3, 15, 10, 0, tzinfo=timezone.utc),
    ),
)

# Convert it into a customer
mark_lead_converted.sync_detailed(
    tenant_path="my-workspace",
    lead_id="lead-uuid",
    client=client,
    body=MarkLeadConverted(
        updated_at=datetime(2026, 3, 15, 10, 5, tzinfo=timezone.utc),
        new_org_name="Acme Corp",
    ),
)

Proposals

from proiectro.api.proposals import add_proposal, org_proposals, change_proposal_stage
from proiectro.models import AddProposal, ChangeProposalStage

# List proposals for a customer
proposals = org_proposals.sync(
    tenant_path="my-workspace",
    org_id="customer-uuid",
    client=client,
)

# Create a proposal
add_proposal.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddProposal(
        name="Q1 Consulting",
        description="Consulting engagement for Q1",
        customer="customer-uuid",
        owner="member-uuid",
        manager="member-uuid",
        sales_stage="stage-uuid",
        proposal_currency="EUR",
        wbsconfiguration="wbs-uuid",
    ),
)

# Move a proposal to the next stage
change_proposal_stage.sync_detailed(
    tenant_path="my-workspace",
    proposal_id="proposal-uuid",
    stage_id="next-stage-uuid",
    client=client,
    body=ChangeProposalStage(),
)

Projects

from proiectro.api.projects import list_projects, project_work_items, add_work_item, update_work_item_status
from proiectro.api.comments import add_work_item_comment
from proiectro.models import AddWorkItem, UpdateWorkItemStatus, AddWorkItemComment

# List all projects
projects = list_projects.sync(tenant_path="my-workspace", client=client)

# Get work items for a project
work_items = project_work_items.sync(
    tenant_path="my-workspace",
    project_id="project-uuid",
    client=client,
)

# Create a work item
add_work_item.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddWorkItem(
        name="Design mockups",
        project_id="project-uuid",
        work_item_type_id="type-uuid",
    ),
)

# Report progress, then finish it
update_work_item_status.sync_detailed(
    tenant_path="my-workspace",
    work_item_id="work-item-uuid",
    client=client,
    body=UpdateWorkItemStatus(percent_complete=60),
)
update_work_item_status.sync_detailed(
    tenant_path="my-workspace",
    work_item_id="work-item-uuid",
    client=client,
    body=UpdateWorkItemStatus(finished_at="2026-03-10T16:00:00Z"),
)

# Comment on it
add_work_item_comment.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddWorkItemComment(work_item_id="work-item-uuid", content="Mockups approved by the customer."),
)

Payments

from proiectro.api.proposals import add_payment, mark_payment_paid
from proiectro.models import AddPayment, MarkPaymentPaid

# Create a payment
add_payment.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddPayment(
        payment_schedule_block_id="block-uuid",
        name="First milestone",
        due_date="2026-03-15",
        amount="5000.00",
    ),
)

# Mark a payment as paid
mark_payment_paid.sync_detailed(
    tenant_path="my-workspace",
    payment_id="payment-uuid",
    client=client,
    body=MarkPaymentPaid(paid_date="2026-03-15"),
)

Documents

from proiectro.api.documents import tenant_document_templates_list, generate_proposal_document, tenant_documents_list
from proiectro.models import GenerateDocument

# Templates available in the workspace
templates = tenant_document_templates_list.sync(tenant_path="my-workspace", client=client)

# Generate a numbered document for a proposal
generate_proposal_document.sync_detailed(
    tenant_path="my-workspace",
    proposal_id="proposal-uuid",
    client=client,
    body=GenerateDocument(template_id="template-uuid"),
)

# Documents, filtered
documents = tenant_documents_list.sync(tenant_path="my-workspace", client=client, org_id="customer-uuid")

Tags

from proiectro.api.tags import tenant_tags, add_tag, tag_org, untag_org
from proiectro.models import AddTag

# List all tags
tags = tenant_tags.sync(tenant_path="my-workspace", client=client)

# Create a tag
add_tag.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddTag(name="VIP", color="#ff0000"),
)

# Tag a customer
tag_org.sync_detailed(
    tenant_path="my-workspace",
    org_id="customer-uuid",
    tag_id="tag-uuid",
    client=client,
)

Team

from proiectro.api.team import tenant_team, invite_to_team
from proiectro.models import InviteMemberToTenant

# List team members
team = tenant_team.sync(tenant_path="my-workspace", client=client)

# Invite someone to the team
invite_to_team.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=InviteMemberToTenant(email="colleague@example.com"),
)

Webhooks

Subscribe to platform events instead of polling:

from proiectro.api.webhooks import add_webhook, tenant_webhooks
from proiectro.models import AddWebhook

add_webhook.sync_detailed(
    tenant_path="my-workspace",
    client=client,
    body=AddWebhook(
        name="CRM sync",
        target_url="https://example.com/hooks/proiectro",
        event_types=["changeProposalStage", "markPaymentPaid"],
        is_active=True,
        is_secure=True,
    ),
)

hooks = tenant_webhooks.sync(tenant_path="my-workspace", client=client)

Namespaces

Operations live under proiectro.api.<namespace>, one module per operation:

Area Namespaces
Sales leads, proposals, orgs, rfp, bridge (partnerships), partnerportal
Delivery projects, work, operations, comments, timers, booking, capacity, resources, holidays, calendar
Money costs, exchange, analytics, kpis
Support & assets support, assets, locations, custom_forms
Documents & files documents, files, cdn
Workspace tenant, team, rbac, tags, labels, notifications, feed, welcome, auth
Automation webhooks, automation, integrations, portal

Error Handling

Use sync_detailed / asyncio_detailed to inspect status codes:

response = tenant_orgs.sync_detailed(
    tenant_path="my-workspace",
    client=client,
)

if response.status_code == 200:
    print("Success:", response.parsed)
else:
    print("Error:", response.status_code, response.content)

Or enable automatic exceptions for unexpected status codes:

client = AuthenticatedClient(
    base_url="https://proiect.ro",
    token="your_api_key_here",
    raise_on_unexpected_status=True,
)

Context Manager

The client can be used as a context manager to ensure connections are properly closed:

with AuthenticatedClient(
    base_url="https://proiect.ro",
    token="your_api_key_here",
) as client:
    data = tenant_orgs.sync(tenant_path="my-workspace", client=client)

Async:

async with AuthenticatedClient(
    base_url="https://proiect.ro",
    token="your_api_key_here",
) as client:
    data = await tenant_orgs.asyncio(tenant_path="my-workspace", client=client)

Requirements

  • Python >= 3.10
  • httpx >= 0.23.0

API Documentation

Full API reference is available at proiect.ro/api/v1/docs.

Changelog

See CHANGELOG.md.

License

MIT

Metadata

Release files for proiectro 0.4.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 proiectro 0.4.0
File Size Uploaded Provenance
proiectro-0.4.0.tar.gz 755.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for proiectro 0.4.0
File Interpreter ABI Platform
proiectro-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 3.3 MB

Release files / proiectro-0.4.0.tar.gz

Download URL proiectro-0.4.0.tar.gz
Size 755.2 kB
Tags Source
SHA-256 checksum
How to use checksums
31e67dc19e82f6bdf0cd40b0f7a7dc78c39abd9b4d73bc487b02ecba441cbc51
BLAKE2b-256 checksum
How to use checksums
da8d1afae252117fe6d34bbb3d510874dee195ec92e134bd6c068919797ce38b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / proiectro-0.4.0-py3-none-any.whl

Download URL proiectro-0.4.0-py3-none-any.whl
Size 2.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
a0931e734ecfde353a3bdb7c5a079f755144f8e5e6602d77f78e1a6e9b874825
BLAKE2b-256 checksum
How to use checksums
b7040cab1ca9f4637858c68d4de9b203838ce3125ffdb84b1ea5637381edf019
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Security for proiectro 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for proiectro-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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