Skip to main content

hashry-pay

The official Hashry Pay server SDK for Python. Use it on your server to create payments, read their status and verify webhooks.

Full docs: https://docs.hashrytech.com/pay

This is an early release (0.0.1). The API can change before 1.0.

Install

pip install hashry-pay

Python 3.11 or newer. The only dependency is httpx.

Quick start

1. Create the client

Get the client ID and secret from your channel's API access page in the Hashry admin. Keep them in environment variables on your server.

import os
from hashry_pay import Hashry

hashry = Hashry(
    client_id=os.environ["HASHRY_CLIENT_ID"],
    client_secret=os.environ["HASHRY_CLIENT_SECRET"],
    environment="sandbox",  # "live" with a live key
)

A test key (hsk_test_) works only with environment="sandbox", and a live key (hsk_live_) only with "live". The client refuses the wrong pair. Keys made before the prefixes still work, with a one-time warning.

2. Create a payment on your server

intent = hashry.payment_intents.create(
    amount="2500.00",  # a string or Decimal, never a float
    currency="JMD",
    description=f"Order #{order.number}",
    external_reference=str(order.id),
    payer={"email": order.email},  # an email or a phone is required
    return_url="https://shop.example.com/pay/done",
    cancel_url="https://shop.example.com/cart",
    presentation="embedded",
    embed_origin="https://shop.example.com",
    idempotency_key=f"order-{order.id}-pay-1",
)

You choose the idempotency_key, one per payment. The SDK never makes one up. Sending the same key and details again is safe: you get the same payment back.

A declined card does not end an embedded payment. The SDK always asks for retry after a decline (retry_after_decline=True) on an embedded create. It is not a parameter, so you cannot turn it off. After a declined card the frame shows the card form again and the payment stays redirect_issued. No payment.failed webhook is sent for that card. When the last card the frame allows (3) is declined, the payment becomes requires_payment_method; then start a new attempt with create_attempt. The docs have a complete route that starts, renews and retries a payment: https://docs.hashrytech.com/pay/python. The SDK raises HashryError if the API answers an embedded create without retry_after_decline on.

3. Hand four values to the browser

return {
    "embed_url": intent.embed_url,
    "transaction_uid": intent.transaction_uid,
    "status_url": intent.status_url,
    "status_token": intent.status_token,
}
  • embed_url and transaction_uid load the card form (with @hashrytech/pay-react or @hashrytech/pay-svelte). embed_url is a bearer link: don't log it or store it.
  • status_url and status_token let the page show the status while the shopper waits (pollStatus). The token reads only this payment's status. It can't confirm a payment.

Send nothing else. The client secret never goes to the browser.

4. Confirm on your server

When the card form says it is done, or the shopper lands on your return_url, ask Hashry. refresh checks with the gateway first.

intent = hashry.payment_intents.refresh(intent_uid)
if intent.status == "succeeded":
    mark_order_paid(intent.external_reference, intent.uid)

5. Verify webhooks

from django.db import transaction
from hashry_pay import WebhookError, webhooks


def hashry_webhook(request):  # Django shown; any framework works
    try:
        event = webhooks.verify(
            request.body,  # the raw bytes, not parsed JSON
            path=request.path,
            headers=request.headers,
            secret=os.environ["HASHRY_WEBHOOK_SECRET"],
        )
    except WebhookError:
        return HttpResponse(status=400)
    # Read from Hashry before opening your database transaction.
    intent = hashry.payment_intents.refresh(event.payment_intent_uid) if event.payment_intent_uid else None
    with transaction.atomic():
        if not seen_events.add_if_new(event.id):
            return HttpResponse(status=200)  # already handled
        if intent is not None:
            apply_payment_update(intent)  # your amount, currency, and order checks
    return HttpResponse(status=200)

verify checks the signature in constant time and refuses a timestamp more than 5 minutes old or ahead. During a webhook secret rotation, pass secrets=[new_secret, old_secret]. There is no way to read an event without verifying it.

Other resources

Resource Methods
payment_intents create, retrieve, list, refresh, cancel, create_attempt
payment_links create, retrieve, list, cancel
payment_methods list, delete, forget_customer
subscription_intents create, retrieve, list
subscriptions retrieve, list, charges, cancel, uncancel, update_card_session, retry_now
channel self

AsyncHashry has the same methods. Use await, and async with or aclose().

Results are typed objects. Their raw attribute holds the full response, so new API fields are there before the SDK models them. Money values are strings with 2 decimal places.

Errors and retries

  • Every error is a hashry_pay.HashryError.
  • API refusals raise ApiError with code, status and detail, or a subclass: InvalidRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, IdempotencyError, RateLimitError, ServerError.
  • No answer raises ApiConnectionError (or ApiTimeoutError).
  • error.outcome_unknown is true when Hashry may have acted anyway. Replay with the same idempotency key, or read the payment. Never create a new one.

The SDK retries network errors, 5xx and 429 answers twice (max_retries), with backoff. It retries only reads and calls with an idempotency key. Other 4xx answers are never retried. The access token is cached and renewed before it expires, and once more after a 401.

Security rules

  • Keep the client secret (hsk_live_, hsk_test_) and the webhook secret (hwhsec_) on your server. Use @hashrytech/pay-build-guard to fail a frontend build that bundles one.
  • Give the browser only the intent uid, embed_url, transaction_uid and status_token (hst_).
  • Treat the card form's "completed" message and webhooks as cues. Confirm with refresh or retrieve before you fulfil an order.
  • Store each webhook event ID and apply each event once.
  • The SDK masks secrets, the access token, embed_url and status tokens in repr, logs (logger hashry_pay) and errors.

Supported versions

Python 3.11 or newer. CI tests 3.11, 3.12, 3.13 and 3.14.

Support and security

Questions: support@hashrytech.com. For a security problem, email the same address with "Security" in the subject.

License

Apache License 2.0. See LICENSE and NOTICE.

Webhook deduplication uses the event ID inside the signed body. The verifier rejects a different X-Hashry-Event-Id header. For older deliveries without a signed event ID, it returns a stable hash of the signed body. Treat the returned ID as opaque. Commit the ID and your payment changes in one database transaction. A failed transaction must leave the event available for retry.

Metadata

Release files for hashry-pay 0.1.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 hashry-pay 0.1.0
File Size Uploaded Provenance
hashry_pay-0.1.0.tar.gz 74.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for hashry-pay 0.1.0
File Interpreter ABI Platform
hashry_pay-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 117.5 kB

Release files / hashry_pay-0.1.0.tar.gz

Download URL hashry_pay-0.1.0.tar.gz
Size 74.9 kB
Tags Source
SHA-256 checksum
How to use checksums
7883ed24a795616d317be9293257cd1726150fb9f0ac5ef87677ee2b7b1b6312
BLAKE2b-256 checksum
How to use checksums
3490a8a8fed54fa23cf10511dc00165641b4a6e40278a43e18ec157ef854d885
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 20, 2026.

Transparency log

Release files / hashry_pay-0.1.0-py3-none-any.whl

Download URL hashry_pay-0.1.0-py3-none-any.whl
Size 42.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d032a7d96578c834fca6e5e0e36479b794a6aa693ba917fda1e8e194c42c42e4
BLAKE2b-256 checksum
How to use checksums
0241da049942c9ce94f62d05ed41de2b49a7f971b88137d6d34355ba763a450c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 20, 2026.

Transparency log

Security for hashry-pay 0.1.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 hashry_pay-0.1.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 20, 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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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