Official Python SDK for the Zoho Payments API (IN, IN Sandbox, US editions)
Project description
Zoho Payments Python SDK
Official Python SDK for the Zoho Payments API — supports IN, IN Sandbox, and US editions.
API reference:
- India: https://www.zoho.com/in/payments/api/v1/introduction/
- United States: https://www.zoho.com/us/payments/api/v1/introduction/
Requirements
- Python 3.11+
- requests 2.32+
Installation
pip install zoho-payments
Quick Start
from zohopayments import ZohoPayments, Edition
from zohopayments.params import PaymentLinkCreateParams
# 1. Build the client
client = (
ZohoPayments.builder()
.account_id("23137556")
.edition(Edition.IN)
.oauth_token("1000.xxxx.yyyy")
.build()
)
# 2. Use a service
link = client.payment_links().create(
PaymentLinkCreateParams(
amount=500.00,
currency="INR",
description="Order #1234",
email="customer@example.com",
)
)
print("Created:", link.payment_link_id)
# 3. Close when done (or use as a context manager)
client.close()
Or using the client as a context manager:
with ZohoPayments.builder() \
.account_id("23137556") \
.edition(Edition.IN) \
.oauth_token("1000.xxxx.yyyy") \
.build() as client:
link = client.payment_links().get("pl_abc")
Editions
| Edition | Payments API Base URL | OAuth Accounts URL |
|---|---|---|
Edition.IN |
https://payments.zoho.in/api/v1 |
https://accounts.zoho.in |
Edition.IN_SANDBOX |
https://paymentssandbox.zoho.in/api/v1 |
https://accounts.zoho.in |
Edition.US |
https://payments.zoho.com/api/v1 |
https://accounts.zoho.com |
Helper methods: edition.is_in() returns True for both IN and IN_SANDBOX; edition.is_us() returns True for US.
Authentication
Access token only
client = (
ZohoPayments.builder()
.account_id("23137556")
.edition(Edition.IN)
.oauth_token("1000.access_token_here")
.build()
)
Token refresh
The SDK does not auto-refresh tokens. Use ZohoPayments.generate_access_token() when the access token expires, then push the new token into the client:
fresh = ZohoPayments.generate_access_token(
refresh_token="...",
client_id="...",
client_secret="...",
redirect_uri="...",
edition=Edition.IN,
)
# Persist the new token in your storage layer
my_store.save(fresh.access_token, fresh.expires_in)
# Update the running client (thread-safe, no rebuild needed)
client.update_token(fresh.access_token)
You can also pass an OAuthToken directly to the builder:
token = ZohoPayments.generate_access_token(...)
client = (
ZohoPayments.builder()
.account_id("23137556")
.edition(Edition.IN)
.oauth_token(token)
.build()
)
OAuthToken exposes access_token and expires_in (token lifetime in seconds, as returned by IAM).
Client configuration
client = (
ZohoPayments.builder()
.account_id("23137556") # Required
.edition(Edition.IN) # Required
.oauth_token("1000.xxxx.yyyy") # Required
.connect_timeout(15.0) # Default: 30 seconds
.request_timeout(45.0) # Default: 60 seconds
.add_default_header("X-Custom-Header", "value")
.build()
)
Reserved headers (Authorization, User-Agent, Accept, Content-Type, Content-Length, Host) are managed by the SDK and cannot be overridden via add_default_header.
Services
| Accessor | Description | Editions |
|---|---|---|
client.payment_links() |
Payment link CRUD | All |
client.payment_sessions() |
Payment sessions | All |
client.customers() |
Customers | All (list/delete: US only) |
client.payments() |
Payments | All (create: US only) |
client.refunds() |
Refunds | All |
client.payment_methods() |
Saved payment methods | US only |
client.payment_method_sessions() |
Payment-method collection sessions | US only |
client.mandates() |
Recurring mandates | IN only |
client.collect() |
Virtual accounts (Collect) | IN only |
Examples
Payment link
from zohopayments.params import PaymentLinkCreateParams, NotifyCustomerParams
link = client.payment_links().create(
PaymentLinkCreateParams(
amount=500.00,
currency="INR",
description="Order #1234",
email="customer@example.com",
notify_customer=NotifyCustomerParams(email=True, sms=False),
)
)
# Retrieve
fetched = client.payment_links().get(link.payment_link_id)
# Cancel
cancelled = client.payment_links().cancel(link.payment_link_id)
Customer (US)
from zohopayments.params import CustomerCreateParams, CustomerListParams, MetaDataParams
customer = client.customers().create(
CustomerCreateParams(
name="Jane Doe",
email="jane@example.com",
meta_data=[MetaDataParams("source", "web")],
)
)
page = client.customers().list(CustomerListParams(per_page=25, page=1))
for c in page.data:
print(c.customer_id, c.customer_name)
print("total:", page.page_context.total)
Refund
from zohopayments.params import RefundCreateParams
refund = client.refunds().create(
payment_id="pay_abc",
params=RefundCreateParams(
amount=100.00,
reason="requested_by_customer",
type="full",
),
)
Mandate (IN)
from zohopayments.params import (
MandateDetailsParams,
MandateEnrollmentSessionCreateParams,
)
enrollment = client.mandates().create_enrollment_session(
MandateEnrollmentSessionCreateParams(
amount=0.00,
currency="INR",
customer_id="cust_abc",
description="SIP enrollment",
mandate_details=MandateDetailsParams(
payment_method_type="upi",
frequency="monthly",
description="Monthly SIP",
amount_rule="variable",
max_amount=5000.00,
),
)
)
Error handling
All API errors raise a subclass of ZohoPaymentsException.
| Exception | HTTP |
|---|---|
AuthenticationException |
401 |
PermissionException |
403 |
ResourceNotFoundException |
404 |
InvalidRequestException |
400, 422 |
RateLimitException |
429 |
ZohoPaymentsAPIException |
Any other non-2xx |
ConnectionException |
Network / IO failure |
from zohopayments import (
AuthenticationException,
InvalidRequestException,
ZohoPaymentsAPIException,
)
try:
client.payments().get("pay_missing")
except AuthenticationException:
# refresh the token and retry
...
except InvalidRequestException as exc:
print(exc.code_string, exc.api_error_message)
except ZohoPaymentsAPIException as exc:
print("other API error:", exc.http_status_code)
Custom HTTP transport
DefaultHttpClient wraps a requests.Session. To plug in your own retries, proxy, instrumentation, etc., implement HttpClientInterface:
from zohopayments.net.http_client_interface import HttpClientInterface
from zohopayments.net.response import ZohoResponse
class MyTransport(HttpClientInterface):
def execute(self, request):
# ... send request.method / request.url / request.headers / request.body
return ZohoResponse(status_code=200, headers={}, body='{...}')
def close(self):
pass
client = (
ZohoPayments.builder()
.account_id("...")
.edition(Edition.IN)
.oauth_token("...")
.http_client(MyTransport())
.build()
)
When you inject a custom transport you cannot also set connect_timeout — the transport manages its own connection lifecycle.
Thread safety
ZohoPaymentsClientis safe to share across threads.client.update_token()is atomic; in-flight requests on other threads see either the old or the new token.- Services are eagerly constructed and stateless beyond the shared HTTP client.
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zoho_payments-1.0.1-py3-none-any.whl.
File metadata
- Download URL: zoho_payments-1.0.1-py3-none-any.whl
- Upload date:
- Size: 49.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
718669a8f0a85e51e8b17765b0567795005cc44d1a8dff046086ceb467e8809d
|
|
| MD5 |
4ffc8dea556556e2915b8cfdf0e76bfd
|
|
| BLAKE2b-256 |
aedd94dd1dda66979b11162200d27198629a311a7e190203da2592f704d34fb6
|