Metadata-Version: 2.4
Name: pinelabs-online-p3p-client-sdk
Version: 0.2.2
Summary: Pine Labs Online P3P Client SDK — x402 Pine Labs Online P3P client for AI agents (Python)
Author: Pine Labs Online
License: MIT
Keywords: mpp,p3p,x402,payment,client,upi,sbmd,machine-payments
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"

# Pine Labs Online P3P Client SDK (Python)

Python SDK for Pine Labs Online P3P client integrations. It mirrors
`p3p-client-sdk`, intercepts HTTP 402 Payment Required
responses, creates customer-scoped P3P payment credentials, and retries paid
requests.

## Installation

```bash
pip install pinelabs-online-p3p-client-sdk
```

Import module: `pinelabs_p3p_client`. Requires Python 3.9 or newer.

## Quick Start

```python
from pinelabs_p3p_client import (
    ClientRuntimeContext,
    P3PEnvironment,
    PaymentMethod,
    PineLabsOnlineClient,
    PineLabsOnlineClientConfig,
)

client = PineLabsOnlineClient.create(PineLabsOnlineClientConfig(
    env=P3PEnvironment.SANDBOX,
    selectedPaymentMethod=PaymentMethod.RESERVE_PAY,
    clientId="client-client-id",
    clientSecret="client-client-secret",
))

response = client.get(
    "https://server.example.com/api/premium",
    context=ClientRuntimeContext(
        customerReference="9876543210",
        mobileNumber="9876543210",
    ),
)
print(response.json())
client.close()
```

Customer identity is runtime context, not static SDK config. This lets one
client instance safely serve many customers.

By default, the SDK uses client-credentials customer auth: it exchanges
`clientId` and `clientSecret` through `POST /api/auth/v1/token`, then calls
`POST /mpp/v1/token`.

For customer API-token flows, explicitly set
`customerAuthMode=P3PCustomerAuthMode.CustomerKey` and pass `customerKey` plus
`mobileNumber` in `ClientRuntimeContext`.

Keep the client SDK instance long-lived in production. Auth tokens are cached
per SDK instance.

## 402 Flow

1. Your code calls `client.get(url, context=...)`.
2. The server returns `HTTP 402` with `WWW-Authenticate: Payment <challenge>`.
3. The SDK decodes the challenge and validates amount, expiry, and accepted payment methods.
4. The SDK creates a token:
   - default mode: `POST /mpp/v1/token` with `Authorization: Bearer <token>`
   - customer-key mode: `POST /api/v1/customer/mpp/token` with `Authorization: Bearer <token>` and `X-Customer-Key`
   - `customer.merchant_customer_reference` and/or `customer.mobile_number`
   - `challenge_id`
   - `payment_amount.value` in minor units
5. The SDK retries the server with `P3P-Credential: Payment <credential>`.
6. The server captures the payment and may return `Payment-Receipt`.

## Direct Token API

```python
from pinelabs_p3p_client import Amount, CreateTokenOptions, PaymentMethod

token = client.methods.create_token(CreateTokenOptions(
    customerReference="9876543210",
    mobileNumber="9876543210",
    challengeId="ch_...",
    paymentAmount=Amount(value=50000, currency="INR"),
    paymentMethod=PaymentMethod.RESERVE_PAY,
))
```

The client SDK no longer creates mandates. Mandate/pre-authorization creation
is handled by the server SDK.

Customer-key mode remains available:

```python
from pinelabs_p3p_client import P3PCustomerAuthMode

customer_key_client = PineLabsOnlineClient.create(PineLabsOnlineClientConfig(
    env=P3PEnvironment.SANDBOX,
    selectedPaymentMethod=PaymentMethod.RESERVE_PAY,
    customerAuthMode=P3PCustomerAuthMode.CustomerKey,
    clientId="client-client-id",
    clientSecret="client-client-secret",
))
```

Timeout and retry settings (`requestTimeoutMs`, `maxRetries`,
`initialRetryDelayMs`) apply to internal P3P calls only. The protected
resource request itself uses the integrator's own HTTP timeout policy.

Environment defaults:

| Env | URL | Timeout | Retries | Initial retry delay |
|---|---|---:|---:|---:|
| `P3PEnvironment.SANDBOX` | `https://pluraluat.v2.pinepg.in` | 60000 ms | 3 | 500 ms |
| `P3PEnvironment.PRODUCTION` | `https://api.pluralpay.in` | 45000 ms | 3 | 500 ms |

## Supported Methods

- `PaymentMethod.RESERVE_PAY` -> `"RESERVE_PAY"` / UPI ReservePay
- `PaymentMethod.OTM` -> `"OTM"`
- `PaymentMethod.Crypto` -> `"CRYPTO"`

## Error Handling

```python
from pinelabs_p3p_client import P3PChallengeError, P3PError, P3PNetworkError

try:
    response = client.get(url, context=runtime_context)
except P3PChallengeError as err:
    ...
except P3PNetworkError as err:
    ...
except P3PError as err:
    print(err.code, err.http_status, err.details)
```

## License

MIT
