jobcelis
Official Python SDK for the Jobcelis Event Infrastructure Platform.
All API calls go to https://jobcelis.com by default — you only need your API key to get started.
Installation
pip install jobcelis
Quick Start
from jobcelis import JobcelisClient
# Only your API key is required — connects to https://jobcelis.com automatically
client = JobcelisClient(api_key="your_api_key")
Custom URL: If you're self-hosting Jobcelis, you can override the base URL:
client = JobcelisClient(api_key="your_api_key", base_url="https://your-instance.example.com")
Authentication
The auth methods do not require an API key. Use them to register, log in, and manage JWT tokens.
from jobcelis import JobcelisClient
client = JobcelisClient(api_key="")
# Register a new account
user = client.register("alice@example.com", "SecurePass123!", name="Alice")
# Log in — returns JWT access token and refresh token
session = client.login("alice@example.com", "SecurePass123!")
access_token = session["token"]
refresh_token = session["refresh_token"]
# Set the JWT for subsequent authenticated calls
client.set_auth_token(access_token)
# Refresh an expired token
new_session = client.refresh_token(refresh_token)
client.set_auth_token(new_session["token"])
# Verify MFA (requires Bearer token already set)
result = client.verify_mfa(token=access_token, code="123456")
Events
# Send a single event
event = client.send_event("order.created", {"order_id": "123", "amount": 99.99})
# Send batch events (up to 1000)
batch = client.send_events([
{"topic": "order.created", "payload": {"order_id": "1"}},
{"topic": "order.created", "payload": {"order_id": "2"}},
])
# List events with pagination
events = client.list_events(limit=25)
next_page = client.list_events(limit=25, cursor=events["cursor"])
# Get / delete a single event
event = client.get_event("evt_abc123")
client.delete_event("evt_abc123")
Webhooks
# Create a webhook
webhook = client.create_webhook(
url="https://example.com/webhook",
topics=["order.*"],
)
# List, get, update, delete
webhooks = client.list_webhooks()
wh = client.get_webhook("wh_abc123")
client.update_webhook("wh_abc123", url="https://new-url.com/hook")
client.delete_webhook("wh_abc123")
# Health and templates
health = client.webhook_health("wh_abc123")
templates = client.webhook_templates()
Deliveries
deliveries = client.list_deliveries(limit=20, status="failed")
client.retry_delivery("del_abc123")
Dead Letters
dead_letters = client.list_dead_letters()
dl = client.get_dead_letter("dlq_abc123")
client.retry_dead_letter("dlq_abc123")
client.resolve_dead_letter("dlq_abc123")
Replays
replay = client.create_replay(
topic="order.created",
from_date="2026-01-01T00:00:00Z",
to_date="2026-01-31T23:59:59Z",
webhook_id="wh_abc123", # optional
)
replays = client.list_replays()
r = client.get_replay("rpl_abc123")
client.cancel_replay("rpl_abc123")
Scheduled Jobs
# Create a job
job = client.create_job(
name="daily-report",
queue="default",
cron_expression="0 9 * * *",
payload={"type": "daily"},
)
# CRUD
jobs = client.list_jobs(limit=10)
job = client.get_job("job_abc123")
client.update_job("job_abc123", cron_expression="0 10 * * *")
client.delete_job("job_abc123")
# List runs for a job
runs = client.list_job_runs("job_abc123", limit=20)
# Preview cron schedule
preview = client.cron_preview("0 9 * * *", count=10)
Pipelines
pipeline = client.create_pipeline(
name="order-processing",
topics=["order.created"],
steps=[
{"type": "filter", "config": {"field": "amount", "gt": 100}},
{"type": "transform", "config": {"add_field": "priority", "value": "high"}},
],
)
pipelines = client.list_pipelines()
p = client.get_pipeline("pipe_abc123")
client.update_pipeline("pipe_abc123", name="order-processing-v2")
client.delete_pipeline("pipe_abc123")
# Test a pipeline with a sample payload
result = client.test_pipeline("pipe_abc123", {"topic": "order.created", "payload": {"id": "1"}})
Invitations
# List pending invitations
invitations = client.list_pending_invitations()
# Accept or reject
client.accept_invitation("inv_abc123")
client.reject_invitation("inv_def456")
Event Schemas
schema = client.create_event_schema(
topic="order.created",
schema={
"type": "object",
"properties": {
"order_id": {"type": "string"},
"amount": {"type": "number"},
},
"required": ["order_id", "amount"],
},
)
schemas = client.list_event_schemas()
s = client.get_event_schema("sch_abc123")
client.update_event_schema("sch_abc123", schema={"type": "object"})
client.delete_event_schema("sch_abc123")
# Validate a payload against a topic's schema
result = client.validate_payload("order.created", {"order_id": "123", "amount": 50})
Sandbox
# Create a temporary endpoint for testing
endpoint = client.create_sandbox_endpoint(name="my-test")
endpoints = client.list_sandbox_endpoints()
# Inspect received requests
requests = client.list_sandbox_requests("sbx_abc123", limit=20)
client.delete_sandbox_endpoint("sbx_abc123")
Analytics
events_chart = client.events_per_day(days=30)
deliveries_chart = client.deliveries_per_day(days=7)
topics = client.top_topics(limit=5)
stats = client.webhook_stats()
Project and Token Management
# Current project
project = client.get_project()
client.update_project(name="My Project v2")
# Topics
topics = client.list_topics()
# API token
token = client.get_token()
new_token = client.regenerate_token()
# Limit the token to scopes and client IPs (empty allowed_ips = any IP)
client.update_token_restrictions(scopes=["events:read", "events:write"], allowed_ips=["203.0.113.10"])
Multi-Project Management
projects = client.list_projects()
new_project = client.create_project("staging-env")
p = client.get_project_by_id("proj_abc123")
client.update_project_by_id("proj_abc123", name="production-env")
client.set_default_project("proj_abc123")
client.delete_project("proj_abc123")
Team Members
members = client.list_members("proj_abc123")
member = client.add_member("proj_abc123", "alice@example.com", role="admin")
client.update_member("proj_abc123", "mem_abc123", role="viewer")
client.remove_member("proj_abc123", "mem_abc123")
Audit Logs
logs = client.list_audit_logs(limit=100)
next_page = client.list_audit_logs(cursor=logs["cursor"])
Data Export
Export methods return raw bytes (CSV or JSON).
# Export as CSV
csv_data = client.export_events(format="csv")
with open("events.csv", "wb") as f:
f.write(csv_data)
# Export as JSON
json_data = client.export_deliveries(format="json")
# Other exports
client.export_jobs(format="csv")
client.export_audit_log(format="csv")
Simulate
# Dry-run an event to see which webhooks would fire
result = client.simulate_event("order.created", {"order_id": "test"})
GDPR / Privacy
# Consent management
consents = client.get_consents()
client.accept_consent("marketing")
# Data portability
my_data = client.export_my_data()
# Processing restrictions
client.restrict_processing()
client.lift_restriction()
# Right to object
client.object_to_processing()
client.restore_consent()
Health Check
health = client.health()
status = client.status()
Retries
The client retries requests that fail during a brief outage (for example while the platform is being deployed):
- network errors (connection refused or reset, DNS, TLS, timeouts) and HTTP
429,502,503,504 - up to 6 retries with exponential backoff (1 s, 2 s, 4 s, 8 s, 16 s, 30 s, about 60 s in total, with jitter);
a
Retry-Afterheader is honoured (capped at 60 s) POSTrequests are retried on network errors only when they carry an idempotency key, so a retry never creates a resource twice.send_eventsends anX-Idempotency-Keyheader (youridempotency_key, or a generated UUID) andsend_eventsadds anidempotency_keyto every event that has none, so retried events are never duplicated.
Other errors (400, 401, 404, 500, ...) are raised at once; after the last retry the error is the same
one you would get without retries.
# Change the number of retries
client = JobcelisClient(api_key="your_api_key", max_retries=3)
# Disable retries
client = JobcelisClient(api_key="your_api_key", max_retries=0)
Error Handling
from jobcelis import JobcelisClient, JobcelisError
client = JobcelisClient(api_key="your_api_key")
try:
event = client.get_event("nonexistent")
except JobcelisError as e:
print(f"Status: {e.status}") # 404
print(f"Detail: {e.detail}") # {"message": "Not found"}
Webhook Signature Verification
from jobcelis import verify_webhook_signature
# Flask example
@app.route('/webhook', methods=['POST'])
def handle_webhook():
is_valid = verify_webhook_signature(
secret='your_webhook_secret',
body=request.get_data(as_text=True),
signature=request.headers.get('X-Signature', '')
)
if not is_valid:
return 'Invalid signature', 401
event = request.get_json()
print(f"Received: {event['topic']}")
return 'OK', 200
License
BSL-1.1 (Business Source License)
Metadata
Release files for jobcelis 1.7.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 | Actions |
|---|---|---|---|---|
| jobcelis-1.7.0.tar.gz | 15.9 kB | Without provenance | Details for jobcelis-1.7.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| jobcelis-1.7.0-py3-none-any.whl | Python 3 | none | any | Details for jobcelis-1.7.0-py3-none-any.whl |
Total release size: 27.4 kB
Release files / jobcelis-1.7.0.tar.gz
| Download URL | jobcelis-1.7.0.tar.gz |
|---|---|
| Size | 15.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f83b37e49829e6ab907d28633d061ea476d866bd85a60f9b81211982c97c4ca6
|
|
BLAKE2b-256 checksum How to use checksums |
38b5b0c9348d8be717c395f286e44aa42406fac871de2180b83a3777621f421c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.16
|
Release files / jobcelis-1.7.0-py3-none-any.whl
| Download URL | jobcelis-1.7.0-py3-none-any.whl |
|---|---|
| Size | 11.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
55430028d4f3192eeecf9063a71f86565c2f6d18c98554f51b8db5cfb5a2e8d2
|
|
BLAKE2b-256 checksum How to use checksums |
b11aef5bf7cfa185a7c48ddc7f98cd40dd99adfa6d57582543cfe63a5c9b8183
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.16
|
Security for jobcelis 1.7.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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.