Skip to main content

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:

License

Requirements

  • Python 3.11+
  • requests 2.25+

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

  • ZohoPaymentsClient is 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


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

zoho_payments-1.0.0-py3-none-any.whl (50.3 kB view details)

Uploaded Python 3

File details

Details for the file zoho_payments-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: zoho_payments-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 50.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.2

File hashes

Hashes for zoho_payments-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c4c8c9223c99fb60482ca818626b7c39ad77be9635423de6c8cc16cb896ceb22
MD5 fffbf86d807b398c7071a23bf7326d18
BLAKE2b-256 2dec85d1d6f7e7dc521824b834695d3ee7bae21ad0433ea56761eeb475554fc8

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