Skip to main content

Python client for Postcept, Proof-of-Completion for AI agents. Verify high-risk agent actions against the system of record and get a signed completion receipt.

Project description

Postcept Python SDK

Submit Proof-of-Completion verifications for your AI agents' high-risk actions.

pip install postcept

Usage

from postcept import Postcept

pc = Postcept(api_key="pcpt_sk_...")  # create a key in the dashboard

# After your agent issues a refund, prove it actually completed:
result = pc.verify_refund(
    operation_id="refund_8F31",        # stable across retries
    agent_id="SupportAgent-04",
    refund_id="re_4md82k",
    amount_cents=12000,
    currency="usd",
    customer="mara.ellis@example.com",
    idempotency_key="refund_8F31",     # safe to retry
)

print(result["result"])                # "verified" | "incomplete" | "duplicated" | "mismatched" | "policy_failed"
print(result["lifecycle"])             # "pending_finality" | "finalized" | "unobserved" | "reversed" | ...
print(result["safe_to_claim_complete"])  # True only when verified and the provider state is terminal
print(result["claim_reason"])          # why it isn't safe, e.g. "pending_finality"
print(result["receipt"]["id"])         # signed completion receipt

Act on safe_to_claim_complete, not on the raw result. When it is False, claim_reason tells you what to say. pending_finality means the provider is still settling, so tell the customer "processing" and re-check later. Anything else means the work is not done, so surface the gap and recover.

Cancellations work the same way:

pc.verify_cancellation(
    operation_id="cancel_2240",
    agent_id="SupportAgent-04",
    subscription_id="sub_9Kd21",
    customer="mara.ellis@example.com",
)

Read your Verified Completion Rate:

pc.verified_completion_rate()  # {"claimed": 1240, "verified": 1167, "verified_completion_rate": 0.9411, ...}

Notes

  • Auth: pass an organization API key (pcpt_sk_...). All data is scoped to that org.
  • Idempotency: pass idempotency_key so retried submissions return the original verification instead of creating a duplicate.
  • Errors: non-2xx responses raise PostceptError (.status_code, .detail).
  • Base URL: defaults to https://api.postcept.com. Override with Postcept(api_key=..., base_url=...) for staging.
  • Use as a context manager (with Postcept(...) as pc:) to close the HTTP client.

Verifying lifecycle webhooks

Postcept can push signed lifecycle events (a verification created, a previously verified refund later reversed) to an endpoint you register in the dashboard or via POST /v1/webhook-endpoints. Verify every delivery against the raw request body before acting on it:

from postcept import verify_webhook_signature

# In your handler, BEFORE parsing the JSON:
ok = verify_webhook_signature(
    payload=raw_body_bytes,
    header=request.headers["Postcept-Signature"],
    secret=os.environ["POSTCEPT_WEBHOOK_SECRET"],
)

Stale timestamps are rejected (replay protection, 5-minute default). Delivery is at-least-once and unordered: de-duplicate by the Postcept-Event-Id header. During a secret rotation the header carries a signature for both the new and the previous secret, so you can switch without dropping deliveries.

Guarded actions

Run your action in your own code, then verify it, and get a customer-safe status:

result = pc.guard_refund(
    lambda: stripe.Refund.create(charge="ch_1P09x", amount=12000),  # YOUR code
    operation_id="refund_8F31", agent_id="SupportAgent-04",
    refund_id="re_4md82k", amount_cents=12000, customer="mara.ellis@example.com",
)

result.action                  # whatever your function returned
result.safe_to_claim_complete  # True only when verified AND final
result.status                  # "completed" | "processing" | "failed" | "unverified" | "unreachable"
result.customer_message        # a non-false sentence for that status

Postcept never runs your action or holds write authority. guard_refund never raises for a non-verified or unreachable outcome (they're in the result). A raise from your own action propagates. A pending refund yields status="processing", never "done".

OpenTelemetry

Export Postcept outcomes to your existing observability tool. Attach the standard postcept.* attributes to your own span (no OTel dependency forced):

from opentelemetry import trace
from postcept import postcept_span_attributes

result = pc.verify_refund(...)
trace.get_current_span().set_attributes(postcept_span_attributes(result))

Works with any OTel-compatible backend (LangSmith, Phoenix, Datadog, Honeycomb, plain OTLP).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

postcept-0.3.0.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

postcept-0.3.0-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file postcept-0.3.0.tar.gz.

File metadata

  • Download URL: postcept-0.3.0.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for postcept-0.3.0.tar.gz
Algorithm Hash digest
SHA256 f3c997636342cf036638335b88feaa392bfebe2f798a225e7b98d7c4abded3dd
MD5 b23a52d51448a467a7291a4d6081df0c
BLAKE2b-256 e81ce6907c7450b59e7b923227d92b8ae03976124ecba8a16b3305afa62596ca

See more details on using hashes here.

File details

Details for the file postcept-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: postcept-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for postcept-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0361199e2a3313a03b1767ab1766df21e9a38693ff7bc8297f4fd38a73aa73df
MD5 2b40cff6c96106f6968cfea6b9378a7f
BLAKE2b-256 5fa27b3cf66271b1a58bfc67017af41e7c54ab6478b331105cb561e27174e3d8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page