FulcrumPro
A lightweight Python SDK for the Fulcrum Pro API, built on httpx.
Installation
pip install fulcrumpro
Or with uv:
uv add fulcrumpro
Requirements
- Python 3.14+
Quick Start
from fulcrumpro import FulcrumPro
client = FulcrumPro(api_token="your-api-token")
job = client.jobs.get("6a0e5cad7c2e97225f8def9c")
print(job["name"])
Use as a context manager to ensure the underlying HTTP connection is closed:
with FulcrumPro(api_token="your-api-token") as client:
job = client.jobs.get("6a0e5cad7c2e97225f8def9c")
Authentication
All requests are authenticated with a Bearer token. Pass your API token when constructing the client:
client = FulcrumPro(api_token="your-api-token")
Resources
Jobs
# Get a job by ID
job = client.jobs.get("6a0e5cad7c2e97225f8def9c")
Attachments
Upload a file to a Fulcrum record. Every attachment needs an owner — the record
it hangs off — and file accepts a path, raw bytes, or an open binary file
object, with a path opened and closed for you:
created = client.attachments.upload(
"drawing.pdf",
owner_type="job",
owner_id="6a0e5cad7c2e97225f8def9c",
description="Revision C drawing",
metadata={"source": "sdk"},
)
Download one by ID. Omit dest to get the content back as bytes, or pass a
path to stream it straight to disk without buffering it in memory:
content = client.attachments.download(created["id"])
path = client.attachments.download(created["id"], dest="drawing.pdf")
Find attachments on a record, and download them all as a single ZIP:
owner = {"type": "job", "id": "6a0e5cad7c2e97225f8def9c"}
for attachment in client.attachments.stream(data={"owner": owner}):
print(attachment["name"], attachment["size"])
client.attachments.download_many(data={"owner": owner}, dest="attachments.zip")
Queries must always be narrowed by owner, owners or attachmentIds — the
API will not enumerate every attachment in a tenant, and formats on its own
doesn't count. An unfiltered call raises ValueError rather than making a
request. To sweep broadly, iterate the owning records:
for job in client.jobs.stream():
owner = {"type": "job", "id": job["id"]}
for attachment in client.attachments.stream(data={"owner": owner}):
...
owners takes up to 500 at a time, so batching is usually faster than one
request per record.
Known gap: attachments on a job operation
Files attached to a job operation — including note attachments added through the
Fulcrum UI — are stored with an owner type (Job_ItemToMake_Operation) that the
public API's owner enum doesn't include. It can't be sent as a filter (list
returns 400) and can't be read back (get returns 500). The failure happens
while serializing the record, so any query that would return one fails — these
attachments can't be discovered through the public API at all.
Downloads are unaffected, because they return bytes and never build an owner object. If you obtain an ID another way, the file itself is retrievable:
client.attachments.download("6aa82ae1f826405557c34006", dest="photo.png")
Certification attachments and remotely hosted files have their own methods:
client.attachments.upload_certification(
"cert.pdf", owner_type="item", owner_id="...", lot_id="..."
)
client.attachments.create_remote(
owner, file_name="spec.pdf", access_url="https://example.com/spec.pdf"
)
client.attachments.delete(created["id"])
Error Handling
All non-2xx responses raise a FulcrumProError:
from fulcrumpro import FulcrumPro, FulcrumProError
client = FulcrumPro(api_token="your-api-token")
try:
job = client.jobs.get("nonexistent-id")
except FulcrumProError as e:
print(e.status_code) # e.g. 404
print(str(e)) # "FulcrumPro API error 404: not found"
Version History
See CHANGELOG.md.
Docs
Full API documentation can be found on GitHub Pages
Metadata
Release files for fulcrumpro 0.22.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fulcrumpro-0.22.0.tar.gz | 17.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fulcrumpro-0.22.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.9 kB
Release files / fulcrumpro-0.22.0.tar.gz
| Download URL | fulcrumpro-0.22.0.tar.gz |
|---|---|
| Size | 17.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
14025e02063e3753aac9468e85fa6f75f3a04a12327157af7ea1c6a50983c2b0
|
|
BLAKE2b-256 checksum How to use checksums |
33d9926fabfcc886f4af5a41f2a7756469914e4824669c8fbac278dc5cd31eb3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / fulcrumpro-0.22.0-py3-none-any.whl
| Download URL | fulcrumpro-0.22.0-py3-none-any.whl |
|---|---|
| Size | 24.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6754ebd5e0df882ddcf378cfac3b92a5ee26e255359e165a00fcfe37a22a86fd
|
|
BLAKE2b-256 checksum How to use checksums |
e3558e970415e1675536c88d57f210e6544e3287bc6e8e6623d1356a083803f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for fulcrumpro 0.22.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.